@josephyan/qingflow-cli 0.2.0-beta.68 → 0.2.0-beta.70

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.
@@ -0,0 +1,668 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from copy import deepcopy
5
+ from functools import wraps
6
+ from typing import Any, Callable
7
+
8
+
9
+ JSONObject = dict[str, Any]
10
+ TransformFn = Callable[[JSONObject], None]
11
+
12
+
13
+ COMMON_SUCCESS_DROP_TOP = {
14
+ "request_route",
15
+ "profile",
16
+ "ws_id",
17
+ "output_profile",
18
+ "qf_version_source",
19
+ "persisted",
20
+ "base_url",
21
+ "normalized_args",
22
+ "suggested_next_call",
23
+ "noop",
24
+ "allowed_values",
25
+ "missing_fields",
26
+ "ok",
27
+ }
28
+
29
+ COMMON_ERROR_DROP_TOP = {
30
+ "request_route",
31
+ "base_url",
32
+ "normalized_args",
33
+ "suggested_next_call",
34
+ "profile",
35
+ "ws_id",
36
+ "output_profile",
37
+ "qf_version_source",
38
+ "persisted",
39
+ "allowed_values",
40
+ "missing_fields",
41
+ "noop",
42
+ "ok",
43
+ }
44
+
45
+ SUCCESS_POLICY_BY_TOOL: dict[str, TransformFn] = {}
46
+
47
+
48
+ def trim_public_response(tool_name: str | None, payload: dict[str, Any]) -> dict[str, Any]:
49
+ if not isinstance(payload, dict):
50
+ return payload
51
+ if _looks_like_failure_payload(payload):
52
+ return _trim_returned_failure(payload)
53
+ return trim_success_response(tool_name, payload)
54
+
55
+
56
+ def trim_success_response(tool_name: str | None, payload: dict[str, Any]) -> dict[str, Any]:
57
+ if not isinstance(payload, dict):
58
+ return payload
59
+ trimmed = deepcopy(payload)
60
+ _drop_top_keys(trimmed, COMMON_SUCCESS_DROP_TOP)
61
+ transformer = SUCCESS_POLICY_BY_TOOL.get(tool_name or "")
62
+ if transformer is not None:
63
+ transformer(trimmed)
64
+ _drop_empty_optional_keys(trimmed)
65
+ return trimmed
66
+
67
+
68
+ def trim_error_response(payload: dict[str, Any]) -> dict[str, Any]:
69
+ if not isinstance(payload, dict):
70
+ return payload
71
+ trimmed = deepcopy(payload)
72
+ _drop_top_keys(trimmed, COMMON_ERROR_DROP_TOP)
73
+ _drop_deep_keys(trimmed.get("details"), {"request_route", "base_url", "normalized_args", "suggested_next_call", "transport", "response", "body", "raw"})
74
+ details = trimmed.get("details")
75
+ if isinstance(details, dict):
76
+ compact_details = _compact_scalar_dict(details)
77
+ if compact_details:
78
+ trimmed["details"] = compact_details
79
+ else:
80
+ trimmed.pop("details", None)
81
+ if trimmed.get("backend_code") is not None:
82
+ trimmed.pop("http_status", None)
83
+ _drop_empty_optional_keys(trimmed)
84
+ return trimmed
85
+
86
+
87
+ def wrap_trimmed_methods(instance: object, method_map: dict[str, str]) -> object:
88
+ for method_name, tool_name in method_map.items():
89
+ original = getattr(instance, method_name, None)
90
+ if original is None or not callable(original):
91
+ continue
92
+ setattr(instance, method_name, _wrap_callable(original, tool_name))
93
+ return instance
94
+
95
+
96
+ def resolve_cli_tool_name(args: Any) -> str | None:
97
+ command = getattr(args, "command", None)
98
+ if command == "auth":
99
+ return {
100
+ "login": "auth_login",
101
+ "use-token": "auth_use_token",
102
+ "whoami": "auth_whoami",
103
+ "logout": "auth_logout",
104
+ }.get(getattr(args, "auth_command", None))
105
+ if command == "workspace":
106
+ return {
107
+ "list": "workspace_list",
108
+ "select": "workspace_select",
109
+ }.get(getattr(args, "workspace_command", None))
110
+ if command == "app":
111
+ return {
112
+ "list": "app_list",
113
+ "search": "app_search",
114
+ "get": "app_get",
115
+ }.get(getattr(args, "app_command", None))
116
+ if command == "record":
117
+ record_command = getattr(args, "record_command", None)
118
+ if record_command == "schema":
119
+ return {
120
+ "applicant": "record_schema_get",
121
+ "browse": "record_browse_schema_get",
122
+ "insert": "record_insert_schema_get",
123
+ "update": "record_update_schema_get",
124
+ "import": "record_import_schema_get",
125
+ "code-block": "record_code_block_schema_get",
126
+ }.get(getattr(args, "record_schema_command", None))
127
+ return {
128
+ "list": "record_list",
129
+ "get": "record_get",
130
+ "insert": "record_insert",
131
+ "update": "record_update",
132
+ "delete": "record_delete",
133
+ "analyze": "record_analyze",
134
+ "code-block-run": "record_code_block_run",
135
+ }.get(record_command)
136
+ if command == "import":
137
+ return {
138
+ "template": "record_import_template_get",
139
+ "verify": "record_import_verify",
140
+ "repair": "record_import_repair_local",
141
+ "start": "record_import_start",
142
+ "status": "record_import_status_get",
143
+ }.get(getattr(args, "import_command", None))
144
+ if command == "task":
145
+ return {
146
+ "list": "task_list",
147
+ "get": "task_get",
148
+ "action": "task_action_execute",
149
+ "log": "task_workflow_log_get",
150
+ }.get(getattr(args, "task_command", None))
151
+ if command not in {"builder", "build"}:
152
+ return None
153
+ builder_command = getattr(args, "builder_command", None)
154
+ if builder_command == "contract":
155
+ return "builder_tool_contract"
156
+ if builder_command == "member":
157
+ return {
158
+ "search": "member_search",
159
+ }.get(getattr(args, "builder_member_command", None))
160
+ if builder_command == "role":
161
+ return {
162
+ "search": "role_search",
163
+ "create": "role_create",
164
+ }.get(getattr(args, "builder_role_command", None))
165
+ if builder_command == "package":
166
+ return {
167
+ "list": "package_list",
168
+ "resolve": "package_resolve",
169
+ "create": "package_create",
170
+ "attach-app": "package_attach_app",
171
+ }.get(getattr(args, "builder_package_command", None))
172
+ if builder_command == "app":
173
+ return {
174
+ "resolve": "app_resolve",
175
+ "release-edit-lock-if-mine": "app_release_edit_lock_if_mine",
176
+ "read-summary": "app_read_summary",
177
+ "read-fields": "app_read_fields",
178
+ "read-layout": "app_read_layout_summary",
179
+ "read-views": "app_read_views_summary",
180
+ "read-flow": "app_read_flow_summary",
181
+ "read-charts": "app_read_charts_summary",
182
+ }.get(getattr(args, "builder_app_command", None))
183
+ if builder_command == "button":
184
+ return {
185
+ "list": "app_custom_button_list",
186
+ "get": "app_custom_button_get",
187
+ "create": "app_custom_button_create",
188
+ "update": "app_custom_button_update",
189
+ "delete": "app_custom_button_delete",
190
+ }.get(getattr(args, "builder_button_command", None))
191
+ if builder_command == "portal":
192
+ return {
193
+ "list": "portal_list",
194
+ "get": "portal_get",
195
+ "read-summary": "portal_read_summary",
196
+ "apply": "portal_apply",
197
+ }.get(getattr(args, "builder_portal_command", None))
198
+ if builder_command == "view":
199
+ return {
200
+ "get": "view_get",
201
+ }.get(getattr(args, "builder_view_command", None))
202
+ if builder_command == "chart":
203
+ return {
204
+ "get": "chart_get",
205
+ }.get(getattr(args, "builder_chart_command", None))
206
+ if builder_command == "schema":
207
+ return {"apply": "app_schema_apply"}.get(getattr(args, "builder_schema_command", None))
208
+ if builder_command == "layout":
209
+ return {"apply": "app_layout_apply"}.get(getattr(args, "builder_layout_command", None))
210
+ if builder_command == "views":
211
+ return {"apply": "app_views_apply"}.get(getattr(args, "builder_views_command", None))
212
+ if builder_command == "flow":
213
+ return {"apply": "app_flow_apply"}.get(getattr(args, "builder_flow_command", None))
214
+ if builder_command == "charts":
215
+ return {"apply": "app_charts_apply"}.get(getattr(args, "builder_charts_command", None))
216
+ if builder_command == "publish":
217
+ return {"verify": "app_publish_verify"}.get(getattr(args, "builder_publish_command", None))
218
+ return None
219
+
220
+
221
+ USER_SERVER_METHOD_MAP = {
222
+ "auth_login": "auth_login",
223
+ "auth_use_token": "auth_use_token",
224
+ "auth_whoami": "auth_whoami",
225
+ "auth_logout": "auth_logout",
226
+ "workspace_list": "workspace_list",
227
+ "workspace_select": "workspace_select",
228
+ "app_list": "app_list",
229
+ "app_search": "app_search",
230
+ "app_get": "app_get",
231
+ "file_get_upload_info": "file_get_upload_info",
232
+ "file_upload_local": "file_upload_local",
233
+ "feedback_submit": "feedback_submit",
234
+ "record_import_schema_get": "record_import_schema_get",
235
+ "record_import_template_get": "record_import_template_get",
236
+ "record_import_verify": "record_import_verify",
237
+ "record_import_repair_local": "record_import_repair_local",
238
+ "record_import_start": "record_import_start",
239
+ "record_import_status_get": "record_import_status_get",
240
+ "record_insert_schema_get_public": "record_insert_schema_get",
241
+ "record_member_candidates": "record_member_candidates",
242
+ "record_department_candidates": "record_department_candidates",
243
+ "record_analyze": "record_analyze",
244
+ "record_list": "record_list",
245
+ "record_get_public": "record_get",
246
+ "record_browse_schema_get_public": "record_browse_schema_get",
247
+ "record_update_schema_get_public": "record_update_schema_get",
248
+ "record_insert_public": "record_insert",
249
+ "record_update_public": "record_update",
250
+ "record_delete_public": "record_delete",
251
+ "record_code_block_schema_get_public": "record_code_block_schema_get",
252
+ "record_code_block_run": "record_code_block_run",
253
+ "task_list": "task_list",
254
+ "task_get": "task_get",
255
+ "task_action_execute": "task_action_execute",
256
+ "task_associated_report_detail_get": "task_associated_report_detail_get",
257
+ "task_workflow_log_get": "task_workflow_log_get",
258
+ "directory_search": "directory_search",
259
+ "directory_list_internal_users": "directory_list_internal_users",
260
+ "directory_list_all_internal_users": "directory_list_all_internal_users",
261
+ "directory_list_internal_departments": "directory_list_internal_departments",
262
+ "directory_list_all_departments": "directory_list_all_departments",
263
+ "directory_list_sub_departments": "directory_list_sub_departments",
264
+ "directory_list_external_members": "directory_list_external_members",
265
+ }
266
+
267
+ BUILDER_SERVER_METHOD_MAP = {
268
+ "auth_login": "auth_login",
269
+ "auth_use_token": "auth_use_token",
270
+ "auth_whoami": "auth_whoami",
271
+ "auth_logout": "auth_logout",
272
+ "workspace_list": "workspace_list",
273
+ "workspace_select": "workspace_select",
274
+ "file_upload_local": "file_upload_local",
275
+ "feedback_submit": "feedback_submit",
276
+ "package_list": "package_list",
277
+ "package_resolve": "package_resolve",
278
+ "builder_tool_contract": "builder_tool_contract",
279
+ "package_create": "package_create",
280
+ "member_search": "member_search",
281
+ "role_search": "role_search",
282
+ "role_create": "role_create",
283
+ "package_attach_app": "package_attach_app",
284
+ "app_release_edit_lock_if_mine": "app_release_edit_lock_if_mine",
285
+ "app_resolve": "app_resolve",
286
+ "app_custom_button_list": "app_custom_button_list",
287
+ "app_custom_button_get": "app_custom_button_get",
288
+ "app_custom_button_create": "app_custom_button_create",
289
+ "app_custom_button_update": "app_custom_button_update",
290
+ "app_custom_button_delete": "app_custom_button_delete",
291
+ "app_read_summary": "app_read_summary",
292
+ "app_read_fields": "app_read_fields",
293
+ "app_read_layout_summary": "app_read_layout_summary",
294
+ "app_read_views_summary": "app_read_views_summary",
295
+ "app_read_flow_summary": "app_read_flow_summary",
296
+ "app_read_charts_summary": "app_read_charts_summary",
297
+ "portal_list": "portal_list",
298
+ "portal_get": "portal_get",
299
+ "portal_read_summary": "portal_read_summary",
300
+ "view_get": "view_get",
301
+ "chart_get": "chart_get",
302
+ "app_schema_apply": "app_schema_apply",
303
+ "app_layout_apply": "app_layout_apply",
304
+ "app_flow_apply": "app_flow_apply",
305
+ "app_views_apply": "app_views_apply",
306
+ "app_charts_apply": "app_charts_apply",
307
+ "portal_apply": "portal_apply",
308
+ "app_publish_verify": "app_publish_verify",
309
+ }
310
+
311
+
312
+ def _wrap_callable(original: Callable[..., Any], tool_name: str) -> Callable[..., Any]:
313
+ @wraps(original)
314
+ def wrapped(*args: Any, **kwargs: Any) -> Any:
315
+ try:
316
+ result = original(*args, **kwargs)
317
+ except RuntimeError as exc:
318
+ payload = _parse_runtime_error_payload(exc)
319
+ if payload is None:
320
+ raise
321
+ raise RuntimeError(json.dumps(trim_error_response(payload), ensure_ascii=False)) from None
322
+ return trim_public_response(tool_name, result) if isinstance(result, dict) else result
323
+
324
+ return wrapped
325
+
326
+
327
+ def _parse_runtime_error_payload(exc: RuntimeError) -> dict[str, Any] | None:
328
+ raw = str(exc)
329
+ try:
330
+ payload = json.loads(raw)
331
+ except json.JSONDecodeError:
332
+ return None
333
+ return payload if isinstance(payload, dict) else None
334
+
335
+
336
+ def _looks_like_failure_payload(payload: dict[str, Any]) -> bool:
337
+ if payload.get("ok") is False:
338
+ return True
339
+ status = str(payload.get("status") or "").lower()
340
+ return status in {"failed", "blocked", "verification_failed"}
341
+
342
+
343
+ def _trim_returned_failure(payload: dict[str, Any]) -> dict[str, Any]:
344
+ trimmed = deepcopy(payload)
345
+ _drop_top_keys(trimmed, COMMON_ERROR_DROP_TOP)
346
+ _drop_deep_keys(trimmed.get("details"), {"request_route", "base_url", "normalized_args", "suggested_next_call", "transport", "response", "body", "raw"})
347
+ details = trimmed.get("details")
348
+ if isinstance(details, dict):
349
+ compact_details = _compact_scalar_dict(details)
350
+ if compact_details:
351
+ trimmed["details"] = compact_details
352
+ else:
353
+ trimmed.pop("details", None)
354
+ if trimmed.get("backend_code") is not None:
355
+ trimmed.pop("http_status", None)
356
+ _drop_empty_optional_keys(trimmed)
357
+ return trimmed
358
+
359
+
360
+ def _drop_top_keys(payload: JSONObject, keys: set[str]) -> None:
361
+ for key in keys:
362
+ payload.pop(key, None)
363
+
364
+
365
+ def _drop_empty_optional_keys(payload: JSONObject) -> None:
366
+ for key in ("warnings", "verification", "details"):
367
+ value = payload.get(key)
368
+ if value in (None, [], {}, ""):
369
+ payload.pop(key, None)
370
+
371
+
372
+ def _compact_scalar_dict(payload: dict[str, Any]) -> dict[str, Any]:
373
+ compact: dict[str, Any] = {}
374
+ for key, value in payload.items():
375
+ if isinstance(value, (str, int, float, bool)) or value is None:
376
+ compact[key] = value
377
+ continue
378
+ if isinstance(value, dict):
379
+ nested = {
380
+ nested_key: nested_value
381
+ for nested_key, nested_value in value.items()
382
+ if isinstance(nested_value, (str, int, float, bool)) or nested_value is None
383
+ }
384
+ if nested:
385
+ compact[key] = nested
386
+ return compact
387
+
388
+
389
+ def _trim_item_list(payload: JSONObject, key: str, *, allowed: tuple[str, ...]) -> None:
390
+ items = payload.get(key)
391
+ if not isinstance(items, list):
392
+ return
393
+ payload[key] = [_pick(item, allowed) for item in items if isinstance(item, dict)]
394
+
395
+
396
+ def _trim_nested_item_list(payload: JSONObject, path: tuple[str, ...], *, allowed: tuple[str, ...]) -> None:
397
+ parent = _nested_dict(payload, path[:-1])
398
+ if not isinstance(parent, dict):
399
+ return
400
+ key = path[-1]
401
+ items = parent.get(key)
402
+ if not isinstance(items, list):
403
+ return
404
+ parent[key] = [_pick(item, allowed) for item in items if isinstance(item, dict)]
405
+
406
+
407
+ def _keep_nested_keys(payload: JSONObject, path: tuple[str, ...], *, allowed: tuple[str, ...]) -> None:
408
+ parent = _nested_dict(payload, path[:-1])
409
+ if not isinstance(parent, dict):
410
+ return
411
+ node = parent.get(path[-1])
412
+ if isinstance(node, dict):
413
+ parent[path[-1]] = _pick(node, allowed)
414
+
415
+
416
+ def _drop_nested_keys(payload: JSONObject, path: tuple[str, ...], *, keys: tuple[str, ...]) -> None:
417
+ parent = _nested_dict(payload, path[:-1])
418
+ if not isinstance(parent, dict):
419
+ return
420
+ node = parent.get(path[-1])
421
+ if not isinstance(node, dict):
422
+ return
423
+ for key in keys:
424
+ node.pop(key, None)
425
+
426
+
427
+ def _drop_deep_keys(payload: Any, keys: set[str]) -> None:
428
+ if isinstance(payload, dict):
429
+ for key in list(payload.keys()):
430
+ if key in keys:
431
+ payload.pop(key, None)
432
+ continue
433
+ _drop_deep_keys(payload.get(key), keys)
434
+ elif isinstance(payload, list):
435
+ for item in payload:
436
+ _drop_deep_keys(item, keys)
437
+
438
+
439
+ def _nested_dict(payload: JSONObject, path: tuple[str, ...]) -> JSONObject | None:
440
+ node: Any = payload
441
+ for key in path:
442
+ if not isinstance(node, dict):
443
+ return None
444
+ node = node.get(key)
445
+ return node if isinstance(node, dict) else None
446
+
447
+
448
+ def _pick(payload: JSONObject, allowed: tuple[str, ...]) -> JSONObject:
449
+ return {key: payload.get(key) for key in allowed if key in payload}
450
+
451
+
452
+ def _trim_auth_payload(payload: JSONObject) -> None:
453
+ pass
454
+
455
+
456
+ def _trim_auth_logout(payload: JSONObject) -> None:
457
+ pass
458
+
459
+
460
+ def _trim_workspace_list(payload: JSONObject) -> None:
461
+ page = payload.get("page")
462
+ if isinstance(page, dict):
463
+ _trim_item_list(page, "list", allowed=("wsId", "workspaceName", "remark"))
464
+
465
+
466
+ def _trim_workspace_select(payload: JSONObject) -> None:
467
+ workspace = payload.get("workspace")
468
+ if isinstance(workspace, dict):
469
+ payload["workspace"] = _pick(workspace, ("wsId", "workspaceName"))
470
+
471
+
472
+ def _trim_app_search_like(payload: JSONObject) -> None:
473
+ payload.pop("apps", None)
474
+ _trim_item_list(payload, "items", allowed=("app_key", "app_name", "package_name"))
475
+
476
+
477
+ def _trim_app_get(payload: JSONObject) -> None:
478
+ _trim_nested_item_list(
479
+ payload,
480
+ ("data", "accessible_views"),
481
+ allowed=("view_id", "name", "analysis_supported", "list_supported", "kind"),
482
+ )
483
+
484
+
485
+ def _trim_file_upload_info(payload: JSONObject) -> None:
486
+ pass
487
+
488
+
489
+ def _trim_file_upload_local(payload: JSONObject) -> None:
490
+ payload.pop("result", None)
491
+ payload.pop("upload_result", None)
492
+
493
+
494
+ def _trim_import_schema(payload: JSONObject) -> None:
495
+ pass
496
+
497
+
498
+ def _trim_record_schema(payload: JSONObject) -> None:
499
+ payload.pop("legacy_schema", None)
500
+
501
+
502
+ def _trim_record_write(payload: JSONObject) -> None:
503
+ data = payload.get("data")
504
+ if not isinstance(data, dict):
505
+ return
506
+ data.pop("normalized_payload", None)
507
+ data.pop("human_review", None)
508
+ data.pop("action", None)
509
+
510
+
511
+ def _trim_record_get(payload: JSONObject) -> None:
512
+ _keep_nested_keys(payload, ("data", "selection", "view"), allowed=("view_id", "name"))
513
+ _drop_nested_keys(payload, ("data", "selection"), keys=("columns", "workflow_node_id"))
514
+
515
+
516
+ def _trim_record_list(payload: JSONObject) -> None:
517
+ _keep_nested_keys(payload, ("data", "selection", "view"), allowed=("view_id", "name"))
518
+ _drop_nested_keys(payload, ("data", "selection"), keys=("columns",))
519
+
520
+
521
+ def _trim_record_analyze(payload: JSONObject) -> None:
522
+ _drop_deep_keys(payload, {"debug"})
523
+
524
+
525
+ def _trim_code_block_schema(payload: JSONObject) -> None:
526
+ payload.pop("legacy_schema", None)
527
+ _trim_nested_item_list(payload, ("code_block_fields",), allowed=("title", "selector", "bound_output_fields", "configured_aliases"))
528
+
529
+
530
+ def _trim_code_block_run(payload: JSONObject) -> None:
531
+ _drop_deep_keys(payload, {"debug", "request_route"})
532
+
533
+
534
+ def _trim_task_list(payload: JSONObject) -> None:
535
+ _drop_nested_keys(payload, ("data", "selection"), keys=("query",))
536
+
537
+
538
+ def _trim_task_get(payload: JSONObject) -> None:
539
+ _drop_deep_keys(payload, {"request_route", "output_profile"})
540
+
541
+
542
+ def _trim_directory(payload: JSONObject) -> None:
543
+ pass
544
+
545
+
546
+ def _trim_feedback(payload: JSONObject) -> None:
547
+ payload.pop("normalized_payload", None)
548
+
549
+
550
+ def _trim_builder_envelope(payload: JSONObject) -> None:
551
+ if str(payload.get("status") or "").lower() == "success":
552
+ details = payload.get("details")
553
+ if isinstance(details, dict):
554
+ _drop_deep_keys(details, {"request_route", "base_url", "normalized_args", "suggested_next_call", "transport", "response", "body", "raw"})
555
+ compact = _compact_scalar_dict(details)
556
+ if compact:
557
+ payload["details"] = compact
558
+ else:
559
+ payload.pop("details", None)
560
+
561
+
562
+ def _trim_builder_list_like(payload: JSONObject) -> None:
563
+ _trim_builder_envelope(payload)
564
+
565
+
566
+ def _register_policy(names: tuple[str, ...], transform: TransformFn) -> None:
567
+ for name in names:
568
+ SUCCESS_POLICY_BY_TOOL[name] = transform
569
+
570
+
571
+ _register_policy(("auth_login", "auth_use_token", "auth_whoami"), _trim_auth_payload)
572
+ _register_policy(("auth_logout",), _trim_auth_logout)
573
+ _register_policy(("workspace_list",), _trim_workspace_list)
574
+ _register_policy(("workspace_select",), _trim_workspace_select)
575
+ _register_policy(("app_list", "app_search"), _trim_app_search_like)
576
+ _register_policy(("app_get",), _trim_app_get)
577
+ _register_policy(("file_get_upload_info",), _trim_file_upload_info)
578
+ _register_policy(("file_upload_local",), _trim_file_upload_local)
579
+ _register_policy(
580
+ (
581
+ "record_import_schema_get",
582
+ "record_import_template_get",
583
+ "record_import_verify",
584
+ "record_import_repair_local",
585
+ "record_import_start",
586
+ "record_import_status_get",
587
+ ),
588
+ _trim_import_schema,
589
+ )
590
+ _register_policy(
591
+ (
592
+ "record_schema_get",
593
+ "record_insert_schema_get",
594
+ "record_browse_schema_get",
595
+ "record_update_schema_get",
596
+ "record_code_block_schema_get",
597
+ ),
598
+ _trim_record_schema,
599
+ )
600
+ _register_policy(("record_insert", "record_update"), _trim_record_write)
601
+ _register_policy(("record_get",), _trim_record_get)
602
+ _register_policy(("record_list",), _trim_record_list)
603
+ _register_policy(("record_analyze",), _trim_record_analyze)
604
+ _register_policy(("record_code_block_run",), _trim_code_block_run)
605
+ _register_policy(("task_list",), _trim_task_list)
606
+ _register_policy(
607
+ (
608
+ "task_get",
609
+ "task_action_execute",
610
+ "task_associated_report_detail_get",
611
+ "task_workflow_log_get",
612
+ ),
613
+ _trim_task_get,
614
+ )
615
+ _register_policy(
616
+ (
617
+ "directory_search",
618
+ "directory_list_internal_users",
619
+ "directory_list_all_internal_users",
620
+ "directory_list_internal_departments",
621
+ "directory_list_all_departments",
622
+ "directory_list_sub_departments",
623
+ "directory_list_external_members",
624
+ ),
625
+ _trim_directory,
626
+ )
627
+ _register_policy(("feedback_submit",), _trim_feedback)
628
+ _register_policy(
629
+ (
630
+ "record_member_candidates",
631
+ "record_department_candidates",
632
+ "record_delete",
633
+ "package_list",
634
+ "package_resolve",
635
+ "builder_tool_contract",
636
+ "package_create",
637
+ "member_search",
638
+ "role_search",
639
+ "role_create",
640
+ "package_attach_app",
641
+ "app_release_edit_lock_if_mine",
642
+ "app_resolve",
643
+ "app_custom_button_list",
644
+ "app_custom_button_get",
645
+ "app_custom_button_create",
646
+ "app_custom_button_update",
647
+ "app_custom_button_delete",
648
+ "app_read_summary",
649
+ "app_read_fields",
650
+ "app_read_layout_summary",
651
+ "app_read_views_summary",
652
+ "app_read_flow_summary",
653
+ "app_read_charts_summary",
654
+ "portal_list",
655
+ "portal_get",
656
+ "portal_read_summary",
657
+ "view_get",
658
+ "chart_get",
659
+ "app_schema_apply",
660
+ "app_layout_apply",
661
+ "app_flow_apply",
662
+ "app_views_apply",
663
+ "app_charts_apply",
664
+ "portal_apply",
665
+ "app_publish_verify",
666
+ ),
667
+ _trim_builder_list_like,
668
+ )