@shwfed/config 2.9.7 → 2.9.8
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/mcp.mjs +1054 -855
- package/dist/module.json +1 -1
- package/dist/preview/assets/{FieldGroup.vue_vue_type_script_setup_true_lang-tkU7rYrs.js → FieldGroup.vue_vue_type_script_setup_true_lang-ByKzTJkK.js} +1 -1
- package/dist/preview/assets/{badge-C55P2V8D.js → badge-Dq4c6LC9.js} +1 -1
- package/dist/preview/assets/{config-DqibnZH4.js → config-B8qH4_4x.js} +1 -1
- package/dist/preview/assets/{config-DzKcQKJj.js → config-BBGDw3Em.js} +1 -1
- package/dist/preview/assets/{config-rL7m78ZC.js → config-C32gE_z0.js} +1 -1
- package/dist/preview/assets/{config-j1oKH3Ci.js → config-COfUny1G.js} +1 -1
- package/dist/preview/assets/{config-CnxzerC5.js → config-CVPTjqGi.js} +1 -1
- package/dist/preview/assets/{config-DeaHg7ps.js → config-CgdFXkLJ.js} +1 -1
- package/dist/preview/assets/{config-Bu1S_DR5.js → config-DNr8rSLw.js} +1 -1
- package/dist/preview/assets/{config-Bc2N2jlD.js → config-DVEOLj6d.js} +1 -1
- package/dist/preview/assets/{config-B3-xqMew.js → config-DpRJqJ1d.js} +1 -1
- package/dist/preview/assets/{config-D0j4njOQ.js → config-Dvqs3X3R.js} +1 -1
- package/dist/preview/assets/{config-CH2QpakU.js → config-DyqhZSFe.js} +1 -1
- package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-G748uLwi.js → definition.vue_vue_type_script_setup_true_lang-B0MHEyHj.js} +1 -1
- package/dist/preview/assets/index-Br3FtCu2.js +1 -0
- package/dist/preview/assets/index-C1h9lV52.css +1 -0
- package/dist/preview/assets/index-C1wWjgLL.js +717 -0
- package/dist/preview/assets/{index-dIh1Jn4U.js → index-CWJ_W3Gk.js} +1 -1
- package/dist/preview/assets/{item-BCWcrKaL.js → item-Bp81qizC.js} +1 -1
- package/dist/preview/assets/{runtime-DZiqhnCm.js → runtime-AHwg8SCY.js} +1 -1
- package/dist/preview/assets/{runtime-C-KLJ71q.js → runtime-BHWdj0nM.js} +1 -1
- package/dist/preview/assets/{runtime-CBg0VVCJ.js → runtime-Be6zYys6.js} +1 -1
- package/dist/preview/assets/{runtime-bRCsEM7S.js → runtime-CKj3_07G.js} +1 -1
- package/dist/preview/assets/{runtime-DO8ov3J6.js → runtime-CVIZYrHD.js} +1 -1
- package/dist/preview/assets/{runtime-D3LGPlv3.js → runtime-C_F9tcxh.js} +1 -1
- package/dist/preview/assets/{runtime-BTFesnrJ.js → runtime-DNHuKamx.js} +1 -1
- package/dist/preview/assets/{runtime-zoq6YaMz.js → runtime-DambLtyb.js} +1 -1
- package/dist/preview/assets/{runtime-C5-cN3M1.js → runtime-DqkDOQp2.js} +1 -1
- package/dist/preview/assets/{runtime-BsqCaddm.js → runtime-UVi5ssie.js} +1 -1
- package/dist/preview/index.html +2 -2
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.d.ts +1 -1
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.js +2 -2
- package/dist/runtime/components/actions/buttons/2026-06-08/com.shwfed.actions.button.http.request.json.batch/schema.d.ts +1 -1
- package/dist/runtime/components/actions/buttons/2026-06-08/com.shwfed.actions.button.http.request.json.batch/schema.js +1 -1
- package/dist/runtime/components/block-layout-editor/index.vue +98 -3
- package/dist/runtime/components/config/footer.vue +22 -20
- package/dist/runtime/components/config/use-editor.js +5 -9
- package/dist/runtime/components/config/utils/validation-error.d.ts +1 -0
- package/dist/runtime/components/config/utils/validation-error.js +34 -0
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +4 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +4 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +4 -4
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +4 -4
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.d.vue.ts +155 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue +918 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue.d.ts +155 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.d.vue.ts +8 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue +482 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue.d.ts +8 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.d.ts +126 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.js +178 -0
- package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +2 -2
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +2 -2
- package/dist/runtime/vendor/cel-js/CLAUDE.md +1 -1
- package/dist/runtime/vendor/cel-js/PROMPT.md +2 -2
- package/dist/runtime/vendor/cel-js/lib/http-builder.js +13 -3
- package/package.json +1 -1
- package/dist/preview/assets/index-C16exop7.js +0 -717
- package/dist/preview/assets/index-CSm6dB4o.js +0 -1
- package/dist/preview/assets/index-vPcvbp7e.css +0 -1
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Effect, Schema } from 'effect';
|
|
2
|
+
import type { Environment } from '../../../../../vendor/cel-js/lib/index.js';
|
|
3
|
+
export declare const type: "com.shwfed.form.field.upload";
|
|
4
|
+
export declare const compatibilityDate: "2026-06-09";
|
|
5
|
+
export declare const metadata: {
|
|
6
|
+
readonly name: "文件上传";
|
|
7
|
+
readonly icon: "fluent:cloud-arrow-up-20-regular";
|
|
8
|
+
readonly w: {
|
|
9
|
+
readonly initial: 8;
|
|
10
|
+
readonly min: 8;
|
|
11
|
+
readonly max: number;
|
|
12
|
+
};
|
|
13
|
+
readonly h: {
|
|
14
|
+
readonly initial: 6;
|
|
15
|
+
readonly min: 6;
|
|
16
|
+
readonly max: number;
|
|
17
|
+
readonly grow: true;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export declare const JSON_VAR: {
|
|
21
|
+
readonly type: "dyn";
|
|
22
|
+
readonly label: "HTTP 响应体";
|
|
23
|
+
readonly description: "第一步 `请求` 的响应体(已解析 JSON);用于构造第二步下载请求";
|
|
24
|
+
};
|
|
25
|
+
export declare const FILES_VAR: {
|
|
26
|
+
readonly type: "list<dyn>";
|
|
27
|
+
readonly label: "已选文件";
|
|
28
|
+
readonly description: "本次选择的文件列表(`File` 数组);通常通过 `form({...})` 构造 multipart 请求体";
|
|
29
|
+
};
|
|
30
|
+
export declare const UPLOAD_JSON_VAR: {
|
|
31
|
+
readonly type: "dyn";
|
|
32
|
+
readonly label: "上传响应";
|
|
33
|
+
readonly description: "上传 `请求` 的响应体(已解析 JSON);用于提取已上传文件项";
|
|
34
|
+
};
|
|
35
|
+
export declare const FILE_VAR: {
|
|
36
|
+
readonly type: "dyn";
|
|
37
|
+
readonly label: "文件项";
|
|
38
|
+
readonly description: "表单状态中的单个文件项(服务端回填或上传响应映射所得);返回其展示文件名";
|
|
39
|
+
};
|
|
40
|
+
export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
|
|
41
|
+
label: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
|
|
42
|
+
locale: Schema.Literal<["zh"]>;
|
|
43
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
44
|
+
}>], [Schema.Struct<{
|
|
45
|
+
locale: Schema.Literal<["ja", "en", "ko"]>;
|
|
46
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
47
|
+
}>]>>;
|
|
48
|
+
description: Schema.optional<Schema.refine<readonly [{
|
|
49
|
+
readonly locale: "zh";
|
|
50
|
+
readonly message: string;
|
|
51
|
+
}, ...{
|
|
52
|
+
readonly locale: "en" | "ja" | "ko";
|
|
53
|
+
readonly message: string;
|
|
54
|
+
}[]], Schema.TupleType<readonly [Schema.Struct<{
|
|
55
|
+
locale: Schema.Literal<["zh"]>;
|
|
56
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
57
|
+
}>], [Schema.Struct<{
|
|
58
|
+
locale: Schema.Literal<["ja", "en", "ko"]>;
|
|
59
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
60
|
+
}>]>>>;
|
|
61
|
+
placeholder: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
|
|
62
|
+
locale: Schema.Literal<["zh"]>;
|
|
63
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
64
|
+
}>], [Schema.Struct<{
|
|
65
|
+
locale: Schema.Literal<["ja", "en", "ko"]>;
|
|
66
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
67
|
+
}>]>>;
|
|
68
|
+
tooltip: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
|
|
69
|
+
locale: Schema.Literal<["zh"]>;
|
|
70
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
71
|
+
}>], [Schema.Struct<{
|
|
72
|
+
locale: Schema.Literal<["ja", "en", "ko"]>;
|
|
73
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
74
|
+
}>]>>;
|
|
75
|
+
orientation: Schema.optional<Schema.Literal<["vertical", "floating"]>>;
|
|
76
|
+
binding: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|
|
77
|
+
disabled: Schema.optional<Schema.Schema<string, string, never>>;
|
|
78
|
+
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
79
|
+
multiple: Schema.optional<Schema.SchemaClass<boolean, boolean, never>>;
|
|
80
|
+
accept: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
81
|
+
maxFileSize: Schema.optional<Schema.refine<number, typeof Schema.Number>>;
|
|
82
|
+
maxTotalSize: Schema.optional<Schema.refine<number, typeof Schema.Number>>;
|
|
83
|
+
maxFiles: Schema.optional<Schema.refine<number, Schema.filter<typeof Schema.Number>>>;
|
|
84
|
+
upload: Schema.optional<Schema.Struct<{
|
|
85
|
+
request: Schema.Schema<string, string, never>;
|
|
86
|
+
handle: Schema.Schema<string, string, never>;
|
|
87
|
+
filename: Schema.optional<Schema.Schema<string, string, never>>;
|
|
88
|
+
}>>;
|
|
89
|
+
templates: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
90
|
+
request: Schema.Schema<string, string, never>;
|
|
91
|
+
download: Schema.optional<Schema.Schema<string, string, never>>;
|
|
92
|
+
icon: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|
|
93
|
+
label: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
|
|
94
|
+
locale: Schema.Literal<["zh"]>;
|
|
95
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
96
|
+
}>], [Schema.Struct<{
|
|
97
|
+
locale: Schema.Literal<["ja", "en", "ko"]>;
|
|
98
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
99
|
+
}>]>>;
|
|
100
|
+
}>>>;
|
|
101
|
+
id: Schema.refine<string, typeof Schema.String>;
|
|
102
|
+
displayName: Schema.optional<Schema.SchemaClass<string, string, never>>;
|
|
103
|
+
hidden: Schema.optional<Schema.Schema<string, string, never>>;
|
|
104
|
+
required: Schema.optional<Schema.Schema<string, string, never>>;
|
|
105
|
+
validations: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
106
|
+
when: Schema.Schema<string, string, never>;
|
|
107
|
+
warning: Schema.optional<Schema.SchemaClass<boolean, boolean, never>>;
|
|
108
|
+
message: Schema.refine<readonly [{
|
|
109
|
+
readonly locale: "zh";
|
|
110
|
+
readonly message: string;
|
|
111
|
+
}, ...{
|
|
112
|
+
readonly locale: "en" | "ja" | "ko";
|
|
113
|
+
readonly message: string;
|
|
114
|
+
}[]], Schema.TupleType<readonly [Schema.Struct<{
|
|
115
|
+
locale: Schema.Literal<["zh"]>;
|
|
116
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
117
|
+
}>], [Schema.Struct<{
|
|
118
|
+
locale: Schema.Literal<["ja", "en", "ko"]>;
|
|
119
|
+
message: Schema.SchemaClass<string, string, never>;
|
|
120
|
+
}>]>>;
|
|
121
|
+
}>>>;
|
|
122
|
+
type: Schema.Literal<["com.shwfed.form.field.upload"]>;
|
|
123
|
+
compatibilityDate: Schema.Literal<["2026-06-09"]>;
|
|
124
|
+
}>;
|
|
125
|
+
export type Value = Schema.Schema.Type<ReturnType<typeof schema>>;
|
|
126
|
+
export declare function migrate(prev: unknown): Effect.Effect<unknown, Error>;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
|
|
3
|
+
import { Locale } from "../../../../../share/locale.js";
|
|
4
|
+
import { commonFieldFields, FieldOrientationSchema } from "../../../utils/common.js";
|
|
5
|
+
export const type = "com.shwfed.form.field.upload";
|
|
6
|
+
export const compatibilityDate = "2026-06-09";
|
|
7
|
+
export const metadata = {
|
|
8
|
+
name: "\u6587\u4EF6\u4E0A\u4F20",
|
|
9
|
+
icon: "fluent:cloud-arrow-up-20-regular",
|
|
10
|
+
w: { initial: 8, min: 8, max: Infinity },
|
|
11
|
+
h: { initial: 6, min: 6, max: Infinity, grow: true }
|
|
12
|
+
};
|
|
13
|
+
export const JSON_VAR = {
|
|
14
|
+
type: "dyn",
|
|
15
|
+
label: "HTTP \u54CD\u5E94\u4F53",
|
|
16
|
+
description: "\u7B2C\u4E00\u6B65 `\u8BF7\u6C42` \u7684\u54CD\u5E94\u4F53\uFF08\u5DF2\u89E3\u6790 JSON\uFF09\uFF1B\u7528\u4E8E\u6784\u9020\u7B2C\u4E8C\u6B65\u4E0B\u8F7D\u8BF7\u6C42"
|
|
17
|
+
};
|
|
18
|
+
export const FILES_VAR = {
|
|
19
|
+
type: "list<dyn>",
|
|
20
|
+
label: "\u5DF2\u9009\u6587\u4EF6",
|
|
21
|
+
description: "\u672C\u6B21\u9009\u62E9\u7684\u6587\u4EF6\u5217\u8868\uFF08`File` \u6570\u7EC4\uFF09\uFF1B\u901A\u5E38\u901A\u8FC7 `form({...})` \u6784\u9020 multipart \u8BF7\u6C42\u4F53"
|
|
22
|
+
};
|
|
23
|
+
export const UPLOAD_JSON_VAR = {
|
|
24
|
+
type: "dyn",
|
|
25
|
+
label: "\u4E0A\u4F20\u54CD\u5E94",
|
|
26
|
+
description: "\u4E0A\u4F20 `\u8BF7\u6C42` \u7684\u54CD\u5E94\u4F53\uFF08\u5DF2\u89E3\u6790 JSON\uFF09\uFF1B\u7528\u4E8E\u63D0\u53D6\u5DF2\u4E0A\u4F20\u6587\u4EF6\u9879"
|
|
27
|
+
};
|
|
28
|
+
export const FILE_VAR = {
|
|
29
|
+
type: "dyn",
|
|
30
|
+
label: "\u6587\u4EF6\u9879",
|
|
31
|
+
description: "\u8868\u5355\u72B6\u6001\u4E2D\u7684\u5355\u4E2A\u6587\u4EF6\u9879\uFF08\u670D\u52A1\u7AEF\u56DE\u586B\u6216\u4E0A\u4F20\u54CD\u5E94\u6620\u5C04\u6240\u5F97\uFF09\uFF1B\u8FD4\u56DE\u5176\u5C55\u793A\u6587\u4EF6\u540D"
|
|
32
|
+
};
|
|
33
|
+
function withVar(configure, name, spec) {
|
|
34
|
+
return (env) => {
|
|
35
|
+
configure(env);
|
|
36
|
+
env.registerVariable(name, spec.type, { description: spec.description });
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function schema(configure) {
|
|
40
|
+
const CelBool = Expression({ configure, resultType: "bool" });
|
|
41
|
+
const CelHttpRequest = Expression({ configure, resultType: "HttpRequest" });
|
|
42
|
+
const CelDownloadRequest = Expression({ configure: withVar(configure, "json", JSON_VAR), resultType: "HttpRequest" });
|
|
43
|
+
const CelUploadRequest = Expression({ configure: withVar(configure, "files", FILES_VAR), resultType: "HttpRequest" });
|
|
44
|
+
const CelUploadHandle = Expression({ configure: withVar(configure, "json", UPLOAD_JSON_VAR), resultType: "list" });
|
|
45
|
+
const CelItemName = Expression({ configure: withVar(configure, "file", FILE_VAR), resultType: "string" });
|
|
46
|
+
const LocaleMd = LocaleMarkdown({ configure });
|
|
47
|
+
return Schema.Struct({
|
|
48
|
+
type: Schema.Literal(type),
|
|
49
|
+
compatibilityDate: Schema.Literal(compatibilityDate),
|
|
50
|
+
...commonFieldFields(configure),
|
|
51
|
+
label: Schema.optional(Locale.annotations({
|
|
52
|
+
title: "\u6807\u7B7E",
|
|
53
|
+
description: "\u5B57\u6BB5\u524D\u5C55\u793A\u7684\u6587\u672C\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u6807\u7B7E"
|
|
54
|
+
})),
|
|
55
|
+
description: Schema.optional(LocaleMd.annotations({
|
|
56
|
+
title: "\u8BF4\u660E",
|
|
57
|
+
description: "\u5C55\u793A\u5728\u4E0A\u4F20\u533A\u57DF\u4E0A\u65B9\u7684\u591A\u8BED\u8A00\u8BF4\u660E\uFF0C\u652F\u6301 Markdown \u4E0E `{{ form.foo }}` \u63D2\u503C"
|
|
58
|
+
})),
|
|
59
|
+
placeholder: Schema.optional(Locale.annotations({
|
|
60
|
+
title: "\u5360\u4F4D\u7B26",
|
|
61
|
+
description: "\u4E0A\u4F20\u533A\u57DF\u4E3A\u7A7A\u65F6\u7684\u63D0\u793A\u6587\u672C"
|
|
62
|
+
})),
|
|
63
|
+
tooltip: Schema.optional(Locale.annotations({
|
|
64
|
+
title: "\u63D0\u793A",
|
|
65
|
+
description: "\u9F20\u6807\u60AC\u505C\u5728\u6807\u7B7E\u4E0A\u65F6\u5C55\u793A\u7684\u8BF4\u660E"
|
|
66
|
+
})),
|
|
67
|
+
orientation: Schema.optional(FieldOrientationSchema),
|
|
68
|
+
binding: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
|
|
69
|
+
title: "\u7ED1\u5B9A\u8DEF\u5F84",
|
|
70
|
+
description: "\u5199\u5165\u8868\u5355\u72B6\u6001\u7684 `dot-prop` \u8DEF\u5F84\uFF0C\u4F8B\u5982 `attachments.5du4fbuv`\uFF1B\u7559\u7A7A\u5219\u4E3A\u975E\u53D7\u63A7\u5B57\u6BB5"
|
|
71
|
+
})),
|
|
72
|
+
disabled: Schema.optional(CelBool.annotations({
|
|
73
|
+
title: "\u7981\u7528\u6761\u4EF6",
|
|
74
|
+
description: "\u8FD4\u56DE `true` \u65F6\u4E0A\u4F20\u533A\u57DF\u4ECD\u7136\u6E32\u67D3\u4F46\u4E0D\u53EF\u64CD\u4F5C"
|
|
75
|
+
})),
|
|
76
|
+
readonly: Schema.optional(CelBool.annotations({
|
|
77
|
+
title: "\u53EA\u8BFB\u6761\u4EF6",
|
|
78
|
+
description: "\u8FD4\u56DE `true` \u65F6\u4EC5\u4EE5\u6587\u4EF6\u5217\u8868\u5C55\u793A\u5F53\u524D\u503C\uFF0C\u4E0D\u5141\u8BB8\u589E\u5220"
|
|
79
|
+
})),
|
|
80
|
+
multiple: Schema.optional(Schema.Boolean.annotations({
|
|
81
|
+
title: "\u5141\u8BB8\u591A\u6587\u4EF6",
|
|
82
|
+
description: "\u5F00\u542F\u540E\u53EF\u4E00\u6B21\u9009\u62E9/\u62D6\u5165\u591A\u4E2A\u6587\u4EF6\uFF1B\u5173\u95ED\u65F6\u65B0\u6587\u4EF6\u4F1A\u66FF\u6362\u5DF2\u9009\u6587\u4EF6"
|
|
83
|
+
})),
|
|
84
|
+
accept: Schema.optional(Schema.Array(Schema.String).annotations({
|
|
85
|
+
title: "\u5141\u8BB8\u7684\u6587\u4EF6\u7C7B\u578B",
|
|
86
|
+
description: "\u5141\u8BB8\u4E0A\u4F20\u7684 MIME \u7C7B\u578B\u5217\u8868\uFF1B\u7559\u7A7A\u8868\u793A\u4E0D\u9650\u5236"
|
|
87
|
+
})),
|
|
88
|
+
maxFileSize: Schema.optional(Schema.Number.pipe(Schema.positive()).annotations({
|
|
89
|
+
title: "\u5355\u6587\u4EF6\u5927\u5C0F\u9650\u5236",
|
|
90
|
+
description: "\u5355\u4E2A\u6587\u4EF6\u5141\u8BB8\u7684\u6700\u5927\u5B57\u8282\u6570\uFF1B\u8D85\u8FC7\u6B64\u9650\u5236\u7684\u6587\u4EF6\u4F1A\u88AB\u62D2\u7EDD"
|
|
91
|
+
})),
|
|
92
|
+
maxTotalSize: Schema.optional(Schema.Number.pipe(Schema.positive()).annotations({
|
|
93
|
+
title: "\u603B\u5927\u5C0F\u9650\u5236",
|
|
94
|
+
description: "\u6240\u6709\u5DF2\u9009\u6587\u4EF6\u7D2F\u8BA1\u7684\u6700\u5927\u5B57\u8282\u6570\uFF1B\u65B0\u589E\u5BFC\u81F4\u8D85\u51FA\u65F6\u4F1A\u88AB\u62D2\u7EDD"
|
|
95
|
+
})),
|
|
96
|
+
maxFiles: Schema.optional(Schema.Number.pipe(Schema.int(), Schema.positive()).annotations({
|
|
97
|
+
title: "\u6587\u4EF6\u6570\u91CF\u9650\u5236",
|
|
98
|
+
description: "\u5141\u8BB8\u540C\u65F6\u4E0A\u4F20\u7684\u6700\u5927\u6587\u4EF6\u6570\uFF1B\u8FBE\u5230\u4E0A\u9650\u540E\u65B0\u589E\u6587\u4EF6\u4F1A\u88AB\u62D2\u7EDD"
|
|
99
|
+
})),
|
|
100
|
+
// Immediate upload. Its presence enables "upload on pick": each picked file
|
|
101
|
+
// is POSTed right away (`request`), the response is mapped into the stored
|
|
102
|
+
// items (`handle`), and each stored item's display name is resolved via
|
|
103
|
+
// `filename`. Absent → files are held as raw `File[]` and submitted with the
|
|
104
|
+
// form (deferred mode). The canonical→backend write mapping lives in the
|
|
105
|
+
// submit action, not here, so the field stays backend-agnostic.
|
|
106
|
+
upload: Schema.optional(Schema.Struct({
|
|
107
|
+
request: CelUploadRequest.annotations({
|
|
108
|
+
title: "\u4E0A\u4F20\u8BF7\u6C42",
|
|
109
|
+
description: '\u8FD4\u56DE `HttpRequest` \u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u53EF\u901A\u8FC7 `files` \u5F15\u7528\u672C\u6B21\u9009\u62E9\u7684\u6587\u4EF6\uFF0C\u4F8B\u5982 `http.post(url).body(form({"files": files}))`\u3002\u4EE5 `.json()` \u53D1\u8D77'
|
|
110
|
+
}),
|
|
111
|
+
handle: CelUploadHandle.annotations({
|
|
112
|
+
title: "\u5904\u7406\u54CD\u5E94",
|
|
113
|
+
description: '\u8FD4\u56DE**\u5217\u8868**\u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u901A\u8FC7 `json` \u5F15\u7528\u4E0A\u4F20\u54CD\u5E94\uFF1B\u6620\u5C04\u4E3A\u8FFD\u52A0\u5230\u7ED1\u5B9A\u503C\u7684\u6587\u4EF6\u9879\uFF0C\u4F8B\u5982 `json.data.map(d, {"cacheKey": d.key, "filename": d.fileOriginalName})`'
|
|
114
|
+
}),
|
|
115
|
+
filename: Schema.optional(CelItemName.annotations({
|
|
116
|
+
title: "\u6587\u4EF6\u540D",
|
|
117
|
+
description: "\u8FD4\u56DE `string` \u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u901A\u8FC7 `file` \u5F15\u7528\u5355\u4E2A\u6587\u4EF6\u9879\uFF1B\u7528\u4E8E\u5C55\u793A\u6587\u4EF6\u540D\uFF0C\u4F8B\u5982 `file.filename`\u3002\u7559\u7A7A\u65F6\u56DE\u9000\u5230 `filename` / `name` \u5B57\u6BB5"
|
|
118
|
+
}))
|
|
119
|
+
}).annotations({
|
|
120
|
+
title: "\u5373\u65F6\u4E0A\u4F20",
|
|
121
|
+
description: "\u914D\u7F6E\u540E\u6587\u4EF6\u5728\u9009\u62E9\u65F6\u7ACB\u5373\u4E0A\u4F20\uFF0C\u7ED1\u5B9A\u503C\u5B58\u50A8\u6620\u5C04\u540E\u7684\u6587\u4EF6\u9879\uFF08\u800C\u975E\u539F\u59CB `File`\uFF09\uFF1B\u4E0D\u914D\u7F6E\u5219\u4FDD\u7559\u6587\u4EF6\u968F\u8868\u5355\u4E00\u5E76\u63D0\u4EA4"
|
|
122
|
+
})),
|
|
123
|
+
// Download templates — each entry renders one button next to the upload
|
|
124
|
+
// zone. `request` is the (possibly only) step; `download` is an optional
|
|
125
|
+
// second step that may reference the first response via `json`.
|
|
126
|
+
templates: Schema.optional(Schema.Array(Schema.Struct({
|
|
127
|
+
request: CelHttpRequest.annotations({
|
|
128
|
+
title: "\u8BF7\u6C42",
|
|
129
|
+
description: "\u8FD4\u56DE `HttpRequest` \u7684 CEL \u8868\u8FBE\u5F0F\u3002\u672A\u914D\u7F6E\u300C\u4E0B\u8F7D\u8BF7\u6C42\u300D\u65F6\u76F4\u63A5\u53D1\u8D77\u5E76\u4E0B\u8F7D\u5176\u54CD\u5E94\uFF1B\u914D\u7F6E\u4E86\u300C\u4E0B\u8F7D\u8BF7\u6C42\u300D\u65F6\u4F5C\u4E3A\u83B7\u53D6\u4E0B\u8F7D\u51ED\u636E\u7684\u7B2C\u4E00\u6B65\u8BF7\u6C42"
|
|
130
|
+
}),
|
|
131
|
+
download: Schema.optional(CelDownloadRequest.annotations({
|
|
132
|
+
title: "\u4E0B\u8F7D\u8BF7\u6C42",
|
|
133
|
+
description: "\u53EF\u9009\u7684\u7B2C\u4E8C\u6B65\uFF1A\u8FD4\u56DE `HttpRequest` \u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u901A\u8FC7 `json` \u5F15\u7528\u7B2C\u4E00\u6B65\u7684\u54CD\u5E94\u4F53\uFF0C\u4F8B\u5982\u7528 `json.data.key` \u6784\u9020\u771F\u6B63\u7684\u4E0B\u8F7D\u8BF7\u6C42"
|
|
134
|
+
})),
|
|
135
|
+
icon: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
|
|
136
|
+
title: "\u6A21\u677F\u6309\u94AE\u56FE\u6807",
|
|
137
|
+
description: "Iconify \u56FE\u6807\u6807\u8BC6\u7B26\uFF0C\u4F8B\u5982 `fluent:arrow-download-20-regular`\uFF1B\u7559\u7A7A\u65F6\u4F7F\u7528\u9ED8\u8BA4\u56FE\u6807"
|
|
138
|
+
})),
|
|
139
|
+
label: Schema.optional(Locale.annotations({
|
|
140
|
+
title: "\u6A21\u677F\u6309\u94AE\u6587\u672C",
|
|
141
|
+
description: "\u4E0B\u8F7D\u6A21\u677F\u6309\u94AE\u4E0A\u7684\u672C\u5730\u5316\u6587\u672C\uFF1B\u7559\u7A7A\u65F6\u4F7F\u7528\u300C\u4E0B\u8F7D\u6A21\u677F\u300D"
|
|
142
|
+
}))
|
|
143
|
+
})).annotations({
|
|
144
|
+
title: "\u4E0B\u8F7D\u6A21\u677F",
|
|
145
|
+
description: "\u4E0B\u8F7D\u6A21\u677F\u5217\u8868\uFF1B\u6BCF\u4E00\u9879\u5728\u4E0A\u4F20\u533A\u57DF\u65C1\u6E32\u67D3\u4E00\u4E2A\u4E0B\u8F7D\u6309\u94AE"
|
|
146
|
+
}))
|
|
147
|
+
}).annotations({
|
|
148
|
+
title: "UploadField",
|
|
149
|
+
description: "\u6587\u4EF6\u4E0A\u4F20\u5B57\u6BB5"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
export function migrate(prev) {
|
|
153
|
+
return Effect.try({
|
|
154
|
+
try: () => {
|
|
155
|
+
if (typeof prev !== "object" || prev === null) {
|
|
156
|
+
throw new Error("\u4E0A\u4F20\u5B57\u6BB5\u8FC1\u79FB\u5931\u8D25\uFF1A\u539F\u914D\u7F6E\u4E0D\u662F\u5BF9\u8C61");
|
|
157
|
+
}
|
|
158
|
+
const {
|
|
159
|
+
template,
|
|
160
|
+
templateIcon,
|
|
161
|
+
templateLabel,
|
|
162
|
+
compatibilityDate: _drop,
|
|
163
|
+
...rest
|
|
164
|
+
} = prev;
|
|
165
|
+
const next = { ...rest, compatibilityDate };
|
|
166
|
+
if (template != null && typeof template === "object" && typeof template.request === "string") {
|
|
167
|
+
const t = template;
|
|
168
|
+
const entry = { request: t.request };
|
|
169
|
+
if (typeof t.download === "string") entry.download = t.download;
|
|
170
|
+
if (typeof templateIcon === "string") entry.icon = templateIcon;
|
|
171
|
+
if (templateLabel != null) entry.label = templateLabel;
|
|
172
|
+
next.templates = [entry];
|
|
173
|
+
}
|
|
174
|
+
return next;
|
|
175
|
+
},
|
|
176
|
+
catch: (error) => error instanceof Error ? error : new Error(String(error))
|
|
177
|
+
});
|
|
178
|
+
}
|
|
@@ -24,8 +24,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
24
24
|
"onUpdate:modelValue"?: ((args_0: Date | undefined) => any) | undefined;
|
|
25
25
|
}>, {
|
|
26
26
|
size: "sm" | "md" | "lg";
|
|
27
|
-
clearIcon: string;
|
|
28
27
|
clearable: boolean;
|
|
28
|
+
clearIcon: string;
|
|
29
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
30
|
declare const _default: typeof __VLS_export;
|
|
31
31
|
export default _default;
|
|
@@ -24,8 +24,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
24
24
|
"onUpdate:modelValue"?: ((args_0: Date | undefined) => any) | undefined;
|
|
25
25
|
}>, {
|
|
26
26
|
size: "sm" | "md" | "lg";
|
|
27
|
-
clearIcon: string;
|
|
28
27
|
clearable: boolean;
|
|
28
|
+
clearIcon: string;
|
|
29
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
30
|
declare const _default: typeof __VLS_export;
|
|
31
31
|
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;
|
|
@@ -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;
|
|
@@ -26,7 +26,7 @@ The custom `Optional` class has been replaced with Effect's `Option` type (`impo
|
|
|
26
26
|
|
|
27
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.
|
|
28
28
|
|
|
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()`
|
|
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`.
|
|
31
31
|
|
|
32
32
|
A `JSON` built-in namespace has been added (`json-builtins.ts`) — not from upstream. It registers a `JSON` brand class and a same-named constant on `globalRegistry`, so `JSON.parse(string): dyn` and `JSON.stringify(dyn): string` resolve in every `Environment`. The CEL-side surface mirrors the JS globals deliberately. `JSON.parse` is a thin wrapper over `globalThis.JSON.parse` — numbers come back as plain JS `number` (the evaluator coerces via `Decimal.from` at use time). `JSON.stringify` pre-walks the value via `normalizeForJSON` before handing it to `globalThis.JSON.stringify`: `Decimal` → JS number (via `.toNumber()` — loses precision past safe-integer range, deliberate trade-off for idiomatic JSON output), `Option.Some(x)` → `x`, `Option.None` → `null`, `Map` → plain object, `Date`/`TZDate` passes through so its built-in `toJSON` emits ISO 8601. The pre-walk is required because Effect's `Option` defines its own `toJSON()` that runs before any replacer would see it.
|
|
@@ -198,8 +198,8 @@ http.post("https://api.example.com/files")
|
|
|
198
198
|
.body(form({"file": myFile, "name": "Alice", "tags": ["a", "b"]}))
|
|
199
199
|
```
|
|
200
200
|
`form(map): FormData` turns a flat record into a native `FormData`. Pass it
|
|
201
|
-
straight to `.body(...)` —
|
|
202
|
-
need a `Content-Type` header.
|
|
201
|
+
straight to `.body(...)` — the builder derives the multipart `Content-Type`
|
|
202
|
+
(boundary included), so you don't need a `Content-Type` header.
|
|
203
203
|
|
|
204
204
|
Value coercion is flat (same rules as `.query(...)`):
|
|
205
205
|
- `null` / `undefined` / absent `.?` values → key is skipped
|
|
@@ -134,6 +134,19 @@ export class HttpRequestBuilder {
|
|
|
134
134
|
const explicit = new Set(this.#headers.map(([k]) => k.toLowerCase()));
|
|
135
135
|
const headers = {};
|
|
136
136
|
for (const [k, v] of this.#headers) headers[k] = v;
|
|
137
|
+
if (this.#body !== void 0) {
|
|
138
|
+
if (this.#body instanceof FormData) {
|
|
139
|
+
const serialized = new Response(this.#body);
|
|
140
|
+
const contentType = serialized.headers.get("content-type");
|
|
141
|
+
if (contentType !== null && !explicit.has("content-type")) {
|
|
142
|
+
headers["Content-Type"] = contentType;
|
|
143
|
+
explicit.add("content-type");
|
|
144
|
+
}
|
|
145
|
+
parts.body = serialized.blob();
|
|
146
|
+
} else {
|
|
147
|
+
parts.body = this.#body;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
137
150
|
for (const [key, { name, get }] of HttpRequestBuilder.#defaultHeaders) {
|
|
138
151
|
if (explicit.has(key)) continue;
|
|
139
152
|
const v = get();
|
|
@@ -143,9 +156,6 @@ export class HttpRequestBuilder {
|
|
|
143
156
|
if (Object.keys(headers).length > 0) {
|
|
144
157
|
parts.headers = headers;
|
|
145
158
|
}
|
|
146
|
-
if (this.#body !== void 0) {
|
|
147
|
-
parts.body = this.#body;
|
|
148
|
-
}
|
|
149
159
|
let request = FxRequest.unsafeMake(parts);
|
|
150
160
|
for (const [k, v] of this.#queries) {
|
|
151
161
|
request = FxRequest.appendUrlSearchParam(request, k, v);
|