@anchrd/intel 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +496 -0
- package/bin/intel.mjs +134 -0
- package/dist/adapters/cloudflare/cloudflare-flow-workflow.d.ts +42 -0
- package/dist/adapters/cloudflare/cloudflare-flow-workflow.js +89 -0
- package/dist/adapters/cloudflare/cloudflare.d.ts +29 -0
- package/dist/adapters/cloudflare/cloudflare.js +416 -0
- package/dist/adapters/cloudflare/cloudflare.types.d.ts +31 -0
- package/dist/adapters/cloudflare/cloudflare.types.js +1 -0
- package/dist/adapters/content/content.d.ts +3 -0
- package/dist/adapters/content/content.js +128 -0
- package/dist/adapters/content/content.types.d.ts +38 -0
- package/dist/adapters/content/content.types.js +1 -0
- package/dist/adapters/db/db-audit.d.ts +62 -0
- package/dist/adapters/db/db-audit.js +150 -0
- package/dist/adapters/db/db-boards.d.ts +6 -0
- package/dist/adapters/db/db-boards.js +324 -0
- package/dist/adapters/db/db-feed.d.ts +30 -0
- package/dist/adapters/db/db-feed.js +276 -0
- package/dist/adapters/db/db-flows.d.ts +42 -0
- package/dist/adapters/db/db-flows.js +1311 -0
- package/dist/adapters/db/db-grants.d.ts +133 -0
- package/dist/adapters/db/db-grants.js +269 -0
- package/dist/adapters/db/db-indexing.d.ts +3 -0
- package/dist/adapters/db/db-indexing.js +200 -0
- package/dist/adapters/db/db-oauth.d.ts +3 -0
- package/dist/adapters/db/db-oauth.js +26 -0
- package/dist/adapters/db/db-prompts.d.ts +46 -0
- package/dist/adapters/db/db-prompts.js +144 -0
- package/dist/adapters/db/db.d.ts +6 -0
- package/dist/adapters/db/db.js +1687 -0
- package/dist/adapters/db/db.types.d.ts +16 -0
- package/dist/adapters/db/db.types.js +1 -0
- package/dist/adapters/document-converter/document-converter.d.ts +2 -0
- package/dist/adapters/document-converter/document-converter.js +26 -0
- package/dist/adapters/document-converter/document-converter.types.d.ts +17 -0
- package/dist/adapters/document-converter/document-converter.types.js +1 -0
- package/dist/adapters/flow-runtime/flow-runtime.d.ts +3 -0
- package/dist/adapters/flow-runtime/flow-runtime.js +22 -0
- package/dist/adapters/flow-runtime/flow-runtime.types.d.ts +19 -0
- package/dist/adapters/flow-runtime/flow-runtime.types.js +1 -0
- package/dist/adapters/index-queue/index-queue.d.ts +10 -0
- package/dist/adapters/index-queue/index-queue.js +12 -0
- package/dist/adapters/index-queue/index-queue.types.d.ts +11 -0
- package/dist/adapters/index-queue/index-queue.types.js +1 -0
- package/dist/adapters/json-schema/json-schema.d.ts +2 -0
- package/dist/adapters/json-schema/json-schema.js +77 -0
- package/dist/adapters/openid/openid.d.ts +5 -0
- package/dist/adapters/openid/openid.js +301 -0
- package/dist/adapters/portal-tokens/portal-tokens.d.ts +8 -0
- package/dist/adapters/portal-tokens/portal-tokens.js +79 -0
- package/dist/adapters/remote-tools/remote-tools.d.ts +5 -0
- package/dist/adapters/remote-tools/remote-tools.js +129 -0
- package/dist/adapters/semantic-index/semantic-index.d.ts +2 -0
- package/dist/adapters/semantic-index/semantic-index.js +139 -0
- package/dist/adapters/semantic-index/semantic-index.types.d.ts +56 -0
- package/dist/adapters/semantic-index/semantic-index.types.js +1 -0
- package/dist/adapters/session-cookie/session-cookie.d.ts +5 -0
- package/dist/adapters/session-cookie/session-cookie.js +87 -0
- package/dist/adapters/tool-source-policy/tool-source-policy.d.ts +1 -0
- package/dist/adapters/tool-source-policy/tool-source-policy.js +22 -0
- package/dist/audit/audit.d.ts +2 -0
- package/dist/audit/audit.js +87 -0
- package/dist/audit/audit.types.d.ts +23 -0
- package/dist/audit/audit.types.js +1 -0
- package/dist/auth/auth.d.ts +2 -0
- package/dist/auth/auth.js +284 -0
- package/dist/auth/auth.types.d.ts +108 -0
- package/dist/auth/auth.types.js +1 -0
- package/dist/boards/boards.d.ts +44 -0
- package/dist/boards/boards.js +447 -0
- package/dist/boards/boards.types.d.ts +117 -0
- package/dist/boards/boards.types.js +1 -0
- package/dist/build/build.d.ts +2 -0
- package/dist/build/build.js +192 -0
- package/dist/build/build.types.d.ts +17 -0
- package/dist/build/build.types.js +1 -0
- package/dist/bundle/bundle.d.ts +4 -0
- package/dist/bundle/bundle.js +1194 -0
- package/dist/bundle/bundle.types.d.ts +33 -0
- package/dist/bundle/bundle.types.js +1 -0
- package/dist/cli/cli.d.ts +4 -0
- package/dist/cli/cli.js +262 -0
- package/dist/cli/cli.types.d.ts +14 -0
- package/dist/cli/cli.types.js +1 -0
- package/dist/contract/audit.d.ts +50 -0
- package/dist/contract/audit.js +72 -0
- package/dist/contract/board.d.ts +150 -0
- package/dist/contract/board.js +262 -0
- package/dist/contract/bundle.d.ts +147 -0
- package/dist/contract/bundle.js +139 -0
- package/dist/contract/contract.d.ts +112 -0
- package/dist/contract/contract.js +143 -0
- package/dist/contract/feed.d.ts +126 -0
- package/dist/contract/feed.js +149 -0
- package/dist/contract/flow-run.d.ts +346 -0
- package/dist/contract/flow-run.js +194 -0
- package/dist/contract/flow.d.ts +1057 -0
- package/dist/contract/flow.js +552 -0
- package/dist/contract/node.d.ts +551 -0
- package/dist/contract/node.js +456 -0
- package/dist/contract/share.d.ts +216 -0
- package/dist/contract/share.js +134 -0
- package/dist/contract/table.d.ts +171 -0
- package/dist/contract/table.js +117 -0
- package/dist/contract/tool.d.ts +122 -0
- package/dist/contract/tool.js +172 -0
- package/dist/feed/feed.d.ts +2 -0
- package/dist/feed/feed.js +77 -0
- package/dist/feed/feed.types.d.ts +23 -0
- package/dist/feed/feed.types.js +1 -0
- package/dist/flows/flows.d.ts +41 -0
- package/dist/flows/flows.js +2216 -0
- package/dist/flows/flows.types.d.ts +339 -0
- package/dist/flows/flows.types.js +1 -0
- package/dist/http/http.d.ts +9 -0
- package/dist/http/http.js +874 -0
- package/dist/http/http.types.d.ts +22 -0
- package/dist/http/http.types.js +1 -0
- package/dist/indexing/indexing.d.ts +6 -0
- package/dist/indexing/indexing.js +239 -0
- package/dist/indexing/indexing.types.d.ts +11 -0
- package/dist/indexing/indexing.types.js +1 -0
- package/dist/intel/intel.d.ts +3 -0
- package/dist/intel/intel.js +194 -0
- package/dist/intel/intel.types.d.ts +24 -0
- package/dist/intel/intel.types.js +1 -0
- package/dist/mcp/mcp.d.ts +2 -0
- package/dist/mcp/mcp.js +1292 -0
- package/dist/mcp/mcp.types.d.ts +25 -0
- package/dist/mcp/mcp.types.js +1 -0
- package/dist/nodes/document-links/document-links.d.ts +20 -0
- package/dist/nodes/document-links/document-links.js +57 -0
- package/dist/nodes/nodes.d.ts +2 -0
- package/dist/nodes/nodes.js +1667 -0
- package/dist/nodes/nodes.types.d.ts +511 -0
- package/dist/nodes/nodes.types.js +1 -0
- package/dist/prepare/prepare.d.ts +4 -0
- package/dist/prepare/prepare.js +16 -0
- package/dist/prepare/prepare.types.d.ts +9 -0
- package/dist/prepare/prepare.types.js +1 -0
- package/dist/prompts/prompts.d.ts +2 -0
- package/dist/prompts/prompts.js +65 -0
- package/dist/prompts/prompts.types.d.ts +71 -0
- package/dist/prompts/prompts.types.js +1 -0
- package/dist/shared/callers/callers.d.ts +28 -0
- package/dist/shared/callers/callers.js +30 -0
- package/dist/shared/csv/csv.d.ts +13 -0
- package/dist/shared/csv/csv.js +85 -0
- package/dist/shared/document-text/document-text.d.ts +21 -0
- package/dist/shared/document-text/document-text.js +31 -0
- package/dist/shared/gate-authorization/gate-authorization.d.ts +5 -0
- package/dist/shared/gate-authorization/gate-authorization.js +26 -0
- package/dist/shared/grant-expiry/grant-expiry.d.ts +19 -0
- package/dist/shared/grant-expiry/grant-expiry.js +26 -0
- package/dist/shared/intel-error/intel-error.d.ts +22 -0
- package/dist/shared/intel-error/intel-error.js +27 -0
- package/dist/shared/plain-title/plain-title.d.ts +16 -0
- package/dist/shared/plain-title/plain-title.js +45 -0
- package/dist/shared/problem-details/problem-details.d.ts +30 -0
- package/dist/shared/problem-details/problem-details.js +18 -0
- package/dist/shared/report-unexpected-error/report-unexpected-error.d.ts +1 -0
- package/dist/shared/report-unexpected-error/report-unexpected-error.js +37 -0
- package/dist/shared/safe-return-path/safe-return-path.d.ts +2 -0
- package/dist/shared/safe-return-path/safe-return-path.js +11 -0
- package/dist/shared/sha256/sha256.d.ts +2 -0
- package/dist/shared/sha256/sha256.js +14 -0
- package/dist/tools/tool-servers/tool-servers.d.ts +46 -0
- package/dist/tools/tool-servers/tool-servers.js +177 -0
- package/dist/tools/tools.d.ts +2 -0
- package/dist/tools/tools.js +207 -0
- package/dist/tools/tools.types.d.ts +56 -0
- package/dist/tools/tools.types.js +1 -0
- package/examples/branding/favicon.svg +5 -0
- package/examples/branding/logo.svg +5 -0
- package/examples/branding/theme.css +16 -0
- package/examples/dev.vars.example +7 -0
- package/examples/intel.json +9 -0
- package/migrations/0000_intel_foundation.sql +203 -0
- package/migrations/0001_portal_native_tools.sql +21 -0
- package/migrations/0002_flows_in_the_knowledge_tree.sql +34 -0
- package/migrations/0003_folder_permissions.sql +211 -0
- package/migrations/0004_subflow_runs.sql +14 -0
- package/migrations/0005_flow_node_cleanup.sql +28 -0
- package/migrations/0005_tables_in_the_knowledge_tree.sql +68 -0
- package/migrations/0006_links_are_written_in_the_text.sql +20 -0
- package/migrations/0007_no_node_waits.sql +69 -0
- package/migrations/0008_three_layers.sql +130 -0
- package/migrations/0009_no_context_policy.sql +48 -0
- package/migrations/0010_no_run_waits_a_year.sql +27 -0
- package/migrations/0011_one_name_for_the_tree.sql +53 -0
- package/migrations/0012_table_snapshots.sql +29 -0
- package/migrations/0017_a_vector_per_card.sql +38 -0
- package/migrations/0018_no_context_policy_at_last.sql +97 -0
- package/migrations/0019_one_name_for_the_grants.sql +52 -0
- package/migrations/0020_cascade_purge_replay.sql +11 -0
- package/migrations/0021_a_flow_carries_its_own_grant.sql +44 -0
- package/migrations/0022_a_cursor_over_the_journal.sql +14 -0
- package/migrations/0023_a_board_and_its_tasks.sql +116 -0
- package/migrations/0024_the_archive_is_a_column.sql +33 -0
- package/migrations/0025_archiving_takes_the_subtree.sql +29 -0
- package/migrations/0026_one_feed_over_two_kinds.sql +23 -0
- package/migrations/0027_the_runs_of_every_flow.sql +27 -0
- package/migrations/0028_a_prompt_name_over_two_kinds.sql +70 -0
- package/package.json +118 -0
- package/src/contract/CLAUDE.md +152 -0
- package/src/contract/README.md +102 -0
- package/src/contract/audit.ts +85 -0
- package/src/contract/board.ts +306 -0
- package/src/contract/bundle.ts +157 -0
- package/src/contract/contract.ts +161 -0
- package/src/contract/feed.ts +165 -0
- package/src/contract/flow-run.ts +241 -0
- package/src/contract/flow.ts +675 -0
- package/src/contract/node.ts +583 -0
- package/src/contract/share.ts +196 -0
- package/src/contract/table.ts +178 -0
- package/src/contract/tool.ts +202 -0
- package/ui/README.md +110 -0
- package/ui/components.json +21 -0
- package/ui/index.html +13 -0
- package/ui/package.json +11 -0
- package/ui/scripts/lint-tokens.mjs +187 -0
- package/ui/src/access-summary/access-summary.tsx +385 -0
- package/ui/src/app/action-slot/action-slot.tsx +27 -0
- package/ui/src/app/app-sidebar/app-sidebar.tsx +71 -0
- package/ui/src/app/app-tree/app-tree.tsx +1175 -0
- package/ui/src/app/app.tsx +87 -0
- package/ui/src/app/header-search/header-search.tsx +294 -0
- package/ui/src/app/reindex-dialog/reindex-dialog.tsx +79 -0
- package/ui/src/app/settings-dialog/settings-dialog.tsx +135 -0
- package/ui/src/app/sidebar-preferences/sidebar-preferences.ts +68 -0
- package/ui/src/app/sidebar-preferences/sidebar-preferences.types.ts +15 -0
- package/ui/src/app/sidebar-resize-handle/sidebar-resize-handle.tsx +86 -0
- package/ui/src/app/tree-expansion/tree-expansion.ts +107 -0
- package/ui/src/app/tree-expansion/tree-expansion.types.ts +31 -0
- package/ui/src/app/tree-move/tree-move.tsx +427 -0
- package/ui/src/app/tree-reveal/tree-reveal.ts +64 -0
- package/ui/src/app/tree-reveal/tree-reveal.types.ts +16 -0
- package/ui/src/app/user-footer/user-footer.tsx +188 -0
- package/ui/src/app/view-menu/view-menu.tsx +115 -0
- package/ui/src/app-root/app-root.tsx +109 -0
- package/ui/src/app-root/app-root.types.ts +27 -0
- package/ui/src/archive/archive.tsx +417 -0
- package/ui/src/attachment-detail/attachment-detail.ts +52 -0
- package/ui/src/attachment-viewer/attachment-viewer.tsx +166 -0
- package/ui/src/blocknote-view/blocknote-view.tsx +30 -0
- package/ui/src/board/board-assignee/board-assignee-picker.tsx +132 -0
- package/ui/src/board/board-assignee/board-assignee.ts +48 -0
- package/ui/src/board/board-assignee/board-assignee.tsx +75 -0
- package/ui/src/board/board-chip/board-chip.tsx +46 -0
- package/ui/src/board/board-crumbs/board-crumbs.ts +56 -0
- package/ui/src/board/board-crumbs/board-crumbs.tsx +111 -0
- package/ui/src/board/board-data/board-data.ts +195 -0
- package/ui/src/board/board-data/board-data.types.ts +38 -0
- package/ui/src/board/board-dates/board-dates.ts +40 -0
- package/ui/src/board/board-dates/board-dates.tsx +105 -0
- package/ui/src/board/board-kanban/board-kanban.ts +162 -0
- package/ui/src/board/board-kanban/board-kanban.tsx +680 -0
- package/ui/src/board/board-open-task/board-open-task.ts +32 -0
- package/ui/src/board/board-panel/board-panel.tsx +259 -0
- package/ui/src/board/board-settings/board-settings.tsx +226 -0
- package/ui/src/board/board-status/board-status.tsx +60 -0
- package/ui/src/board/board-stripes/board-stripes.ts +128 -0
- package/ui/src/board/board-table/board-table.ts +53 -0
- package/ui/src/board/board-table/board-table.tsx +610 -0
- package/ui/src/board/board-task/board-task.ts +108 -0
- package/ui/src/board/board-task/board-task.tsx +335 -0
- package/ui/src/board/board-title-row/board-title-row.tsx +66 -0
- package/ui/src/branding/branding.tsx +17 -0
- package/ui/src/branding/custom-logo.ts +1 -0
- package/ui/src/branding/favicon.default.svg +5 -0
- package/ui/src/branding/favicon.svg +5 -0
- package/ui/src/components/ui/avatar.tsx +39 -0
- package/ui/src/components/ui/button.tsx +64 -0
- package/ui/src/components/ui/collapsible.tsx +20 -0
- package/ui/src/components/ui/command.tsx +160 -0
- package/ui/src/components/ui/dialog.tsx +143 -0
- package/ui/src/components/ui/dropdown-menu.tsx +187 -0
- package/ui/src/components/ui/input.tsx +21 -0
- package/ui/src/components/ui/popover.tsx +41 -0
- package/ui/src/components/ui/select.tsx +163 -0
- package/ui/src/components/ui/separator.tsx +26 -0
- package/ui/src/components/ui/sheet.tsx +136 -0
- package/ui/src/components/ui/sidebar.tsx +693 -0
- package/ui/src/components/ui/skeleton.tsx +13 -0
- package/ui/src/components/ui/switch.tsx +25 -0
- package/ui/src/components/ui/table.tsx +82 -0
- package/ui/src/components/ui/tabs.tsx +52 -0
- package/ui/src/components/ui/tooltip.tsx +51 -0
- package/ui/src/data/intel-data-provider/intel-data-provider.ts +685 -0
- package/ui/src/data/intel-data-provider/intel-data-provider.types.ts +266 -0
- package/ui/src/data/query-client.ts +18 -0
- package/ui/src/data/request-refusal/refusal-notice.tsx +36 -0
- package/ui/src/data/request-refusal/request-refusal.ts +51 -0
- package/ui/src/data/sign-in/sign-in.ts +97 -0
- package/ui/src/data/sign-in/sign-in.types.ts +15 -0
- package/ui/src/document-link/document-link.tsx +114 -0
- package/ui/src/document-markdown/document-markdown.ts +195 -0
- package/ui/src/editor-schema/editor-schema.ts +23 -0
- package/ui/src/entry-picker/entry-picker.tsx +238 -0
- package/ui/src/feed/feed.tsx +344 -0
- package/ui/src/file-preview/file-preview-view.tsx +496 -0
- package/ui/src/file-preview/file-preview.tsx +28 -0
- package/ui/src/file-preview/pdf-file-preview.tsx +5 -0
- package/ui/src/file-preview/presentation-file-preview.tsx +21 -0
- package/ui/src/file-preview/spreadsheet-file-preview.tsx +5 -0
- package/ui/src/file-preview/word-file-preview.tsx +5 -0
- package/ui/src/flow-runs/flow-runs.tsx +238 -0
- package/ui/src/flows/flows.tsx +1646 -0
- package/ui/src/flows/node-icon/node-icon.ts +34 -0
- package/ui/src/flows/node-palette/node-palette.tsx +214 -0
- package/ui/src/flows/node-palette/node-palette.types.ts +15 -0
- package/ui/src/folder-contents/folder-contents.tsx +321 -0
- package/ui/src/folder-index/folder-index.ts +55 -0
- package/ui/src/frontmatter/frontmatter.tsx +193 -0
- package/ui/src/graph-pane/graph-pane.tsx +53 -0
- package/ui/src/hooks/use-mobile.ts +19 -0
- package/ui/src/i18n/custom.json +4 -0
- package/ui/src/i18n/de.json +609 -0
- package/ui/src/i18n/en.json +609 -0
- package/ui/src/i18n/es.json +609 -0
- package/ui/src/i18n/i18n-context.tsx +65 -0
- package/ui/src/i18n/i18n-languages/i18n-languages.ts +83 -0
- package/ui/src/i18n/i18n.ts +32 -0
- package/ui/src/i18n/i18n.types.ts +49 -0
- package/ui/src/kind-icon.ts +97 -0
- package/ui/src/lib/utils.ts +6 -0
- package/ui/src/main.tsx +68 -0
- package/ui/src/modal/modal.tsx +53 -0
- package/ui/src/node-details/node-details.tsx +545 -0
- package/ui/src/node-editor/node-editor.tsx +304 -0
- package/ui/src/node-graph/graph-notice.tsx +21 -0
- package/ui/src/node-graph/node-graph.ts +214 -0
- package/ui/src/node-graph/node-graph.tsx +295 -0
- package/ui/src/node-import/node-import.tsx +418 -0
- package/ui/src/node-save-error.ts +46 -0
- package/ui/src/node-source/node-source.tsx +128 -0
- package/ui/src/node-table/node-table.tsx +107 -0
- package/ui/src/nodes/nodes.tsx +240 -0
- package/ui/src/rename-resource/rename-resource.ts +80 -0
- package/ui/src/resolved-names/resolved-names.tsx +67 -0
- package/ui/src/resource-error.ts +33 -0
- package/ui/src/resource-menu/resource-menu.tsx +1156 -0
- package/ui/src/router/router-context.ts +6 -0
- package/ui/src/router/router.tsx +67 -0
- package/ui/src/router/router.types.ts +8 -0
- package/ui/src/router/selection-search.ts +88 -0
- package/ui/src/save-button/save-button.tsx +94 -0
- package/ui/src/section-hint/section-hint.tsx +40 -0
- package/ui/src/sign-in-refused/sign-in-refused.tsx +35 -0
- package/ui/src/styles.css +189 -0
- package/ui/src/table-columns/table-columns.tsx +379 -0
- package/ui/src/theme/custom.css +1 -0
- package/ui/src/theme/theme-context.tsx +89 -0
- package/ui/src/theme/theme.ts +70 -0
- package/ui/src/time/relative-time.tsx +41 -0
- package/ui/src/time/time-context.tsx +78 -0
- package/ui/src/time/time.ts +165 -0
- package/ui/src/title-row/title-row.tsx +185 -0
- package/ui/src/tools/tools.tsx +546 -0
- package/ui/src/user-name/user-name.ts +61 -0
- package/ui/src/verbatim/verbatim.tsx +68 -0
- package/ui/tsconfig.json +17 -0
- package/ui/vite.config.ts +129 -0
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BoardGetInput,
|
|
3
|
+
BoardTaskCreateInput,
|
|
4
|
+
BoardTaskUpdateInput,
|
|
5
|
+
BoardUpdateInput,
|
|
6
|
+
BoardView,
|
|
7
|
+
DirectoryPersonList,
|
|
8
|
+
} from "@contract/board.ts";
|
|
9
|
+
import { BundleImportResult } from "@contract/bundle.ts";
|
|
10
|
+
import { type NamedOrCounted, ProblemDetails, SessionUser } from "@contract/contract.ts";
|
|
11
|
+
import { FeedListResponse } from "@contract/feed.ts";
|
|
12
|
+
import {
|
|
13
|
+
ArchiveFlowInput,
|
|
14
|
+
CreateFlowInput,
|
|
15
|
+
Flow,
|
|
16
|
+
FlowDocument,
|
|
17
|
+
FlowList,
|
|
18
|
+
FlowPublishPreview,
|
|
19
|
+
FlowRequirements,
|
|
20
|
+
FlowValidation,
|
|
21
|
+
FlowVersionList,
|
|
22
|
+
ListFlowsInput,
|
|
23
|
+
PreviewFlowPublishInput,
|
|
24
|
+
PublishFlowInput,
|
|
25
|
+
PurgeFlowInput,
|
|
26
|
+
PurgeFlowResult,
|
|
27
|
+
RelationGraph,
|
|
28
|
+
RelationGraphInput,
|
|
29
|
+
SaveFlowVersionInput,
|
|
30
|
+
UpdateFlowInput,
|
|
31
|
+
} from "@contract/flow.ts";
|
|
32
|
+
import {
|
|
33
|
+
CompleteFlowRunStepInput,
|
|
34
|
+
FlowRunHistory,
|
|
35
|
+
FlowRunList,
|
|
36
|
+
FlowRunStep,
|
|
37
|
+
ListFlowRunsInput,
|
|
38
|
+
StartFlowRunInput,
|
|
39
|
+
} from "@contract/flow-run.ts";
|
|
40
|
+
import {
|
|
41
|
+
ArchiveNodeInput,
|
|
42
|
+
CreateNodeInput,
|
|
43
|
+
ListNodesInput,
|
|
44
|
+
Node,
|
|
45
|
+
NodeDocument,
|
|
46
|
+
NodeGraph,
|
|
47
|
+
NodeLinkList,
|
|
48
|
+
NodeList,
|
|
49
|
+
NodeTable,
|
|
50
|
+
NodeVersionList,
|
|
51
|
+
PurgeNodeInput,
|
|
52
|
+
PurgeNodePreview,
|
|
53
|
+
PurgeNodePreviewInput,
|
|
54
|
+
PurgeNodeResult,
|
|
55
|
+
ReindexResult,
|
|
56
|
+
ResolveNodeLinksInput,
|
|
57
|
+
ResolveNodeLinksResult,
|
|
58
|
+
SaveAttachmentBytesInput,
|
|
59
|
+
SaveAttachmentInput,
|
|
60
|
+
SaveNodeVersionInput,
|
|
61
|
+
SearchInput,
|
|
62
|
+
SearchResult,
|
|
63
|
+
UpdateNodeInput,
|
|
64
|
+
} from "@contract/node.ts";
|
|
65
|
+
import {
|
|
66
|
+
ResourceAccessList,
|
|
67
|
+
ResourceGrantList,
|
|
68
|
+
RevokeFlowGrantInput,
|
|
69
|
+
RevokeGrantInput,
|
|
70
|
+
RevokeGrantResult,
|
|
71
|
+
ShareFlowInput,
|
|
72
|
+
ShareInput,
|
|
73
|
+
ShareResult,
|
|
74
|
+
} from "@contract/share.ts";
|
|
75
|
+
import {
|
|
76
|
+
AppendTableRowsInput,
|
|
77
|
+
AppendTableRowsResult,
|
|
78
|
+
DefineTableInput,
|
|
79
|
+
RedefineTableInput,
|
|
80
|
+
} from "@contract/table.ts";
|
|
81
|
+
import { ToolCatalog, ToolServerCatalog } from "@contract/tool.ts";
|
|
82
|
+
import type { z } from "zod";
|
|
83
|
+
import { createBrowserSignIn } from "@/data/sign-in/sign-in.ts";
|
|
84
|
+
import type { IntelDataProvider, TreeEntry } from "./intel-data-provider.types.ts";
|
|
85
|
+
|
|
86
|
+
// ⚠️ The refusal's `code`, not only its prose. A view that has to tell four different refusals
|
|
87
|
+
// apart — "you may not write there", "that is not a folder", "that would be a cycle", "someone
|
|
88
|
+
// else changed it" — cannot do so from `detail`, which is a sentence the server is free to
|
|
89
|
+
// reword. The code is the contract (`ProblemDetails.code`); the message stays what it was.
|
|
90
|
+
// One request's own deadline, beside everything `fetch` takes. An upload needs minutes where a
|
|
91
|
+
// read needs seconds, and the difference belongs to the call rather than to the whole provider.
|
|
92
|
+
type IntelRequestInit = RequestInit & { timeoutMs?: number };
|
|
93
|
+
|
|
94
|
+
export class IntelRequestError extends Error {
|
|
95
|
+
/**
|
|
96
|
+
* ⚠️ `callers` is the structured half of the two refusals that name flows — `folder_execute_in_use`
|
|
97
|
+
* (#448) and `flow_in_use_by_flow` (#593): the flows this reader may see, by name, and a count of
|
|
98
|
+
* the ones they may not. It is `null` for every other failure, and a screen that reads it has to
|
|
99
|
+
* say which code it read it for — the field is only meaningful beside its own.
|
|
100
|
+
*
|
|
101
|
+
* `message` still holds the server's finished English sentence. It is no longer what the dialog
|
|
102
|
+
* shows; it is what a log or a report has when nobody translated anything.
|
|
103
|
+
*/
|
|
104
|
+
constructor(
|
|
105
|
+
public readonly status: number,
|
|
106
|
+
public readonly code: string | null,
|
|
107
|
+
message: string,
|
|
108
|
+
public readonly callers: NamedOrCounted | null = null,
|
|
109
|
+
) {
|
|
110
|
+
super(message);
|
|
111
|
+
this.name = "IntelRequestError";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Attachment uploads and downloads share this budget, so it is generous rather than snappy.
|
|
116
|
+
const RequestTimeoutMs = 60_000;
|
|
117
|
+
|
|
118
|
+
// ⚠️ A file upload gets its own, and it is a consequence of the 50 MB limit rather than a taste for
|
|
119
|
+
// patience (#821): 50 MB inside a minute needs about 7 Mbit/s of upstream, which a home connection
|
|
120
|
+
// does not have. On the old 15 MB limit that arithmetic never came up.
|
|
121
|
+
const UploadTimeoutMs = 300_000;
|
|
122
|
+
|
|
123
|
+
// The Worker serves the login route, so the path belongs to the data layer rather than to any view.
|
|
124
|
+
export function loginPath(returnTo?: string): string {
|
|
125
|
+
return returnTo ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}` : "/auth/login";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* One flow as one row of the tree. Two levels show flows — the contents of a folder, and what an
|
|
130
|
+
* expanded flow calls — and they are two lists of the same rows, so they are built here once. Two
|
|
131
|
+
* copies of this would keep returning something plausible and slowly stop agreeing on what a flow
|
|
132
|
+
* row is (#30).
|
|
133
|
+
*/
|
|
134
|
+
// ⚠️ `openable` defaults to false here — more precisely: unknown. Whoever knows the level sets it
|
|
135
|
+
// (`listTreeChildren`); whoever only builds a single row does not know and therefore claims the
|
|
136
|
+
// more reserved of the two. An arrow that is wrongly missing costs a click on the row; one that
|
|
137
|
+
// is wrongly there costs trust (#59).
|
|
138
|
+
export function flowEntry(flow: Flow, openable = false): TreeEntry {
|
|
139
|
+
return { type: "flow", id: flow.id, title: flow.title, kind: "flow", openable, flow };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function createIntelDataProvider(
|
|
143
|
+
deps: {
|
|
144
|
+
fetch?: typeof fetch;
|
|
145
|
+
baseUrl?: string;
|
|
146
|
+
onUnauthorized?(): void;
|
|
147
|
+
navigate?(url: string): void;
|
|
148
|
+
} = {},
|
|
149
|
+
): IntelDataProvider {
|
|
150
|
+
const doFetch = deps.fetch ?? fetch;
|
|
151
|
+
const baseUrl = deps.baseUrl?.replace(/\/$/, "") ?? "";
|
|
152
|
+
const navigate =
|
|
153
|
+
deps.navigate ??
|
|
154
|
+
((url: string) => {
|
|
155
|
+
if (typeof window !== "undefined") window.location.assign(url);
|
|
156
|
+
});
|
|
157
|
+
// ⚠️ The default goes through `createBrowserSignIn` rather than redirecting straight away, and it
|
|
158
|
+
// has to: this is the code path that produced the endless reload (#118). A caller that supplies
|
|
159
|
+
// its own `onUnauthorized` takes the guard on as well — `main.tsx` does, because it also has to
|
|
160
|
+
// put something on the screen once the redirect is refused.
|
|
161
|
+
const unauthorized =
|
|
162
|
+
deps.onUnauthorized ??
|
|
163
|
+
(() => {
|
|
164
|
+
if (typeof window !== "undefined") createBrowserSignIn(loginPath).attempt();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
async function response(path: string, init: IntelRequestInit = {}): Promise<Response> {
|
|
168
|
+
// Without a deadline a stalled request would leave the view in a permanent loading state, and a
|
|
169
|
+
// caller-supplied signal (query cancellation) has to keep working alongside it.
|
|
170
|
+
const { timeoutMs = RequestTimeoutMs, ...rest } = init;
|
|
171
|
+
const deadline = AbortSignal.timeout(timeoutMs);
|
|
172
|
+
const result = await doFetch(`${baseUrl}/api/v1${path}`, {
|
|
173
|
+
...rest,
|
|
174
|
+
credentials: "include",
|
|
175
|
+
signal: rest.signal ? AbortSignal.any([rest.signal, deadline]) : deadline,
|
|
176
|
+
headers: {
|
|
177
|
+
...(rest.body === undefined ? {} : { "content-type": "application/json" }),
|
|
178
|
+
...rest.headers,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
if (result.status === 401) unauthorized();
|
|
182
|
+
if (!result.ok) {
|
|
183
|
+
const parsed = ProblemDetails.safeParse(
|
|
184
|
+
await result
|
|
185
|
+
.clone()
|
|
186
|
+
.json()
|
|
187
|
+
.catch(() => null),
|
|
188
|
+
);
|
|
189
|
+
throw new IntelRequestError(
|
|
190
|
+
result.status,
|
|
191
|
+
parsed.success ? (parsed.data.code ?? null) : null,
|
|
192
|
+
parsed.success
|
|
193
|
+
? (parsed.data.detail ?? parsed.data.title)
|
|
194
|
+
: `Intel responded with ${result.status}`,
|
|
195
|
+
parsed.success ? (parsed.data.callers ?? null) : null,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function request<T>(
|
|
202
|
+
path: string,
|
|
203
|
+
schema: z.ZodType<T>,
|
|
204
|
+
init: IntelRequestInit = {},
|
|
205
|
+
): Promise<T> {
|
|
206
|
+
return schema.parse(await (await response(path, init)).json());
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function listFlows(input: ListFlowsInput = {}): Promise<z.infer<typeof FlowList>> {
|
|
210
|
+
const query = ListFlowsInput.parse(input);
|
|
211
|
+
// The parameter is only sent when the caller asked for one folder. Sending an empty one for
|
|
212
|
+
// "everything" would ask the server for the root instead.
|
|
213
|
+
const params = new URLSearchParams(
|
|
214
|
+
query.parentId === undefined ? {} : { parentId: query.parentId ?? "" },
|
|
215
|
+
);
|
|
216
|
+
// Same rule as `parentId`: only the asked-for case is sent. The default is the server's, and a
|
|
217
|
+
// provider that spells it out anyway would have to be changed whenever the server's is.
|
|
218
|
+
if (query.includeArchived) params.set("includeArchived", "true");
|
|
219
|
+
if (query.archivedOnly) params.set("archivedOnly", "true");
|
|
220
|
+
const search = params.toString();
|
|
221
|
+
return await request(`/flows${search ? `?${search}` : ""}`, FlowList);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function listNodes(input: Partial<ListNodesInput> = {}): Promise<z.infer<typeof NodeList>> {
|
|
225
|
+
const query = ListNodesInput.parse(input);
|
|
226
|
+
const params = new URLSearchParams({ includeArchived: String(query.includeArchived) });
|
|
227
|
+
if (query.parentId !== null) params.set("parentId", query.parentId);
|
|
228
|
+
// Only the asked-for case travels: `archivedOnly` overrides the folder on the server, so
|
|
229
|
+
// sending it as `false` on every tree read would be noise on the one request it never applies
|
|
230
|
+
// to (#113).
|
|
231
|
+
if (query.archivedOnly) params.set("archivedOnly", "true");
|
|
232
|
+
return await request(`/nodes?${params}`, NodeList);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
async getSession() {
|
|
237
|
+
return await request("/session", SessionUser);
|
|
238
|
+
},
|
|
239
|
+
async reindexNodes() {
|
|
240
|
+
return await request("/nodes/reindex", ReindexResult, { method: "POST", body: "{}" });
|
|
241
|
+
},
|
|
242
|
+
listNodes,
|
|
243
|
+
async listTreeChildren(parentId) {
|
|
244
|
+
// Both sides of one folder, asked for in parallel and merged here rather than on the server:
|
|
245
|
+
// the folder is shared, the two records are not, and no endpoint may return a row that is a
|
|
246
|
+
// bit of both (ADR-0004).
|
|
247
|
+
const [nodes, flows] = await Promise.all([listNodes({ parentId }), listFlows({ parentId })]);
|
|
248
|
+
// ⚠️ Both sides say which of their rows have something to expand (#59) — for THIS reader.
|
|
249
|
+
// The tree therefore knows it while drawing, without preloading the level below: that would
|
|
250
|
+
// be one load per row instead of per folder.
|
|
251
|
+
const openable = new Set([...nodes.withChildren, ...flows.withCalls]);
|
|
252
|
+
const entries: TreeEntry[] = [
|
|
253
|
+
...nodes.items.map((node) => ({
|
|
254
|
+
type: "node" as const,
|
|
255
|
+
id: node.id,
|
|
256
|
+
title: node.title,
|
|
257
|
+
kind: node.kind,
|
|
258
|
+
openable: openable.has(node.id),
|
|
259
|
+
node,
|
|
260
|
+
})),
|
|
261
|
+
...flows.items.map((flow) => flowEntry(flow, openable.has(flow.id))),
|
|
262
|
+
];
|
|
263
|
+
// Folders first, then everything else by title: a document and a flow sit side by side, and
|
|
264
|
+
// the icon is what tells them apart.
|
|
265
|
+
return entries.sort(
|
|
266
|
+
(left, right) =>
|
|
267
|
+
Number(right.kind === "folder") - Number(left.kind === "folder") ||
|
|
268
|
+
left.title.localeCompare(right.title) ||
|
|
269
|
+
left.id.localeCompare(right.id),
|
|
270
|
+
);
|
|
271
|
+
},
|
|
272
|
+
async getNode(nodeId) {
|
|
273
|
+
return await request(`/nodes/${encodeURIComponent(nodeId)}`, NodeDocument);
|
|
274
|
+
},
|
|
275
|
+
async createNodes(input) {
|
|
276
|
+
return await request("/nodes", Node, {
|
|
277
|
+
method: "POST",
|
|
278
|
+
body: JSON.stringify(CreateNodeInput.parse(input)),
|
|
279
|
+
});
|
|
280
|
+
},
|
|
281
|
+
async getNodeGraph(limit = 250) {
|
|
282
|
+
return await request(`/nodes/graph?limit=${encodeURIComponent(limit)}`, NodeGraph);
|
|
283
|
+
},
|
|
284
|
+
async listNodeLinks(nodeId) {
|
|
285
|
+
return await request(`/nodes/${encodeURIComponent(nodeId)}/links`, NodeLinkList);
|
|
286
|
+
},
|
|
287
|
+
// ⚠️ POST, not GET. The identifiers of the documents a text links to belong in a body: a
|
|
288
|
+
// query string of them would end up in logs and referrers.
|
|
289
|
+
async resolveNodeLinks(input) {
|
|
290
|
+
return await request("/nodes/links/resolve", ResolveNodeLinksResult, {
|
|
291
|
+
method: "POST",
|
|
292
|
+
body: JSON.stringify(ResolveNodeLinksInput.parse(input)),
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
async saveNode(input) {
|
|
296
|
+
const parsed = SaveNodeVersionInput.parse(input);
|
|
297
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}/versions`, NodeDocument, {
|
|
298
|
+
method: "POST",
|
|
299
|
+
body: JSON.stringify(parsed),
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
async saveNodeAttachment(input) {
|
|
303
|
+
const parsed = SaveAttachmentInput.parse(input);
|
|
304
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}/attachment`, NodeDocument, {
|
|
305
|
+
method: "POST",
|
|
306
|
+
body: JSON.stringify(parsed),
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
// The body IS the file, so everything about it travels in the headers — the same reading the
|
|
310
|
+
// server does, and the same shape the bundle import beside it already had (#821).
|
|
311
|
+
async saveNodeAttachmentBytes(input) {
|
|
312
|
+
const parsed = SaveAttachmentBytesInput.parse({
|
|
313
|
+
nodeId: input.nodeId,
|
|
314
|
+
baseVersionId: input.baseVersionId,
|
|
315
|
+
mediaType: input.file.type || "application/octet-stream",
|
|
316
|
+
size: input.file.size,
|
|
317
|
+
idempotencyKey: input.idempotencyKey,
|
|
318
|
+
});
|
|
319
|
+
return await request(
|
|
320
|
+
`/nodes/${encodeURIComponent(parsed.nodeId)}/attachment/bytes`,
|
|
321
|
+
NodeDocument,
|
|
322
|
+
{
|
|
323
|
+
method: "POST",
|
|
324
|
+
body: input.file,
|
|
325
|
+
timeoutMs: UploadTimeoutMs,
|
|
326
|
+
headers: {
|
|
327
|
+
"content-type": parsed.mediaType,
|
|
328
|
+
"idempotency-key": parsed.idempotencyKey,
|
|
329
|
+
// `none` rather than an absent header: a first upload says so, and a caller who merely
|
|
330
|
+
// forgot the field is refused instead of overwriting the newest version.
|
|
331
|
+
"intel-base-version-id": parsed.baseVersionId ?? "none",
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
);
|
|
335
|
+
},
|
|
336
|
+
async getNodeAttachment(nodeId) {
|
|
337
|
+
return await (await response(`/nodes/${encodeURIComponent(nodeId)}/attachment`)).blob();
|
|
338
|
+
},
|
|
339
|
+
async exportNodeBundle(nodeId) {
|
|
340
|
+
const path =
|
|
341
|
+
nodeId === null ? "/nodes/export" : `/nodes/${encodeURIComponent(nodeId)}/export`;
|
|
342
|
+
return await (await response(path)).blob();
|
|
343
|
+
},
|
|
344
|
+
async exportFlowBundle(flowId) {
|
|
345
|
+
return await (await response(`/flows/${encodeURIComponent(flowId)}/export`)).blob();
|
|
346
|
+
},
|
|
347
|
+
// The body IS the zip, so the idempotency key travels as a header — the same reading the
|
|
348
|
+
// server does (#137).
|
|
349
|
+
async importNodeBundle(input) {
|
|
350
|
+
const path =
|
|
351
|
+
input.nodeId === null
|
|
352
|
+
? "/nodes/import"
|
|
353
|
+
: `/nodes/${encodeURIComponent(input.nodeId)}/import`;
|
|
354
|
+
return await request(path, BundleImportResult, {
|
|
355
|
+
method: "POST",
|
|
356
|
+
body: input.zip,
|
|
357
|
+
headers: {
|
|
358
|
+
"content-type": "application/zip",
|
|
359
|
+
"idempotency-key": input.idempotencyKey,
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
},
|
|
363
|
+
async getNodeTable(nodeId) {
|
|
364
|
+
return await request(`/nodes/${encodeURIComponent(nodeId)}/table`, NodeTable);
|
|
365
|
+
},
|
|
366
|
+
async defineTable(input) {
|
|
367
|
+
const parsed = DefineTableInput.parse(input);
|
|
368
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}/table`, NodeTable, {
|
|
369
|
+
method: "POST",
|
|
370
|
+
body: JSON.stringify(parsed),
|
|
371
|
+
});
|
|
372
|
+
},
|
|
373
|
+
async appendTableRows(input) {
|
|
374
|
+
const parsed = AppendTableRowsInput.parse(input);
|
|
375
|
+
return await request(
|
|
376
|
+
`/nodes/${encodeURIComponent(parsed.nodeId)}/table/rows`,
|
|
377
|
+
AppendTableRowsResult,
|
|
378
|
+
{ method: "POST", body: JSON.stringify(parsed) },
|
|
379
|
+
);
|
|
380
|
+
},
|
|
381
|
+
// ⚠️ `PATCH`, where the two writes above are `POST`. The route is the same address as the
|
|
382
|
+
// header itself, and this changes it — `POST /nodes/:id/table` is the one that WRITES a header
|
|
383
|
+
// and refuses on a table that already has one.
|
|
384
|
+
async redefineTable(input) {
|
|
385
|
+
const parsed = RedefineTableInput.parse(input);
|
|
386
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}/table`, NodeTable, {
|
|
387
|
+
method: "PATCH",
|
|
388
|
+
body: JSON.stringify(parsed),
|
|
389
|
+
});
|
|
390
|
+
},
|
|
391
|
+
async listNodeVersions(nodeId) {
|
|
392
|
+
return await request(`/nodes/${encodeURIComponent(nodeId)}/versions`, NodeVersionList);
|
|
393
|
+
},
|
|
394
|
+
async getBoard(input) {
|
|
395
|
+
const parsed = BoardGetInput.parse(input);
|
|
396
|
+
// ⚠️ Only the filters the caller actually named travel. Sending an empty `status` would ask
|
|
397
|
+
// the server for the column called "" rather than for every column — the same rule the flow
|
|
398
|
+
// list follows above, and for the same reason.
|
|
399
|
+
const params = new URLSearchParams();
|
|
400
|
+
if (parsed.status !== undefined) params.set("status", parsed.status);
|
|
401
|
+
if (parsed.assigneeId !== undefined) params.set("assigneeId", parsed.assigneeId);
|
|
402
|
+
if (parsed.dueBefore !== undefined) params.set("dueBefore", parsed.dueBefore);
|
|
403
|
+
if (parsed.dependsOn !== undefined) params.set("dependsOn", parsed.dependsOn);
|
|
404
|
+
if (parsed.includeArchived) params.set("includeArchived", "true");
|
|
405
|
+
const query = params.toString();
|
|
406
|
+
return await request(
|
|
407
|
+
`/boards/${encodeURIComponent(parsed.boardId)}${query === "" ? "" : `?${query}`}`,
|
|
408
|
+
BoardView,
|
|
409
|
+
);
|
|
410
|
+
},
|
|
411
|
+
async updateBoard(input) {
|
|
412
|
+
const parsed = BoardUpdateInput.parse(input);
|
|
413
|
+
return await request(`/boards/${encodeURIComponent(parsed.boardId)}`, BoardView, {
|
|
414
|
+
method: "PATCH",
|
|
415
|
+
body: JSON.stringify(parsed),
|
|
416
|
+
});
|
|
417
|
+
},
|
|
418
|
+
async createBoardTask(input) {
|
|
419
|
+
const parsed = BoardTaskCreateInput.parse(input);
|
|
420
|
+
return await request(`/boards/${encodeURIComponent(parsed.boardId)}/tasks`, BoardView, {
|
|
421
|
+
method: "POST",
|
|
422
|
+
body: JSON.stringify(parsed),
|
|
423
|
+
});
|
|
424
|
+
},
|
|
425
|
+
// ⚠️ The board id is in the path although the call identifies the card by its own id: the route
|
|
426
|
+
// mirrors the tool name segment for segment (`board_task_update`), and a card that could be
|
|
427
|
+
// addressed without its board would invite a caller to move one between boards — which the
|
|
428
|
+
// service refuses on purpose (#377).
|
|
429
|
+
async updateBoardTask(boardId, input) {
|
|
430
|
+
const parsed = BoardTaskUpdateInput.parse(input);
|
|
431
|
+
return await request(
|
|
432
|
+
`/boards/${encodeURIComponent(boardId)}/tasks/${encodeURIComponent(parsed.taskId)}`,
|
|
433
|
+
BoardView,
|
|
434
|
+
{ method: "PATCH", body: JSON.stringify(parsed) },
|
|
435
|
+
);
|
|
436
|
+
},
|
|
437
|
+
async searchBoardAssignees(boardId, query) {
|
|
438
|
+
return await request(
|
|
439
|
+
`/boards/${encodeURIComponent(boardId)}/assignees?q=${encodeURIComponent(query)}`,
|
|
440
|
+
DirectoryPersonList,
|
|
441
|
+
);
|
|
442
|
+
},
|
|
443
|
+
// ⚠️ A POST although it reads, mirroring the route: a hundred identifiers in a query string
|
|
444
|
+
// land in proxy logs and in browser history, and they would hit the length limit long before
|
|
445
|
+
// the hundredth.
|
|
446
|
+
async resolveNames(ids) {
|
|
447
|
+
return await request("/directory/resolve", DirectoryPersonList, {
|
|
448
|
+
method: "POST",
|
|
449
|
+
body: JSON.stringify({ ids }),
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
async updateNode(input) {
|
|
453
|
+
const parsed = UpdateNodeInput.parse(input);
|
|
454
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}`, Node, {
|
|
455
|
+
method: "PATCH",
|
|
456
|
+
body: JSON.stringify(parsed),
|
|
457
|
+
});
|
|
458
|
+
},
|
|
459
|
+
async archiveNode(input) {
|
|
460
|
+
const parsed = ArchiveNodeInput.parse(input);
|
|
461
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}/archive`, Node, {
|
|
462
|
+
method: "POST",
|
|
463
|
+
body: JSON.stringify(parsed),
|
|
464
|
+
});
|
|
465
|
+
},
|
|
466
|
+
async purgeNode(input) {
|
|
467
|
+
const parsed = PurgeNodeInput.parse(input);
|
|
468
|
+
return await request(`/nodes/${encodeURIComponent(parsed.nodeId)}`, PurgeNodeResult, {
|
|
469
|
+
method: "DELETE",
|
|
470
|
+
body: JSON.stringify(parsed),
|
|
471
|
+
});
|
|
472
|
+
},
|
|
473
|
+
async previewNodePurge(input) {
|
|
474
|
+
const parsed = PurgeNodePreviewInput.parse(input);
|
|
475
|
+
return await request(
|
|
476
|
+
`/nodes/${encodeURIComponent(parsed.nodeId)}/purge-preview`,
|
|
477
|
+
PurgeNodePreview,
|
|
478
|
+
);
|
|
479
|
+
},
|
|
480
|
+
async purgeFlow(input) {
|
|
481
|
+
const parsed = PurgeFlowInput.parse(input);
|
|
482
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}`, PurgeFlowResult, {
|
|
483
|
+
method: "DELETE",
|
|
484
|
+
});
|
|
485
|
+
},
|
|
486
|
+
async searchNodes(input) {
|
|
487
|
+
return await request("/nodes/search", SearchResult, {
|
|
488
|
+
method: "POST",
|
|
489
|
+
body: JSON.stringify(SearchInput.parse(input)),
|
|
490
|
+
});
|
|
491
|
+
},
|
|
492
|
+
async listGrants(resourceId) {
|
|
493
|
+
return await request(`/nodes/${encodeURIComponent(resourceId)}/grants`, ResourceGrantList);
|
|
494
|
+
},
|
|
495
|
+
async listEffectiveAccess(resourceId) {
|
|
496
|
+
return await request(
|
|
497
|
+
`/nodes/${encodeURIComponent(resourceId)}/effective-access`,
|
|
498
|
+
ResourceAccessList,
|
|
499
|
+
);
|
|
500
|
+
},
|
|
501
|
+
async shareNode(input) {
|
|
502
|
+
const parsed = ShareInput.parse(input);
|
|
503
|
+
return await request(`/nodes/${encodeURIComponent(parsed.resourceId)}/grants`, ShareResult, {
|
|
504
|
+
method: "POST",
|
|
505
|
+
body: JSON.stringify(parsed),
|
|
506
|
+
});
|
|
507
|
+
},
|
|
508
|
+
async revokeGrant(input) {
|
|
509
|
+
const parsed = RevokeGrantInput.parse(input);
|
|
510
|
+
return await request(
|
|
511
|
+
`/nodes/${encodeURIComponent(parsed.resourceId)}/grants/${encodeURIComponent(parsed.grantId)}/revoke`,
|
|
512
|
+
RevokeGrantResult,
|
|
513
|
+
{ method: "POST", body: JSON.stringify(parsed) },
|
|
514
|
+
);
|
|
515
|
+
},
|
|
516
|
+
async listFlowGrants(flowId) {
|
|
517
|
+
return await request(`/flows/${encodeURIComponent(flowId)}/grants`, ResourceGrantList);
|
|
518
|
+
},
|
|
519
|
+
async listEffectiveFlowAccess(flowId) {
|
|
520
|
+
return await request(
|
|
521
|
+
`/flows/${encodeURIComponent(flowId)}/effective-access`,
|
|
522
|
+
ResourceAccessList,
|
|
523
|
+
);
|
|
524
|
+
},
|
|
525
|
+
async shareFlow(input) {
|
|
526
|
+
const parsed = ShareFlowInput.parse(input);
|
|
527
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}/grants`, ShareResult, {
|
|
528
|
+
method: "POST",
|
|
529
|
+
body: JSON.stringify(parsed),
|
|
530
|
+
});
|
|
531
|
+
},
|
|
532
|
+
async revokeFlowGrant(input) {
|
|
533
|
+
const parsed = RevokeFlowGrantInput.parse(input);
|
|
534
|
+
return await request(
|
|
535
|
+
`/flows/${encodeURIComponent(parsed.flowId)}/grants/${encodeURIComponent(parsed.grantId)}/revoke`,
|
|
536
|
+
RevokeGrantResult,
|
|
537
|
+
{ method: "POST", body: JSON.stringify(parsed) },
|
|
538
|
+
);
|
|
539
|
+
},
|
|
540
|
+
listFlows,
|
|
541
|
+
async getFlow(flowId) {
|
|
542
|
+
return await request(`/flows/${encodeURIComponent(flowId)}`, FlowDocument);
|
|
543
|
+
},
|
|
544
|
+
async validateFlow(flowId) {
|
|
545
|
+
return await request(`/flows/${encodeURIComponent(flowId)}/validation`, FlowValidation);
|
|
546
|
+
},
|
|
547
|
+
async listFlowCalls(flowId) {
|
|
548
|
+
return await request(`/flows/${encodeURIComponent(flowId)}/calls`, FlowList);
|
|
549
|
+
},
|
|
550
|
+
async getRelationGraph(scope, limit) {
|
|
551
|
+
const parsed = RelationGraphInput.parse({
|
|
552
|
+
scope,
|
|
553
|
+
...(limit === undefined ? {} : { limit }),
|
|
554
|
+
});
|
|
555
|
+
const params = new URLSearchParams({
|
|
556
|
+
of: parsed.scope.of,
|
|
557
|
+
limit: String(parsed.limit),
|
|
558
|
+
// A folder scope without an ID is the root of the shared tree, and an absent parameter is
|
|
559
|
+
// how that is said — the same distinction `/flows?parentId=` makes.
|
|
560
|
+
...(parsed.scope.of === "flow"
|
|
561
|
+
? { flowId: parsed.scope.flowId }
|
|
562
|
+
: parsed.scope.folderId
|
|
563
|
+
? { folderId: parsed.scope.folderId }
|
|
564
|
+
: {}),
|
|
565
|
+
});
|
|
566
|
+
return await request(`/flows/graph?${params}`, RelationGraph);
|
|
567
|
+
},
|
|
568
|
+
async getFlowRequirements(flowId) {
|
|
569
|
+
return await request(`/flows/${encodeURIComponent(flowId)}/requirements`, FlowRequirements);
|
|
570
|
+
},
|
|
571
|
+
async createFlow(input) {
|
|
572
|
+
return await request("/flows", Flow, {
|
|
573
|
+
method: "POST",
|
|
574
|
+
body: JSON.stringify(CreateFlowInput.parse(input)),
|
|
575
|
+
});
|
|
576
|
+
},
|
|
577
|
+
async updateFlow(input) {
|
|
578
|
+
const parsed = UpdateFlowInput.parse(input);
|
|
579
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}`, Flow, {
|
|
580
|
+
method: "PATCH",
|
|
581
|
+
body: JSON.stringify(parsed),
|
|
582
|
+
});
|
|
583
|
+
},
|
|
584
|
+
async archiveFlow(input) {
|
|
585
|
+
const parsed = ArchiveFlowInput.parse(input);
|
|
586
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}/archive`, Flow, {
|
|
587
|
+
method: "POST",
|
|
588
|
+
body: JSON.stringify(parsed),
|
|
589
|
+
});
|
|
590
|
+
},
|
|
591
|
+
async saveFlow(input) {
|
|
592
|
+
const parsed = SaveFlowVersionInput.parse(input);
|
|
593
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}/versions`, FlowDocument, {
|
|
594
|
+
method: "POST",
|
|
595
|
+
body: JSON.stringify(parsed),
|
|
596
|
+
});
|
|
597
|
+
},
|
|
598
|
+
async listFlowVersions(flowId) {
|
|
599
|
+
return await request(`/flows/${encodeURIComponent(flowId)}/versions`, FlowVersionList);
|
|
600
|
+
},
|
|
601
|
+
async previewFlowPublish(input) {
|
|
602
|
+
const parsed = PreviewFlowPublishInput.parse(input);
|
|
603
|
+
return await request(
|
|
604
|
+
`/flows/${encodeURIComponent(parsed.flowId)}/versions/${encodeURIComponent(parsed.versionId)}/publish-preview`,
|
|
605
|
+
FlowPublishPreview,
|
|
606
|
+
);
|
|
607
|
+
},
|
|
608
|
+
async publishFlow(input) {
|
|
609
|
+
const parsed = PublishFlowInput.parse(input);
|
|
610
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}/publish`, Flow, {
|
|
611
|
+
method: "POST",
|
|
612
|
+
body: JSON.stringify(parsed),
|
|
613
|
+
});
|
|
614
|
+
},
|
|
615
|
+
async startFlow(input) {
|
|
616
|
+
const parsed = StartFlowRunInput.parse(input);
|
|
617
|
+
return await request(`/flows/${encodeURIComponent(parsed.flowId)}/runs`, FlowRunStep, {
|
|
618
|
+
method: "POST",
|
|
619
|
+
body: JSON.stringify(parsed),
|
|
620
|
+
});
|
|
621
|
+
},
|
|
622
|
+
async listFeed(input) {
|
|
623
|
+
// Only what was asked for travels: an empty `actor` or `before` in the query string is not
|
|
624
|
+
// the same as leaving it out, and the contract refuses the empty string.
|
|
625
|
+
const params = new URLSearchParams({ limit: String(input.limit) });
|
|
626
|
+
if (input.actor) params.set("actor", input.actor);
|
|
627
|
+
if (input.before) params.set("before", input.before);
|
|
628
|
+
return await request(`/feed?${params}`, FeedListResponse);
|
|
629
|
+
},
|
|
630
|
+
async listFlowRuns(input) {
|
|
631
|
+
const parsed = ListFlowRunsInput.parse(input);
|
|
632
|
+
// Only what was actually asked for travels. `failedOnly` is the parameter's presence rather
|
|
633
|
+
// than a value, which is the same shape the server reads it back with.
|
|
634
|
+
const params = new URLSearchParams({ limit: String(parsed.limit) });
|
|
635
|
+
if (parsed.failedOnly) params.set("failedOnly", "");
|
|
636
|
+
if (parsed.cursor) params.set("cursor", parsed.cursor);
|
|
637
|
+
// Two addresses, one answer (#774): under the flow when one is named, at the root when the
|
|
638
|
+
// question is "did anything run at all".
|
|
639
|
+
return await request(
|
|
640
|
+
parsed.flowId === null
|
|
641
|
+
? `/flow-runs?${params}`
|
|
642
|
+
: `/flows/${encodeURIComponent(parsed.flowId)}/runs?${params}`,
|
|
643
|
+
FlowRunList,
|
|
644
|
+
);
|
|
645
|
+
},
|
|
646
|
+
async getFlowRun(runId) {
|
|
647
|
+
return await request(`/flow-runs/${encodeURIComponent(runId)}`, FlowRunStep);
|
|
648
|
+
},
|
|
649
|
+
async getFlowRunSteps(runId) {
|
|
650
|
+
return await request(`/flow-runs/${encodeURIComponent(runId)}/steps`, FlowRunHistory);
|
|
651
|
+
},
|
|
652
|
+
async completeFlowStep(input) {
|
|
653
|
+
const parsed = CompleteFlowRunStepInput.parse(input);
|
|
654
|
+
return await request(
|
|
655
|
+
`/flow-runs/${encodeURIComponent(parsed.runId)}/steps/complete`,
|
|
656
|
+
FlowRunStep,
|
|
657
|
+
{
|
|
658
|
+
method: "POST",
|
|
659
|
+
body: JSON.stringify(parsed),
|
|
660
|
+
},
|
|
661
|
+
);
|
|
662
|
+
},
|
|
663
|
+
async listTools() {
|
|
664
|
+
return await request("/tools", ToolCatalog);
|
|
665
|
+
},
|
|
666
|
+
// The servers behind the same live list (D30). Its own call rather than a grouping done in the
|
|
667
|
+
// browser: which server a tool belongs to is the portal's answer, and a UI that split tool
|
|
668
|
+
// names would be guessing where the namespace ends.
|
|
669
|
+
async listToolServers() {
|
|
670
|
+
return await request("/tools/servers", ToolServerCatalog);
|
|
671
|
+
},
|
|
672
|
+
// The Worker serves the connect route, so this navigation belongs to the data layer for the
|
|
673
|
+
// same reason `loginPath` does. `silent=1` is what makes it a redirect nobody has to watch.
|
|
674
|
+
startPortalSignIn(returnTo = "/tools") {
|
|
675
|
+
navigate(`${baseUrl}/auth/connect?returnTo=${encodeURIComponent(returnTo)}&silent=1`);
|
|
676
|
+
},
|
|
677
|
+
async logout() {
|
|
678
|
+
const response = await doFetch(`${baseUrl}/auth/logout`, {
|
|
679
|
+
method: "POST",
|
|
680
|
+
credentials: "include",
|
|
681
|
+
});
|
|
682
|
+
if (!response.ok) throw new Error(`Intel responded with ${response.status}`);
|
|
683
|
+
},
|
|
684
|
+
};
|
|
685
|
+
}
|