devchain-cli 0.21.0 → 0.22.1
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 +1 -0
- package/dist/drizzle/0073_integration_storage.sql +27 -0
- package/dist/drizzle/0074_black_drax.sql +7 -0
- package/dist/drizzle/0075_misty_franklin_richards.sql +37 -0
- package/dist/drizzle/0076_epic_time_accounting.sql +48 -0
- package/dist/drizzle/meta/0073_snapshot.json +6247 -0
- package/dist/drizzle/meta/0074_snapshot.json +6299 -0
- package/dist/drizzle/meta/0075_snapshot.json +6563 -0
- package/dist/drizzle/meta/0076_snapshot.json +6913 -0
- package/dist/drizzle/meta/_journal.json +28 -0
- package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.d.ts +27 -1
- package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.d.ts.map +1 -1
- package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.js +15 -0
- package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.js.map +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +52 -52
- package/dist/node_modules/@devchain/shared/tsconfig.tsbuildinfo +1 -1
- package/dist/server/app.main.module.js +4 -0
- package/dist/server/app.main.module.js.map +1 -1
- package/dist/server/app.normal.module.js +2 -0
- package/dist/server/app.normal.module.js.map +1 -1
- package/dist/server/common/config/container-scope.d.ts +11 -0
- package/dist/server/common/config/container-scope.js +37 -0
- package/dist/server/common/config/container-scope.js.map +1 -1
- package/dist/server/common/constants/terminal.d.ts +1 -0
- package/dist/server/common/constants/terminal.js +2 -1
- package/dist/server/common/constants/terminal.js.map +1 -1
- package/dist/server/common/filters/http-exception.filter.js +3 -4
- package/dist/server/common/filters/http-exception.filter.js.map +1 -1
- package/dist/server/common/guards/integration-admission.guard.d.ts +4 -0
- package/dist/server/common/guards/integration-admission.guard.js +22 -0
- package/dist/server/common/guards/integration-admission.guard.js.map +1 -0
- package/dist/server/common/test/app-bootstrap.helper.js +1 -1
- package/dist/server/common/test/app-bootstrap.helper.js.map +1 -1
- package/dist/server/modules/agent-message-delivery/agent-message-delivery.service.js +4 -0
- package/dist/server/modules/agent-message-delivery/agent-message-delivery.service.js.map +1 -1
- package/dist/server/modules/cloud/cloud.module.js +5 -1
- package/dist/server/modules/cloud/cloud.module.js.map +1 -1
- package/dist/server/modules/cloud/services/cloud-egress-bridge.service.d.ts +3 -1
- package/dist/server/modules/cloud/services/cloud-egress-bridge.service.js +19 -3
- package/dist/server/modules/cloud/services/cloud-egress-bridge.service.js.map +1 -1
- package/dist/server/modules/cloud/services/egress-queue.service.d.ts +2 -0
- package/dist/server/modules/cloud/services/egress-queue.service.js +35 -17
- package/dist/server/modules/cloud/services/egress-queue.service.js.map +1 -1
- package/dist/server/modules/cloud/services/event-mapper.service.d.ts +1 -0
- package/dist/server/modules/cloud/services/event-mapper.service.js.map +1 -1
- package/dist/server/modules/cloud/services/notification-recipient-resolver.service.d.ts +10 -0
- package/dist/server/modules/cloud/services/notification-recipient-resolver.service.js +55 -0
- package/dist/server/modules/cloud/services/notification-recipient-resolver.service.js.map +1 -0
- package/dist/server/modules/cloud-tunnel/services/mobile-rpc-contract.generated.d.ts +31 -5
- package/dist/server/modules/cloud-tunnel/services/mobile-rpc-contract.generated.js +15 -0
- package/dist/server/modules/cloud-tunnel/services/mobile-rpc-contract.generated.js.map +1 -1
- package/dist/server/modules/cloud-tunnel/services/mobile-rpc-workspace-access.service.js +5 -2
- package/dist/server/modules/cloud-tunnel/services/mobile-rpc-workspace-access.service.js.map +1 -1
- package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.d.ts +1 -0
- package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.js +8 -0
- package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.js.map +1 -1
- package/dist/server/modules/core/controllers/runtime.controller.d.ts +1 -0
- package/dist/server/modules/core/controllers/runtime.controller.js +2 -0
- package/dist/server/modules/core/controllers/runtime.controller.js.map +1 -1
- package/dist/server/modules/e2ee/services/e2ee-device-store.service.d.ts +2 -0
- package/dist/server/modules/e2ee/services/e2ee-device-store.service.js +26 -0
- package/dist/server/modules/e2ee/services/e2ee-device-store.service.js.map +1 -1
- package/dist/server/modules/e2ee/services/e2ee-trust.service.d.ts +5 -0
- package/dist/server/modules/e2ee/services/e2ee-trust.service.js +11 -0
- package/dist/server/modules/e2ee/services/e2ee-trust.service.js.map +1 -1
- package/dist/server/modules/e2ee/services/paired-device-workspace-access.service.d.ts +1 -0
- package/dist/server/modules/e2ee/services/paired-device-workspace-access.service.js +4 -0
- package/dist/server/modules/e2ee/services/paired-device-workspace-access.service.js.map +1 -1
- package/dist/server/modules/epic-time/controllers/epic-time.controller.d.ts +8 -0
- package/dist/server/modules/epic-time/controllers/epic-time.controller.js +70 -0
- package/dist/server/modules/epic-time/controllers/epic-time.controller.js.map +1 -0
- package/dist/server/modules/epic-time/epic-time.module.d.ts +2 -0
- package/dist/server/modules/epic-time/epic-time.module.js +28 -0
- package/dist/server/modules/epic-time/epic-time.module.js.map +1 -0
- package/dist/server/modules/epic-time/models/epic-time.models.d.ts +26 -0
- package/dist/server/modules/epic-time/models/epic-time.models.js +3 -0
- package/dist/server/modules/epic-time/models/epic-time.models.js.map +1 -0
- package/dist/server/modules/epic-time/services/agent-time-accounting.service.d.ts +32 -0
- package/dist/server/modules/epic-time/services/agent-time-accounting.service.js +159 -0
- package/dist/server/modules/epic-time/services/agent-time-accounting.service.js.map +1 -0
- package/dist/server/modules/epic-time/services/epic-time.service.d.ts +15 -0
- package/dist/server/modules/epic-time/services/epic-time.service.js +224 -0
- package/dist/server/modules/epic-time/services/epic-time.service.js.map +1 -0
- package/dist/server/modules/epic-time/services/epic-time.store.d.ts +75 -0
- package/dist/server/modules/epic-time/services/epic-time.store.js +453 -0
- package/dist/server/modules/epic-time/services/epic-time.store.js.map +1 -0
- package/dist/server/modules/epics/controllers/epics.controller.d.ts +10 -0
- package/dist/server/modules/epics/controllers/epics.controller.js +92 -0
- package/dist/server/modules/epics/controllers/epics.controller.js.map +1 -1
- package/dist/server/modules/epics/services/epics.service.d.ts +32 -2
- package/dist/server/modules/epics/services/epics.service.js +243 -96
- package/dist/server/modules/epics/services/epics.service.js.map +1 -1
- package/dist/server/modules/events/catalog/agent.created.d.ts +4 -4
- package/dist/server/modules/events/catalog/agent.deleted.d.ts +2 -2
- package/dist/server/modules/events/catalog/agent.message.sent.d.ts +40 -40
- package/dist/server/modules/events/catalog/broadcast-registry.js +1 -0
- package/dist/server/modules/events/catalog/broadcast-registry.js.map +1 -1
- package/dist/server/modules/events/catalog/claude.hooks.ask_user_question.pending.d.ts +4 -4
- package/dist/server/modules/events/catalog/claude.hooks.session.started.d.ts +10 -10
- package/dist/server/modules/events/catalog/epic.comment.created.d.ts +6 -6
- package/dist/server/modules/events/catalog/epic.created.d.ts +8 -8
- package/dist/server/modules/events/catalog/epic.deleted.d.ts +4 -4
- package/dist/server/modules/events/catalog/epic.updated.d.ts +68 -42
- package/dist/server/modules/events/catalog/epic.updated.js +5 -0
- package/dist/server/modules/events/catalog/epic.updated.js.map +1 -1
- package/dist/server/modules/events/catalog/guest.registered.d.ts +2 -2
- package/dist/server/modules/events/catalog/guest.unregistered.d.ts +4 -4
- package/dist/server/modules/events/catalog/index.d.ts +370 -228
- package/dist/server/modules/events/catalog/index.js +11 -1
- package/dist/server/modules/events/catalog/index.js.map +1 -1
- package/dist/server/modules/events/catalog/integration.connection.created.d.ts +30 -0
- package/dist/server/modules/events/catalog/integration.connection.created.js +17 -0
- package/dist/server/modules/events/catalog/integration.connection.created.js.map +1 -0
- package/dist/server/modules/events/catalog/integration.connection.deleted.d.ts +27 -0
- package/dist/server/modules/events/catalog/integration.connection.deleted.js +16 -0
- package/dist/server/modules/events/catalog/integration.connection.deleted.js.map +1 -0
- package/dist/server/modules/events/catalog/integration.connection.updated.d.ts +39 -0
- package/dist/server/modules/events/catalog/integration.connection.updated.js +20 -0
- package/dist/server/modules/events/catalog/integration.connection.updated.js.map +1 -0
- package/dist/server/modules/events/catalog/review.comment.created.d.ts +16 -16
- package/dist/server/modules/events/catalog/review.comment.deleted.d.ts +2 -2
- package/dist/server/modules/events/catalog/review.comment.resolved.d.ts +2 -2
- package/dist/server/modules/events/catalog/review.comment.updated.d.ts +4 -4
- package/dist/server/modules/events/catalog/review.created.d.ts +12 -12
- package/dist/server/modules/events/catalog/review.updated.d.ts +22 -22
- package/dist/server/modules/events/catalog/scheduled-epic.executed.d.ts +12 -12
- package/dist/server/modules/events/catalog/session.human-prompt-state-changed.d.ts +77 -0
- package/dist/server/modules/events/catalog/session.human-prompt-state-changed.js +25 -0
- package/dist/server/modules/events/catalog/session.human-prompt-state-changed.js.map +1 -0
- package/dist/server/modules/events/catalog/session.provider-session-id.discovered.d.ts +2 -2
- package/dist/server/modules/events/catalog/session.recommendation.d.ts +4 -4
- package/dist/server/modules/events/catalog/session.restored.d.ts +2 -2
- package/dist/server/modules/events/catalog/session.started.d.ts +2 -2
- package/dist/server/modules/events/catalog/session.starting.d.ts +2 -2
- package/dist/server/modules/events/catalog/session.stopped.d.ts +2 -2
- package/dist/server/modules/events/catalog/session.transcript.discovered.d.ts +4 -4
- package/dist/server/modules/events/catalog/team.config.updated.d.ts +6 -6
- package/dist/server/modules/events/catalog/team.member.added.d.ts +2 -2
- package/dist/server/modules/events/catalog/team.member.removed.d.ts +2 -2
- package/dist/server/modules/events/catalog/terminal.watcher.triggered.d.ts +4 -4
- package/dist/server/modules/events/events-core.module.js +8 -1
- package/dist/server/modules/events/events-core.module.js.map +1 -1
- package/dist/server/modules/events/events-infra.module.js +6 -1
- package/dist/server/modules/events/events-infra.module.js.map +1 -1
- package/dist/server/modules/events/services/committed-event.store.d.ts +23 -0
- package/dist/server/modules/events/services/committed-event.store.js +169 -0
- package/dist/server/modules/events/services/committed-event.store.js.map +1 -0
- package/dist/server/modules/events/services/durable-event-dispatcher.service.d.ts +16 -0
- package/dist/server/modules/events/services/durable-event-dispatcher.service.js +97 -0
- package/dist/server/modules/events/services/durable-event-dispatcher.service.js.map +1 -0
- package/dist/server/modules/events/services/durable-event-registry.service.d.ts +25 -0
- package/dist/server/modules/events/services/durable-event-registry.service.js +59 -0
- package/dist/server/modules/events/services/durable-event-registry.service.js.map +1 -0
- package/dist/server/modules/events/services/event-log.service.d.ts +6 -1
- package/dist/server/modules/events/services/event-log.service.js +32 -18
- package/dist/server/modules/events/services/event-log.service.js.map +1 -1
- package/dist/server/modules/events/services/events.service.d.ts +11 -1
- package/dist/server/modules/events/services/events.service.js +50 -7
- package/dist/server/modules/events/services/events.service.js.map +1 -1
- package/dist/server/modules/external-integrations/adapters/clickup-external-task.provider.d.ts +97 -0
- package/dist/server/modules/external-integrations/adapters/clickup-external-task.provider.js +1404 -0
- package/dist/server/modules/external-integrations/adapters/clickup-external-task.provider.js.map +1 -0
- package/dist/server/modules/external-integrations/adapters/jira-external-task.provider.d.ts +113 -0
- package/dist/server/modules/external-integrations/adapters/jira-external-task.provider.js +1790 -0
- package/dist/server/modules/external-integrations/adapters/jira-external-task.provider.js.map +1 -0
- package/dist/server/modules/external-integrations/adapters/rich/clickup-comment-converter.d.ts +10 -0
- package/dist/server/modules/external-integrations/adapters/rich/clickup-comment-converter.js +97 -0
- package/dist/server/modules/external-integrations/adapters/rich/clickup-comment-converter.js.map +1 -0
- package/dist/server/modules/external-integrations/adapters/rich/clickup-markdown-converter.d.ts +16 -0
- package/dist/server/modules/external-integrations/adapters/rich/clickup-markdown-converter.js +386 -0
- package/dist/server/modules/external-integrations/adapters/rich/clickup-markdown-converter.js.map +1 -0
- package/dist/server/modules/external-integrations/adapters/rich/jira-adf-converter.d.ts +5 -0
- package/dist/server/modules/external-integrations/adapters/rich/jira-adf-converter.js +229 -0
- package/dist/server/modules/external-integrations/adapters/rich/jira-adf-converter.js.map +1 -0
- package/dist/server/modules/external-integrations/adapters/vendor-shared.d.ts +42 -0
- package/dist/server/modules/external-integrations/adapters/vendor-shared.js +182 -0
- package/dist/server/modules/external-integrations/adapters/vendor-shared.js.map +1 -0
- package/dist/server/modules/external-integrations/connections/integration-connections.controller.d.ts +11 -0
- package/dist/server/modules/external-integrations/connections/integration-connections.controller.js +121 -0
- package/dist/server/modules/external-integrations/connections/integration-connections.controller.js.map +1 -0
- package/dist/server/modules/external-integrations/connections/integration-connections.service.d.ts +46 -0
- package/dist/server/modules/external-integrations/connections/integration-connections.service.js +193 -0
- package/dist/server/modules/external-integrations/connections/integration-connections.service.js.map +1 -0
- package/dist/server/modules/external-integrations/connections/managed-subtask-sync.controller.d.ts +8 -0
- package/dist/server/modules/external-integrations/connections/managed-subtask-sync.controller.js +73 -0
- package/dist/server/modules/external-integrations/connections/managed-subtask-sync.controller.js.map +1 -0
- package/dist/server/modules/external-integrations/errors/external-provider.errors.d.ts +23 -0
- package/dist/server/modules/external-integrations/errors/external-provider.errors.js +105 -0
- package/dist/server/modules/external-integrations/errors/external-provider.errors.js.map +1 -0
- package/dist/server/modules/external-integrations/external-integrations.module.d.ts +2 -0
- package/dist/server/modules/external-integrations/external-integrations.module.js +72 -0
- package/dist/server/modules/external-integrations/external-integrations.module.js.map +1 -0
- package/dist/server/modules/external-integrations/external-task-provider.registry.d.ts +12 -0
- package/dist/server/modules/external-integrations/external-task-provider.registry.js +65 -0
- package/dist/server/modules/external-integrations/external-task-provider.registry.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-comment-lookup-token.d.ts +12 -0
- package/dist/server/modules/external-integrations/models/external-comment-lookup-token.js +49 -0
- package/dist/server/modules/external-integrations/models/external-comment-lookup-token.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-edit-session.models.d.ts +94 -0
- package/dist/server/modules/external-integrations/models/external-edit-session.models.js +10 -0
- package/dist/server/modules/external-integrations/models/external-edit-session.models.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-provider.models.d.ts +341 -0
- package/dist/server/modules/external-integrations/models/external-provider.models.js +21 -0
- package/dist/server/modules/external-integrations/models/external-provider.models.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-rich-capabilities.d.ts +6 -0
- package/dist/server/modules/external-integrations/models/external-rich-capabilities.js +9 -0
- package/dist/server/modules/external-integrations/models/external-rich-capabilities.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-rich-document.d.ts +59 -0
- package/dist/server/modules/external-integrations/models/external-rich-document.js +233 -0
- package/dist/server/modules/external-integrations/models/external-rich-document.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-task-source.d.ts +4 -0
- package/dist/server/modules/external-integrations/models/external-task-source.js +71 -0
- package/dist/server/modules/external-integrations/models/external-task-source.js.map +1 -0
- package/dist/server/modules/external-integrations/models/external-time-mutation.models.d.ts +74 -0
- package/dist/server/modules/external-integrations/models/external-time-mutation.models.js +19 -0
- package/dist/server/modules/external-integrations/models/external-time-mutation.models.js.map +1 -0
- package/dist/server/modules/external-integrations/my-work/external-edit-session.service.d.ts +57 -0
- package/dist/server/modules/external-integrations/my-work/external-edit-session.service.js +776 -0
- package/dist/server/modules/external-integrations/my-work/external-edit-session.service.js.map +1 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.controller.d.ts +37 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.controller.js +626 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.controller.js.map +1 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.openapi.d.ts +29 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.openapi.js +847 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.openapi.js.map +1 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.service.d.ts +34 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.service.js +330 -0
- package/dist/server/modules/external-integrations/my-work/external-my-work.service.js.map +1 -0
- package/dist/server/modules/external-integrations/my-work/external-time-mutation.service.d.ts +27 -0
- package/dist/server/modules/external-integrations/my-work/external-time-mutation.service.js +412 -0
- package/dist/server/modules/external-integrations/my-work/external-time-mutation.service.js.map +1 -0
- package/dist/server/modules/external-integrations/ports/external-task-provider.d.ts +13 -0
- package/dist/server/modules/external-integrations/ports/external-task-provider.js +5 -0
- package/dist/server/modules/external-integrations/ports/external-task-provider.js.map +1 -0
- package/dist/server/modules/external-integrations/request-validation.d.ts +2 -0
- package/dist/server/modules/external-integrations/request-validation.js +14 -0
- package/dist/server/modules/external-integrations/request-validation.js.map +1 -0
- package/dist/server/modules/external-integrations/sessions/external-edit-session.store.d.ts +59 -0
- package/dist/server/modules/external-integrations/sessions/external-edit-session.store.js +329 -0
- package/dist/server/modules/external-integrations/sessions/external-edit-session.store.js.map +1 -0
- package/dist/server/modules/external-integrations/sessions/external-time-mutation.store.d.ts +44 -0
- package/dist/server/modules/external-integrations/sessions/external-time-mutation.store.js +171 -0
- package/dist/server/modules/external-integrations/sessions/external-time-mutation.store.js.map +1 -0
- package/dist/server/modules/external-integrations/sessions/provider-operation-gate.d.ts +7 -0
- package/dist/server/modules/external-integrations/sessions/provider-operation-gate.js +33 -0
- package/dist/server/modules/external-integrations/sessions/provider-operation-gate.js.map +1 -0
- package/dist/server/modules/external-integrations/subscribers/external-subtask-sync.subscriber.d.ts +69 -0
- package/dist/server/modules/external-integrations/subscribers/external-subtask-sync.subscriber.js +1092 -0
- package/dist/server/modules/external-integrations/subscribers/external-subtask-sync.subscriber.js.map +1 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-content.d.ts +8 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-content.js +23 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-content.js.map +1 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-recovery-policy.d.ts +7 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-recovery-policy.js +30 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-recovery-policy.js.map +1 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-sync-health.service.d.ts +44 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-sync-health.service.js +135 -0
- package/dist/server/modules/external-integrations/subscribers/managed-subtask-sync-health.service.js.map +1 -0
- package/dist/server/modules/external-integrations/transport/safe-vendor-http-client.d.ts +47 -0
- package/dist/server/modules/external-integrations/transport/safe-vendor-http-client.js +294 -0
- package/dist/server/modules/external-integrations/transport/safe-vendor-http-client.js.map +1 -0
- package/dist/server/modules/hooks/dtos/hook-event.dto.d.ts +64 -64
- package/dist/server/modules/mcp/dtos/mcp.dto.d.ts +36 -36
- package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.d.ts +5 -0
- package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.js +51 -1
- package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.js.map +1 -1
- package/dist/server/modules/orchestrator/sync/services/task-merge.service.d.ts +0 -2
- package/dist/server/modules/orchestrator/sync/services/task-merge.service.js +9 -48
- package/dist/server/modules/orchestrator/sync/services/task-merge.service.js.map +1 -1
- package/dist/server/modules/profiles/dto.d.ts +11 -11
- package/dist/server/modules/projects/controllers/projects.controller.d.ts +2 -2
- package/dist/server/modules/projects/dtos/export.dto.d.ts +6 -6
- package/dist/server/modules/projects/helpers/project-export.d.ts +1 -1
- package/dist/server/modules/projects/services/projects.service.d.ts +1 -1
- package/dist/server/modules/projects/template-codec/codecs/watchers.codec.d.ts +1 -1
- package/dist/server/modules/registry/controllers/templates.controller.d.ts +7 -7
- package/dist/server/modules/reviews/dtos/review.dto.d.ts +10 -10
- package/dist/server/modules/scheduled-epics/dtos/scheduled-epic.dto.d.ts +1 -1
- package/dist/server/modules/session-reader/adapters/antigravity-session-reader.adapter.d.ts +1 -1
- package/dist/server/modules/session-reader/adapters/opencode-session-reader.adapter.d.ts +1 -1
- package/dist/server/modules/session-reader/data/pricing.json +128 -39
- package/dist/server/modules/session-terminal-runtime/session-terminal-runtime.service.d.ts +2 -0
- package/dist/server/modules/session-terminal-runtime/session-terminal-runtime.service.js +18 -12
- package/dist/server/modules/session-terminal-runtime/session-terminal-runtime.service.js.map +1 -1
- package/dist/server/modules/sessions/controllers/sessions.controller.d.ts +3 -0
- package/dist/server/modules/sessions/controllers/sessions.controller.js +30 -0
- package/dist/server/modules/sessions/controllers/sessions.controller.js.map +1 -1
- package/dist/server/modules/sessions/dtos/sessions.dto.d.ts +2 -2
- package/dist/server/modules/sessions/services/message-enqueue.service.d.ts +2 -0
- package/dist/server/modules/sessions/services/message-enqueue.service.js +2 -0
- package/dist/server/modules/sessions/services/message-enqueue.service.js.map +1 -1
- package/dist/server/modules/sessions/services/message-pool.types.d.ts +8 -1
- package/dist/server/modules/sessions/services/sessions-message-pool.service.d.ts +50 -6
- package/dist/server/modules/sessions/services/sessions-message-pool.service.js +828 -190
- package/dist/server/modules/sessions/services/sessions-message-pool.service.js.map +1 -1
- package/dist/server/modules/settings/dtos/settings.dto.d.ts +8 -0
- package/dist/server/modules/settings/dtos/settings.dto.js +1 -0
- package/dist/server/modules/settings/dtos/settings.dto.js.map +1 -1
- package/dist/server/modules/settings/local/delegates/core-settings.delegate.js +12 -0
- package/dist/server/modules/settings/local/delegates/core-settings.delegate.js.map +1 -1
- package/dist/server/modules/settings/services/settings.constants.d.ts +1 -1
- package/dist/server/modules/settings/services/settings.constants.js +2 -1
- package/dist/server/modules/settings/services/settings.constants.js.map +1 -1
- package/dist/server/modules/settings/services/settings.service.d.ts +1 -1
- package/dist/server/modules/settings/services/settings.service.js +2 -1
- package/dist/server/modules/settings/services/settings.service.js.map +1 -1
- package/dist/server/modules/skills/dtos/skill.dto.d.ts +2 -2
- package/dist/server/modules/storage/db/schema.d.ts +2420 -958
- package/dist/server/modules/storage/db/schema.js +144 -2
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +34 -6
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/delegates/epic.delegate.d.ts +9 -5
- package/dist/server/modules/storage/local/delegates/epic.delegate.js +67 -30
- package/dist/server/modules/storage/local/delegates/epic.delegate.js.map +1 -1
- package/dist/server/modules/storage/local/delegates/external-managed-subtask.delegate.d.ts +18 -0
- package/dist/server/modules/storage/local/delegates/external-managed-subtask.delegate.js +320 -0
- package/dist/server/modules/storage/local/delegates/external-managed-subtask.delegate.js.map +1 -0
- package/dist/server/modules/storage/local/delegates/integration.delegate.d.ts +37 -0
- package/dist/server/modules/storage/local/delegates/integration.delegate.js +308 -0
- package/dist/server/modules/storage/local/delegates/integration.delegate.js.map +1 -0
- package/dist/server/modules/storage/local/integration-credential-cipher.d.ts +18 -0
- package/dist/server/modules/storage/local/integration-credential-cipher.js +138 -0
- package/dist/server/modules/storage/local/integration-credential-cipher.js.map +1 -0
- package/dist/server/modules/storage/local/local-storage.service.d.ts +36 -7
- package/dist/server/modules/storage/local/local-storage.service.js +93 -10
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +127 -0
- package/dist/server/modules/storage/models/domain.models.js +15 -0
- package/dist/server/modules/storage/models/domain.models.js.map +1 -1
- package/dist/server/modules/storage/storage.module.js +2 -1
- package/dist/server/modules/storage/storage.module.js.map +1 -1
- package/dist/server/modules/subscribers/dtos/subscriber.dto.d.ts +1 -1
- package/dist/server/modules/terminal/dtos/ws-envelope.dto.d.ts +2 -2
- package/dist/server/modules/terminal/gateways/terminal.gateway.d.ts +9 -1
- package/dist/server/modules/terminal/gateways/terminal.gateway.js +79 -3
- package/dist/server/modules/terminal/gateways/terminal.gateway.js.map +1 -1
- package/dist/server/modules/terminal/services/human-prompt-state.service.d.ts +58 -0
- package/dist/server/modules/terminal/services/human-prompt-state.service.js +206 -0
- package/dist/server/modules/terminal/services/human-prompt-state.service.js.map +1 -0
- package/dist/server/modules/terminal/services/terminal-activity.service.js +7 -18
- package/dist/server/modules/terminal/services/terminal-activity.service.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-io/delivery.d.ts +2 -1
- package/dist/server/modules/terminal/services/terminal-io/delivery.js +77 -33
- package/dist/server/modules/terminal/services/terminal-io/delivery.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-io/terminal-io.service.d.ts +14 -5
- package/dist/server/modules/terminal/services/terminal-io/terminal-io.service.js +64 -8
- package/dist/server/modules/terminal/services/terminal-io/terminal-io.service.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-io/types.d.ts +8 -0
- package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.d.ts +5 -1
- package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.js +39 -2
- package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-session/terminal-session-registry.d.ts +3 -1
- package/dist/server/modules/terminal/services/terminal-session/terminal-session-registry.js +7 -2
- package/dist/server/modules/terminal/services/terminal-session/terminal-session-registry.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-session/terminal-session.d.ts +4 -0
- package/dist/server/modules/terminal/services/terminal-session/terminal-session.js +8 -0
- package/dist/server/modules/terminal/services/terminal-session/terminal-session.js.map +1 -1
- package/dist/server/modules/terminal/terminal-delivery.module.js +13 -2
- package/dist/server/modules/terminal/terminal-delivery.module.js.map +1 -1
- package/dist/server/modules/terminal/terminal.module.js +4 -3
- package/dist/server/modules/terminal/terminal.module.js.map +1 -1
- package/dist/server/modules/terminal/utils/terminal-activity.d.ts +4 -0
- package/dist/server/modules/terminal/utils/terminal-activity.js +86 -0
- package/dist/server/modules/terminal/utils/terminal-activity.js.map +1 -0
- package/dist/server/modules/watchers/dtos/watcher.dto.d.ts +8 -8
- package/dist/server/templates/teams-dev.json +9 -9
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/ExternalRichEditor-DMtnZIMZ.js +113 -0
- package/dist/server/ui/assets/{ReviewDetailPage-CNffXKv8.js → ReviewDetailPage-BmyiM5IR.js} +1 -1
- package/dist/server/ui/assets/{ReviewsPage-DAcufZ3r.js → ReviewsPage-CQ87BMwT.js} +1 -1
- package/dist/server/ui/assets/index-BX6Yze-A.js +1177 -0
- package/dist/server/ui/assets/index-qoQEv_u4.css +32 -0
- package/dist/server/ui/assets/{useReviewSubscription-DD29I7uU.js → useReviewSubscription-DjbEUzt4.js} +1 -1
- package/dist/server/ui/index.html +2 -2
- package/dist/templates/teams-dev.json +9 -9
- package/package.json +15 -4
- package/dist/server/ui/assets/index-7iCs8Dxj.js +0 -1153
- package/dist/server/ui/assets/index-CLXZjL_B.css +0 -32
|
@@ -0,0 +1,1404 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ClickUpExternalTaskProvider = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const external_provider_errors_1 = require("../errors/external-provider.errors");
|
|
15
|
+
const external_provider_models_1 = require("../models/external-provider.models");
|
|
16
|
+
const external_task_source_1 = require("../models/external-task-source");
|
|
17
|
+
const external_comment_lookup_token_1 = require("../models/external-comment-lookup-token");
|
|
18
|
+
const clickup_comment_converter_1 = require("./rich/clickup-comment-converter");
|
|
19
|
+
const clickup_comment_converter_2 = require("./rich/clickup-comment-converter");
|
|
20
|
+
const safe_vendor_http_client_1 = require("../transport/safe-vendor-http-client");
|
|
21
|
+
const vendor_shared_1 = require("./vendor-shared");
|
|
22
|
+
const CLICKUP_ORIGIN = 'https://api.clickup.com';
|
|
23
|
+
const CLICKUP_TASK_PAGE_SIZE = 100;
|
|
24
|
+
const CLICKUP_MAX_TASK_PAGES = 1_000;
|
|
25
|
+
const CLICKUP_COMMENT_PAGE_SIZE = 25;
|
|
26
|
+
const CLICKUP_SUBTASK_PAGE_SIZE = 100;
|
|
27
|
+
const CLICKUP_SUBTASK_MAX_PAGES = 10;
|
|
28
|
+
const CLICKUP_OWNERSHIP_PREFIX = 'DevChain ownership token: `';
|
|
29
|
+
const CLICKUP_OWNERSHIP_SUFFIX = '`';
|
|
30
|
+
const CLICKUP_COMMENT_CURSOR_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
31
|
+
const CLICKUP_COMMENT_AUTHOR = {
|
|
32
|
+
nameKey: 'username',
|
|
33
|
+
idKey: 'id',
|
|
34
|
+
idFormat: 'identifier',
|
|
35
|
+
};
|
|
36
|
+
let ClickUpExternalTaskProvider = class ClickUpExternalTaskProvider {
|
|
37
|
+
http;
|
|
38
|
+
provider = 'clickup';
|
|
39
|
+
descriptor = {
|
|
40
|
+
provider: this.provider,
|
|
41
|
+
displayName: 'ClickUp',
|
|
42
|
+
capabilities: { myWork: true },
|
|
43
|
+
};
|
|
44
|
+
myWork = {
|
|
45
|
+
discover: (credentials, options) => this.discoverMyWork(credentials, options),
|
|
46
|
+
getTaskDetail: (credentials, context, remoteTaskId) => this.getTaskDetail(credentials, context, remoteTaskId),
|
|
47
|
+
listComments: (credentials, context, remoteTaskId, cursor) => this.listTaskComments(credentials, context, remoteTaskId, cursor),
|
|
48
|
+
changeStatus: (credentials, context, remoteTaskId, input) => this.changeTaskStatus(credentials, context, remoteTaskId, input),
|
|
49
|
+
addComment: (credentials, context, remoteTaskId, input) => this.addTaskComment(credentials, context, remoteTaskId, input),
|
|
50
|
+
getTimeEntryHistory: (credentials, context, remoteTaskId) => this.getTaskTimeEntryHistory(credentials, context, remoteTaskId),
|
|
51
|
+
};
|
|
52
|
+
timeEntryMutations = {
|
|
53
|
+
createTimeEntry: (credentials, context, remoteTaskId, input) => this.createTimeEntry(credentials, context, remoteTaskId, input),
|
|
54
|
+
deleteTimeEntry: (credentials, context, remoteTaskId, remoteEntryId) => this.deleteTimeEntry(credentials, context, remoteTaskId, remoteEntryId),
|
|
55
|
+
readTimeEntryExact: (credentials, context, remoteTaskId, remoteEntryId) => this.readTimeEntryExact(credentials, context, remoteTaskId, remoteEntryId),
|
|
56
|
+
listOwnTimeEntryIdsInRange: (credentials, context, remoteTaskId, startedAfterMs, startedBeforeMs) => this.listOwnTimeEntryIdsInRange(credentials, context, remoteTaskId, startedAfterMs, startedBeforeMs),
|
|
57
|
+
assertTimeEntryDeletable: (credentials, context, remoteTaskId, remoteEntryId) => this.assertTimeEntryDeletable(credentials, context, remoteTaskId, remoteEntryId),
|
|
58
|
+
};
|
|
59
|
+
listMetadataCache = new vendor_shared_1.VendorMetadataCache(vendor_shared_1.WORK_AREA_METADATA_CACHE_MAX_ENTRIES);
|
|
60
|
+
validate = (0, vendor_shared_1.createVendorValidators)((reason) => new external_provider_errors_1.ClickUpProviderError(reason));
|
|
61
|
+
constructor(http) {
|
|
62
|
+
this.http = http;
|
|
63
|
+
}
|
|
64
|
+
ownedMutations = {
|
|
65
|
+
getCurrentOwnerRemoteId: (credentials) => this.getCurrentOwnerRemoteId(credentials),
|
|
66
|
+
findComment: (credentials, context, remoteTaskId, commentId, pageProof) => this.findComment(credentials, context, remoteTaskId, commentId, pageProof),
|
|
67
|
+
deleteComment: (credentials, context, remoteTaskId, commentId) => this.deleteComment(credentials, context, remoteTaskId, commentId),
|
|
68
|
+
updateOwnedComment: (credentials, context, remoteTaskId, commentId, document, metadata) => this.updateOwnedComment(credentials, context, remoteTaskId, commentId, document, metadata),
|
|
69
|
+
};
|
|
70
|
+
descriptionEdit = {
|
|
71
|
+
readDescription: (credentials, context, remoteTaskId) => this.readDescription(credentials, context, remoteTaskId),
|
|
72
|
+
writeDescription: (credentials, context, remoteTaskId, raw) => this.writeDescription(credentials, context, remoteTaskId, raw),
|
|
73
|
+
};
|
|
74
|
+
subtaskSync = {
|
|
75
|
+
create: (credentials, context, input) => this.createSubtask(credentials, context, input),
|
|
76
|
+
readExact: (credentials, context, remoteTaskId) => this.readSubtaskExact(credentials, context, remoteTaskId),
|
|
77
|
+
update: (credentials, context, input) => this.updateSubtask(credentials, context, input),
|
|
78
|
+
delete: (credentials, context, proof) => this.deleteSubtask(credentials, context, proof),
|
|
79
|
+
listOwnedDirectChildren: (credentials, context, parentRemoteTaskId, ownershipToken) => this.listOwnedDirectChildren(credentials, context, parentRemoteTaskId, ownershipToken),
|
|
80
|
+
assertOwned: (credentials, context, proof) => this.assertOwnedSubtask(credentials, context, proof),
|
|
81
|
+
};
|
|
82
|
+
async createSubtask(credentials, _context, input) {
|
|
83
|
+
const token = this.requireToken(credentials);
|
|
84
|
+
const parentTaskId = this.validate.requiredTaskId(input.parentRemoteTaskId);
|
|
85
|
+
const ownershipToken = this.requireSubtaskOwnershipToken(input.ownershipToken);
|
|
86
|
+
const title = this.requireSubtaskTitle(input.title);
|
|
87
|
+
const description = this.requireSubtaskDescription(input.description);
|
|
88
|
+
const parent = await this.readClickUpTaskExact(token, parentTaskId);
|
|
89
|
+
if (parent === null) {
|
|
90
|
+
throw new external_provider_errors_1.ClickUpProviderError('not_found');
|
|
91
|
+
}
|
|
92
|
+
const ownerRemoteId = await this.getCurrentOwnerRemoteId(credentials);
|
|
93
|
+
const ownerId = Number(ownerRemoteId);
|
|
94
|
+
if (!/^\d+$/.test(ownerRemoteId) || !Number.isSafeInteger(ownerId) || ownerId <= 0) {
|
|
95
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
96
|
+
}
|
|
97
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/list/${encodeURIComponent(parent.workAreaRemoteId)}/task`, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
body: JSON.stringify({
|
|
100
|
+
name: title,
|
|
101
|
+
markdown_content: this.managedMarkdown(description, ownershipToken),
|
|
102
|
+
parent: parentTaskId,
|
|
103
|
+
assignees: [ownerId],
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
try {
|
|
107
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !(0, vendor_shared_1.isRecord)(payload.list)) {
|
|
108
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
109
|
+
}
|
|
110
|
+
const remoteTaskId = this.validate.requiredIdentifier(payload.id);
|
|
111
|
+
const parentRemoteTaskId = this.validate.requiredIdentifier(payload.parent);
|
|
112
|
+
const workAreaRemoteId = this.validate.requiredIdentifier(payload.list.id);
|
|
113
|
+
if (parentRemoteTaskId !== parentTaskId ||
|
|
114
|
+
workAreaRemoteId !== parent.workAreaRemoteId ||
|
|
115
|
+
this.validate.requiredString(payload.name) !== title) {
|
|
116
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
remoteTaskId,
|
|
120
|
+
remoteKey: this.optionalIdentifier(payload.custom_id) ?? remoteTaskId,
|
|
121
|
+
parentRemoteTaskId,
|
|
122
|
+
workAreaRemoteId,
|
|
123
|
+
ownershipToken,
|
|
124
|
+
title,
|
|
125
|
+
description,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error instanceof external_provider_errors_1.ClickUpProviderError) {
|
|
130
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response', undefined, true);
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async readSubtaskExact(credentials, _context, remoteTaskId) {
|
|
136
|
+
return this.readClickUpTaskExact(this.requireToken(credentials), this.validate.requiredTaskId(remoteTaskId));
|
|
137
|
+
}
|
|
138
|
+
async readClickUpTaskExact(token, taskId) {
|
|
139
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`);
|
|
140
|
+
url.searchParams.set('include_markdown_description', 'true');
|
|
141
|
+
try {
|
|
142
|
+
const payload = await this.requestJson(token, url.toString());
|
|
143
|
+
const snapshot = this.normalizeManagedSubtask(payload);
|
|
144
|
+
if (snapshot.remoteTaskId !== taskId) {
|
|
145
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
146
|
+
}
|
|
147
|
+
return snapshot;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error instanceof external_provider_errors_1.ClickUpProviderError && error.details?.reason === 'not_found') {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async updateSubtask(credentials, context, input) {
|
|
157
|
+
const current = await this.assertOwnedSubtask(credentials, context, input);
|
|
158
|
+
const body = {};
|
|
159
|
+
if (input.title !== undefined) {
|
|
160
|
+
body.name = this.requireSubtaskTitle(input.title);
|
|
161
|
+
}
|
|
162
|
+
if (input.description !== undefined) {
|
|
163
|
+
body.markdown_content = this.managedMarkdown(this.requireSubtaskDescription(input.description), this.requireSubtaskOwnershipToken(input.ownershipToken));
|
|
164
|
+
}
|
|
165
|
+
if (Object.keys(body).length === 0) {
|
|
166
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
167
|
+
}
|
|
168
|
+
const payload = await this.requestJson(this.requireToken(credentials), `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(current.remoteTaskId)}`, { method: 'PUT', body: JSON.stringify(body) });
|
|
169
|
+
if (!(0, vendor_shared_1.isRecord)(payload) ||
|
|
170
|
+
this.validate.requiredIdentifier(payload.id) !== current.remoteTaskId) {
|
|
171
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response', undefined, true);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async deleteSubtask(credentials, context, proof) {
|
|
175
|
+
const current = await this.readSubtaskExact(credentials, context, proof.remoteTaskId);
|
|
176
|
+
if (current === null) {
|
|
177
|
+
return { outcome: 'already_absent' };
|
|
178
|
+
}
|
|
179
|
+
this.assertSubtaskProof(current, proof);
|
|
180
|
+
try {
|
|
181
|
+
await this.requestNoContent(this.requireToken(credentials), `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(current.remoteTaskId)}`, { method: 'DELETE' });
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error instanceof external_provider_errors_1.ClickUpProviderError && error.details?.reason === 'not_found') {
|
|
185
|
+
return { outcome: 'already_absent' };
|
|
186
|
+
}
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
return { outcome: 'deleted' };
|
|
190
|
+
}
|
|
191
|
+
async listOwnedDirectChildren(credentials, _context, parentRemoteTaskId, ownershipToken) {
|
|
192
|
+
const token = this.requireToken(credentials);
|
|
193
|
+
const parentTaskId = this.validate.requiredTaskId(parentRemoteTaskId);
|
|
194
|
+
const normalizedToken = this.requireSubtaskOwnershipToken(ownershipToken);
|
|
195
|
+
const parent = await this.readClickUpTaskExact(token, parentTaskId);
|
|
196
|
+
if (parent === null) {
|
|
197
|
+
throw new external_provider_errors_1.ClickUpProviderError('not_found');
|
|
198
|
+
}
|
|
199
|
+
const items = new Map();
|
|
200
|
+
for (let page = 0; page < CLICKUP_SUBTASK_MAX_PAGES; page += 1) {
|
|
201
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/list/${encodeURIComponent(parent.workAreaRemoteId)}/task`);
|
|
202
|
+
url.searchParams.set('page', String(page));
|
|
203
|
+
url.searchParams.set('subtasks', 'true');
|
|
204
|
+
url.searchParams.set('include_closed', 'true');
|
|
205
|
+
url.searchParams.set('include_markdown_description', 'true');
|
|
206
|
+
const payload = await this.requestJson(token, url.toString());
|
|
207
|
+
if (!(0, vendor_shared_1.isRecord)(payload) ||
|
|
208
|
+
!Array.isArray(payload.tasks) ||
|
|
209
|
+
payload.tasks.length > CLICKUP_SUBTASK_PAGE_SIZE) {
|
|
210
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
211
|
+
}
|
|
212
|
+
for (const raw of payload.tasks) {
|
|
213
|
+
const child = this.normalizeManagedSubtask(raw);
|
|
214
|
+
if (child.parentRemoteTaskId === parentTaskId && child.ownershipToken === normalizedToken) {
|
|
215
|
+
items.set(child.remoteTaskId, child);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (payload.tasks.length < CLICKUP_SUBTASK_PAGE_SIZE) {
|
|
219
|
+
return { items: [...items.values()], complete: true };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { items: [...items.values()], complete: false };
|
|
223
|
+
}
|
|
224
|
+
async assertOwnedSubtask(credentials, context, proof) {
|
|
225
|
+
const current = await this.readSubtaskExact(credentials, context, proof.remoteTaskId);
|
|
226
|
+
if (current === null) {
|
|
227
|
+
throw new external_provider_errors_1.ClickUpProviderError('not_found');
|
|
228
|
+
}
|
|
229
|
+
this.assertSubtaskProof(current, proof);
|
|
230
|
+
return current;
|
|
231
|
+
}
|
|
232
|
+
assertSubtaskProof(current, proof) {
|
|
233
|
+
const ownershipToken = this.requireSubtaskOwnershipToken(proof.ownershipToken);
|
|
234
|
+
const expectedParent = this.validate.requiredTaskId(proof.expectedParentRemoteTaskId);
|
|
235
|
+
if (current.ownershipToken !== ownershipToken) {
|
|
236
|
+
throw new external_provider_errors_1.ClickUpProviderError('ownership_mismatch');
|
|
237
|
+
}
|
|
238
|
+
if (current.parentRemoteTaskId !== expectedParent) {
|
|
239
|
+
throw new external_provider_errors_1.ClickUpProviderError('parent_mismatch');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
normalizeManagedSubtask(value) {
|
|
243
|
+
if (!(0, vendor_shared_1.isRecord)(value) || !(0, vendor_shared_1.isRecord)(value.list)) {
|
|
244
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
245
|
+
}
|
|
246
|
+
const remoteTaskId = this.validate.requiredIdentifier(value.id);
|
|
247
|
+
const customId = this.optionalIdentifier(value.custom_id);
|
|
248
|
+
const parentRemoteTaskId = value.parent === null || value.parent === undefined
|
|
249
|
+
? null
|
|
250
|
+
: this.validate.requiredIdentifier(value.parent);
|
|
251
|
+
const markdown = value.markdown_description;
|
|
252
|
+
if (markdown !== null && markdown !== undefined && typeof markdown !== 'string') {
|
|
253
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
254
|
+
}
|
|
255
|
+
const managed = this.parseManagedMarkdown(markdown ?? null);
|
|
256
|
+
return {
|
|
257
|
+
remoteTaskId,
|
|
258
|
+
remoteKey: customId ?? remoteTaskId,
|
|
259
|
+
parentRemoteTaskId,
|
|
260
|
+
workAreaRemoteId: this.validate.requiredIdentifier(value.list.id),
|
|
261
|
+
ownershipToken: managed.ownershipToken,
|
|
262
|
+
title: this.validate.requiredString(value.name),
|
|
263
|
+
description: managed.description,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
managedMarkdown(description, ownershipToken) {
|
|
267
|
+
const footer = `${external_provider_models_1.EXTERNAL_SUBTASK_MANAGEMENT_NOTE}\n\n${CLICKUP_OWNERSHIP_PREFIX}${ownershipToken}${CLICKUP_OWNERSHIP_SUFFIX}`;
|
|
268
|
+
return description === null ? footer : `${description}\n\n${footer}`;
|
|
269
|
+
}
|
|
270
|
+
parseManagedMarkdown(value) {
|
|
271
|
+
if (value === null || value === '') {
|
|
272
|
+
return { description: null, ownershipToken: null };
|
|
273
|
+
}
|
|
274
|
+
const notePosition = value.lastIndexOf(`\n\n${external_provider_models_1.EXTERNAL_SUBTASK_MANAGEMENT_NOTE}\n\n`);
|
|
275
|
+
const startsWithNote = value.startsWith(`${external_provider_models_1.EXTERNAL_SUBTASK_MANAGEMENT_NOTE}\n\n`);
|
|
276
|
+
const markerStart = notePosition >= 0
|
|
277
|
+
? notePosition + 2 + external_provider_models_1.EXTERNAL_SUBTASK_MANAGEMENT_NOTE.length + 2
|
|
278
|
+
: startsWithNote
|
|
279
|
+
? external_provider_models_1.EXTERNAL_SUBTASK_MANAGEMENT_NOTE.length + 2
|
|
280
|
+
: -1;
|
|
281
|
+
if (markerStart < 0 || !value.startsWith(CLICKUP_OWNERSHIP_PREFIX, markerStart)) {
|
|
282
|
+
return { description: value || null, ownershipToken: null };
|
|
283
|
+
}
|
|
284
|
+
const tokenStart = markerStart + CLICKUP_OWNERSHIP_PREFIX.length;
|
|
285
|
+
if (!value.endsWith(CLICKUP_OWNERSHIP_SUFFIX)) {
|
|
286
|
+
return { description: value || null, ownershipToken: null };
|
|
287
|
+
}
|
|
288
|
+
const token = value.slice(tokenStart, -CLICKUP_OWNERSHIP_SUFFIX.length);
|
|
289
|
+
if (!this.isSubtaskOwnershipToken(token)) {
|
|
290
|
+
return { description: value || null, ownershipToken: null };
|
|
291
|
+
}
|
|
292
|
+
const description = notePosition > 0 ? value.slice(0, notePosition) : null;
|
|
293
|
+
return { description: description || null, ownershipToken: token };
|
|
294
|
+
}
|
|
295
|
+
requireSubtaskTitle(value) {
|
|
296
|
+
if (typeof value !== 'string' ||
|
|
297
|
+
!value.trim() ||
|
|
298
|
+
value.length > external_provider_models_1.MAX_EXTERNAL_SUBTASK_TITLE_LENGTH) {
|
|
299
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
300
|
+
}
|
|
301
|
+
return value.trim();
|
|
302
|
+
}
|
|
303
|
+
requireSubtaskDescription(value) {
|
|
304
|
+
if (value === null || value === '') {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
if (typeof value !== 'string' || value.length > external_provider_models_1.MAX_EXTERNAL_SUBTASK_DESCRIPTION_LENGTH) {
|
|
308
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
309
|
+
}
|
|
310
|
+
return value;
|
|
311
|
+
}
|
|
312
|
+
isSubtaskOwnershipToken(value) {
|
|
313
|
+
return (value.length <= external_provider_models_1.MAX_EXTERNAL_SUBTASK_OWNERSHIP_TOKEN_LENGTH &&
|
|
314
|
+
/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(value));
|
|
315
|
+
}
|
|
316
|
+
requireSubtaskOwnershipToken(value) {
|
|
317
|
+
if (typeof value !== 'string' || !this.isSubtaskOwnershipToken(value)) {
|
|
318
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
319
|
+
}
|
|
320
|
+
return value;
|
|
321
|
+
}
|
|
322
|
+
async getCurrentOwnerRemoteId(credentials) {
|
|
323
|
+
const token = this.requireToken(credentials);
|
|
324
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/user`);
|
|
325
|
+
const dto = payload;
|
|
326
|
+
return this.validate.requiredIdentifier(dto?.user?.id);
|
|
327
|
+
}
|
|
328
|
+
async findComment(credentials, _context, remoteTaskId, commentId, pageProof) {
|
|
329
|
+
const token = this.requireToken(credentials);
|
|
330
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
331
|
+
const normalizedCommentId = this.validate.requiredIdentifier(commentId);
|
|
332
|
+
let position = pageProof === null ? null : this.decodeCommentCursor(pageProof);
|
|
333
|
+
for (let hop = 0; hop < 2; hop += 1) {
|
|
334
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}/comment`);
|
|
335
|
+
if (position) {
|
|
336
|
+
url.searchParams.set('start', String(position.date));
|
|
337
|
+
url.searchParams.set('start_id', position.id);
|
|
338
|
+
}
|
|
339
|
+
const payload = await this.requestJson(token, url.toString());
|
|
340
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !Array.isArray(payload.comments)) {
|
|
341
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
342
|
+
}
|
|
343
|
+
const match = payload.comments.find((value) => (0, vendor_shared_1.isRecord)(value) &&
|
|
344
|
+
(typeof value.id === 'string' || typeof value.id === 'number') &&
|
|
345
|
+
String(value.id) === normalizedCommentId);
|
|
346
|
+
if (match) {
|
|
347
|
+
const snapshot = this.normalizeTaskComment(match);
|
|
348
|
+
return {
|
|
349
|
+
remoteId: snapshot.remoteId,
|
|
350
|
+
authorRemoteId: snapshot.author.remoteId,
|
|
351
|
+
createdAt: snapshot.createdAt,
|
|
352
|
+
raw: match.comment ?? null,
|
|
353
|
+
metadata: this.commentMetadata(match),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const last = payload.comments[payload.comments.length - 1];
|
|
357
|
+
const lastRecord = (0, vendor_shared_1.isRecord)(last) ? last : null;
|
|
358
|
+
if (!lastRecord) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
const nextDate = this.requiredTimestamp(lastRecord.date);
|
|
362
|
+
const nextId = typeof lastRecord.id === 'string' || typeof lastRecord.id === 'number'
|
|
363
|
+
? String(lastRecord.id)
|
|
364
|
+
: null;
|
|
365
|
+
if (nextId === null) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
position = this.decodeCommentCursor(this.encodeCommentCursor(Date.parse(nextDate), nextId));
|
|
369
|
+
}
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
async deleteComment(credentials, _context, remoteTaskId, commentId) {
|
|
373
|
+
const token = this.requireToken(credentials);
|
|
374
|
+
this.validate.requiredTaskId(remoteTaskId);
|
|
375
|
+
const normalizedCommentId = this.validate.requiredIdentifier(commentId);
|
|
376
|
+
await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/comment/${encodeURIComponent(normalizedCommentId)}`, { method: 'DELETE' });
|
|
377
|
+
}
|
|
378
|
+
async updateOwnedComment(credentials, _context, remoteTaskId, commentId, document, metadata) {
|
|
379
|
+
const token = this.requireToken(credentials);
|
|
380
|
+
this.validate.requiredTaskId(remoteTaskId);
|
|
381
|
+
const normalizedCommentId = this.validate.requiredIdentifier(commentId);
|
|
382
|
+
const emitted = (0, clickup_comment_converter_2.richDocumentToClickUpCommentDelta)(document);
|
|
383
|
+
if (!emitted.ok) {
|
|
384
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
385
|
+
}
|
|
386
|
+
await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/comment/${encodeURIComponent(normalizedCommentId)}`, {
|
|
387
|
+
method: 'PUT',
|
|
388
|
+
body: JSON.stringify({
|
|
389
|
+
comment: emitted.delta,
|
|
390
|
+
assignee: metadata.assignee,
|
|
391
|
+
resolved: metadata.resolved ?? false,
|
|
392
|
+
...(metadata.groupAssignee !== null ? { group_assignee: metadata.groupAssignee } : {}),
|
|
393
|
+
}),
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
commentMetadata(raw) {
|
|
397
|
+
if (!(0, vendor_shared_1.isRecord)(raw)) {
|
|
398
|
+
return { assignee: null, resolved: null, groupAssignee: null };
|
|
399
|
+
}
|
|
400
|
+
const assignee = (0, vendor_shared_1.isRecord)(raw.assignee) ? raw.assignee.id : raw.assignee;
|
|
401
|
+
const groupAssignee = raw.group_assignee;
|
|
402
|
+
return {
|
|
403
|
+
assignee: typeof assignee === 'number' && Number.isSafeInteger(assignee)
|
|
404
|
+
? assignee
|
|
405
|
+
: typeof assignee === 'string' && /^\d+$/.test(assignee)
|
|
406
|
+
? Number(assignee)
|
|
407
|
+
: null,
|
|
408
|
+
resolved: typeof raw.resolved === 'boolean' ? raw.resolved : null,
|
|
409
|
+
groupAssignee: typeof groupAssignee === 'string' && groupAssignee ? groupAssignee : null,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
async readDescription(credentials, _context, remoteTaskId) {
|
|
413
|
+
const token = this.requireToken(credentials);
|
|
414
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
415
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`);
|
|
416
|
+
url.searchParams.set('include_markdown_description', 'true');
|
|
417
|
+
const payload = await this.requestJson(token, url.toString());
|
|
418
|
+
if (!(0, vendor_shared_1.isRecord)(payload)) {
|
|
419
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
420
|
+
}
|
|
421
|
+
const markdown = payload.markdown_description;
|
|
422
|
+
if (markdown === null || markdown === undefined) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
if (typeof markdown !== 'string') {
|
|
426
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
427
|
+
}
|
|
428
|
+
return markdown;
|
|
429
|
+
}
|
|
430
|
+
async writeDescription(credentials, _context, remoteTaskId, raw) {
|
|
431
|
+
const token = this.requireToken(credentials);
|
|
432
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
433
|
+
if (typeof raw !== 'string' || !raw.trim()) {
|
|
434
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
435
|
+
}
|
|
436
|
+
await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`, {
|
|
437
|
+
method: 'PUT',
|
|
438
|
+
body: JSON.stringify({ markdown_description: raw }),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
async verifyCredentials(credentials) {
|
|
442
|
+
const token = this.requireToken(credentials);
|
|
443
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/user`);
|
|
444
|
+
const dto = payload;
|
|
445
|
+
const remoteId = dto?.user?.id;
|
|
446
|
+
const displayName = dto?.user?.username;
|
|
447
|
+
if (typeof displayName !== 'string' || !displayName.trim()) {
|
|
448
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
provider: this.provider,
|
|
452
|
+
remoteId: this.validate.requiredIdentifier(remoteId),
|
|
453
|
+
displayName: displayName.trim(),
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
async getTaskDetail(credentials, _context, remoteTaskId) {
|
|
457
|
+
const token = this.requireToken(credentials);
|
|
458
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
459
|
+
const taskUrl = new URL(`${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`);
|
|
460
|
+
taskUrl.searchParams.set('include_subtasks', 'true');
|
|
461
|
+
const payload = await this.requestJson(token, taskUrl.toString());
|
|
462
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !(0, vendor_shared_1.isRecord)(payload.status) || !(0, vendor_shared_1.isRecord)(payload.list)) {
|
|
463
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
464
|
+
}
|
|
465
|
+
const returnedId = this.validate.requiredIdentifier(payload.id);
|
|
466
|
+
if (returnedId !== taskId) {
|
|
467
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
468
|
+
}
|
|
469
|
+
const scopeKey = this.validate.requiredIdentifier(payload.team_id);
|
|
470
|
+
const workAreaId = this.validate.requiredIdentifier(payload.list.id);
|
|
471
|
+
const description = this.boundedTaskDescription(payload.text_content);
|
|
472
|
+
const webUrl = this.requiredTaskUrl(payload.url);
|
|
473
|
+
const allowedStatuses = await this.loadAllowedStatuses(token, workAreaId);
|
|
474
|
+
const childResult = this.normalizeTaskSubtasks(payload.subtasks, taskId);
|
|
475
|
+
const customId = payload.custom_id;
|
|
476
|
+
if (customId !== null && customId !== undefined && typeof customId !== 'string') {
|
|
477
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
remoteId: returnedId,
|
|
481
|
+
remoteKey: typeof customId === 'string' && customId.trim() ? customId : returnedId,
|
|
482
|
+
title: this.validate.requiredString(payload.name),
|
|
483
|
+
description: description.value,
|
|
484
|
+
descriptionTruncated: description.truncated,
|
|
485
|
+
status: this.normalizeColumn(payload.status),
|
|
486
|
+
dueAt: this.optionalTimestamp(payload.due_date),
|
|
487
|
+
priority: this.normalizePriority(payload.priority),
|
|
488
|
+
subtasks: childResult.items,
|
|
489
|
+
subtasksTruncated: childResult.truncated,
|
|
490
|
+
taskTotalDurationMs: this.taskTotalDurationMs(payload.time_spent),
|
|
491
|
+
webUrl,
|
|
492
|
+
location: {
|
|
493
|
+
scopeKey,
|
|
494
|
+
workAreaId,
|
|
495
|
+
workAreaName: this.validate.requiredString(payload.list.name),
|
|
496
|
+
},
|
|
497
|
+
allowedStatuses,
|
|
498
|
+
actions: [
|
|
499
|
+
{ action: 'change_status', supported: true },
|
|
500
|
+
{ action: 'add_comment', supported: true },
|
|
501
|
+
{ action: 'log_time', supported: true },
|
|
502
|
+
],
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
async listTaskComments(credentials, context, remoteTaskId, cursor) {
|
|
506
|
+
const token = this.requireToken(credentials);
|
|
507
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
508
|
+
const position = cursor === null ? null : this.decodeCommentCursor(cursor);
|
|
509
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}/comment`);
|
|
510
|
+
if (position) {
|
|
511
|
+
url.searchParams.set('start', String(position.date));
|
|
512
|
+
url.searchParams.set('start_id', position.id);
|
|
513
|
+
}
|
|
514
|
+
const payload = await this.requestJson(token, url.toString());
|
|
515
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !Array.isArray(payload.comments)) {
|
|
516
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
517
|
+
}
|
|
518
|
+
if (payload.comments.length > CLICKUP_COMMENT_PAGE_SIZE) {
|
|
519
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
520
|
+
}
|
|
521
|
+
const comments = payload.comments.map((value) => {
|
|
522
|
+
const comment = this.normalizeTaskComment(value);
|
|
523
|
+
return this.enrichTaskComment(comment, value, taskId, cursor, context);
|
|
524
|
+
});
|
|
525
|
+
const last = comments[comments.length - 1];
|
|
526
|
+
return {
|
|
527
|
+
comments,
|
|
528
|
+
nextCursor: comments.length === CLICKUP_COMMENT_PAGE_SIZE && last
|
|
529
|
+
? this.encodeCommentCursor(Date.parse(last.createdAt), last.remoteId)
|
|
530
|
+
: null,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
enrichTaskComment(comment, raw, taskId, pageProof, context) {
|
|
534
|
+
const delta = (0, vendor_shared_1.isRecord)(raw) ? raw.comment : undefined;
|
|
535
|
+
const parsed = delta === undefined || delta === null ? null : (0, clickup_comment_converter_1.clickupCommentDeltaToRichDocument)(delta);
|
|
536
|
+
return {
|
|
537
|
+
...comment,
|
|
538
|
+
owned: false,
|
|
539
|
+
rich: parsed === null
|
|
540
|
+
? null
|
|
541
|
+
: parsed.supported
|
|
542
|
+
? { document: parsed.document, supported: true }
|
|
543
|
+
: { supported: false, readOnlyReason: parsed.reason },
|
|
544
|
+
lookupToken: (0, external_comment_lookup_token_1.encodeExternalCommentLookupToken)({
|
|
545
|
+
v: 1,
|
|
546
|
+
provider: 'clickup',
|
|
547
|
+
connectionId: context.connectionId,
|
|
548
|
+
connectionGeneration: context.connectionGeneration,
|
|
549
|
+
taskId,
|
|
550
|
+
commentId: comment.remoteId,
|
|
551
|
+
pageProof,
|
|
552
|
+
}),
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
decodeCommentCursor(cursor) {
|
|
556
|
+
if (cursor.length > external_provider_models_1.MAX_TASK_COMMENT_CURSOR_LENGTH ||
|
|
557
|
+
!CLICKUP_COMMENT_CURSOR_PATTERN.test(cursor)) {
|
|
558
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
559
|
+
}
|
|
560
|
+
let decoded;
|
|
561
|
+
try {
|
|
562
|
+
decoded = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'));
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
566
|
+
}
|
|
567
|
+
if (!(0, vendor_shared_1.isRecord)(decoded)) {
|
|
568
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
569
|
+
}
|
|
570
|
+
const id = decoded.id;
|
|
571
|
+
if (typeof id !== 'string' || !id.trim() || id.trim().length > external_provider_models_1.MAX_TASK_COMMENT_ID_LENGTH) {
|
|
572
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
573
|
+
}
|
|
574
|
+
const date = decoded.date;
|
|
575
|
+
if (typeof date !== 'number' || !Number.isSafeInteger(date) || date < 0) {
|
|
576
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
577
|
+
}
|
|
578
|
+
return { date, id: id.trim() };
|
|
579
|
+
}
|
|
580
|
+
encodeCommentCursor(date, id) {
|
|
581
|
+
return Buffer.from(JSON.stringify({ date, id }), 'utf8').toString('base64url');
|
|
582
|
+
}
|
|
583
|
+
normalizeTaskComment(value) {
|
|
584
|
+
if (!(0, vendor_shared_1.isRecord)(value)) {
|
|
585
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
586
|
+
}
|
|
587
|
+
const remoteId = this.validate.requiredIdentifier(value.id);
|
|
588
|
+
if (remoteId.length > external_provider_models_1.MAX_TASK_COMMENT_ID_LENGTH) {
|
|
589
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
590
|
+
}
|
|
591
|
+
const text = value.comment_text;
|
|
592
|
+
if (text !== null && text !== undefined && typeof text !== 'string') {
|
|
593
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
594
|
+
}
|
|
595
|
+
const body = text ?? '';
|
|
596
|
+
return {
|
|
597
|
+
remoteId,
|
|
598
|
+
author: this.validate.commentAuthor(value.user, CLICKUP_COMMENT_AUTHOR),
|
|
599
|
+
body: body.slice(0, external_provider_models_1.MAX_TASK_COMMENT_BODY_LENGTH),
|
|
600
|
+
bodyTruncated: body.length > external_provider_models_1.MAX_TASK_COMMENT_BODY_LENGTH,
|
|
601
|
+
createdAt: this.requiredTimestamp(value.date),
|
|
602
|
+
updatedAt: null,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
async changeTaskStatus(credentials, _context, remoteTaskId, input) {
|
|
606
|
+
const token = this.requireToken(credentials);
|
|
607
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
608
|
+
const status = this.validate.statusInput(input);
|
|
609
|
+
await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`, {
|
|
610
|
+
method: 'PUT',
|
|
611
|
+
body: JSON.stringify({ status }),
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
async addTaskComment(credentials, _context, remoteTaskId, input) {
|
|
615
|
+
const token = this.requireToken(credentials);
|
|
616
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
617
|
+
this.validate.commentInput(input);
|
|
618
|
+
await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}/comment`, {
|
|
619
|
+
method: 'POST',
|
|
620
|
+
body: JSON.stringify({ comment_text: input.text, notify_all: input.notifyAll }),
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
async loadTaskWorkspace(token, taskId) {
|
|
624
|
+
const task = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`);
|
|
625
|
+
if (!(0, vendor_shared_1.isRecord)(task) || this.validate.requiredIdentifier(task.id) !== taskId) {
|
|
626
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
627
|
+
}
|
|
628
|
+
return this.validate.requiredIdentifier(task.team_id);
|
|
629
|
+
}
|
|
630
|
+
async createTimeEntry(credentials, _context, remoteTaskId, input) {
|
|
631
|
+
const token = this.requireToken(credentials);
|
|
632
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
633
|
+
const startedAt = this.validate.timeEntryInput(input);
|
|
634
|
+
const workspaceId = await this.loadTaskWorkspace(token, taskId);
|
|
635
|
+
const body = {
|
|
636
|
+
start: startedAt,
|
|
637
|
+
duration: input.durationMs,
|
|
638
|
+
};
|
|
639
|
+
if (input.note !== null) {
|
|
640
|
+
body.description = input.note;
|
|
641
|
+
}
|
|
642
|
+
body.tid = taskId;
|
|
643
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/team/${encodeURIComponent(workspaceId)}/time_entries`, { method: 'POST', body: JSON.stringify(body) });
|
|
644
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !this.isDocumentedCreateReceipt(payload, taskId)) {
|
|
645
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response', undefined, true);
|
|
646
|
+
}
|
|
647
|
+
return { remoteEntryId: this.optionalIdentifier(payload.id) };
|
|
648
|
+
}
|
|
649
|
+
isDocumentedCreateReceipt(payload, taskId) {
|
|
650
|
+
if (!this.isNumericValue(payload.start) || !this.isNumericValue(payload.duration)) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
if (!this.isNumericValue(payload.assignee) || typeof payload.billable !== 'boolean') {
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
if (!Array.isArray(payload.tags)) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
if (payload.description !== null &&
|
|
660
|
+
payload.description !== undefined &&
|
|
661
|
+
typeof payload.description !== 'string') {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
const tid = this.optionalIdentifier(payload.tid);
|
|
665
|
+
return tid !== null && tid === taskId;
|
|
666
|
+
}
|
|
667
|
+
async readTimeEntryExact(credentials, _context, remoteTaskId, remoteEntryId) {
|
|
668
|
+
const token = this.requireToken(credentials);
|
|
669
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
670
|
+
const entryId = this.validate.requiredIdentifier(remoteEntryId);
|
|
671
|
+
const ownerId = await this.getCurrentOwnerRemoteId(credentials);
|
|
672
|
+
const workspaceId = await this.loadTaskWorkspace(token, taskId);
|
|
673
|
+
let payload;
|
|
674
|
+
try {
|
|
675
|
+
payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/team/${encodeURIComponent(workspaceId)}/time_entries/${encodeURIComponent(entryId)}`);
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
if (error instanceof external_provider_errors_1.ClickUpProviderError && error.details?.reason === 'not_found') {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
throw error;
|
|
682
|
+
}
|
|
683
|
+
const entry = this.singularTimeEntryBody(payload);
|
|
684
|
+
if (entry === null) {
|
|
685
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
686
|
+
}
|
|
687
|
+
const remoteId = this.optionalIdentifier(entry.id);
|
|
688
|
+
if (remoteId === null || remoteId !== entryId) {
|
|
689
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
690
|
+
}
|
|
691
|
+
const owner = (0, vendor_shared_1.isRecord)(entry.user) ? this.validate.requiredIdentifier(entry.user.id) : null;
|
|
692
|
+
if (owner === null) {
|
|
693
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
694
|
+
}
|
|
695
|
+
return {
|
|
696
|
+
remoteId,
|
|
697
|
+
startedAt: new Date(this.numericValue(entry.start)).toISOString(),
|
|
698
|
+
durationMs: this.numericValue(entry.duration),
|
|
699
|
+
owned: owner === ownerId,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
singularTimeEntryBody(payload) {
|
|
703
|
+
if (!(0, vendor_shared_1.isRecord)(payload)) {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
if (!('data' in payload)) {
|
|
707
|
+
return payload;
|
|
708
|
+
}
|
|
709
|
+
const data = payload.data;
|
|
710
|
+
if ((0, vendor_shared_1.isRecord)(data)) {
|
|
711
|
+
return data;
|
|
712
|
+
}
|
|
713
|
+
if (Array.isArray(data) && data.length === 1) {
|
|
714
|
+
const only = data[0];
|
|
715
|
+
if ((0, vendor_shared_1.isRecord)(only)) {
|
|
716
|
+
return only;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
async deleteTimeEntry(credentials, _context, remoteTaskId, remoteEntryId) {
|
|
722
|
+
const token = this.requireToken(credentials);
|
|
723
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
724
|
+
const entryId = this.validate.requiredIdentifier(remoteEntryId);
|
|
725
|
+
const workspaceId = await this.loadTaskWorkspace(token, taskId);
|
|
726
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/team/${encodeURIComponent(workspaceId)}/time_entries/${encodeURIComponent(entryId)}`, { method: 'DELETE' });
|
|
727
|
+
const entry = this.singularTimeEntryBody(payload);
|
|
728
|
+
if (entry === null) {
|
|
729
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response', undefined, true);
|
|
730
|
+
}
|
|
731
|
+
const remoteId = this.optionalIdentifier(entry.id);
|
|
732
|
+
if (remoteId !== entryId) {
|
|
733
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response', undefined, true);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async listOwnTimeEntryIdsInRange(credentials, _context, remoteTaskId, startedAfterMs, startedBeforeMs) {
|
|
737
|
+
const token = this.requireToken(credentials);
|
|
738
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
739
|
+
const ownerId = await this.getCurrentOwnerRemoteId(credentials);
|
|
740
|
+
const workspaceId = await this.loadTaskWorkspace(token, taskId);
|
|
741
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/team/${encodeURIComponent(workspaceId)}/time_entries`);
|
|
742
|
+
url.searchParams.set('start_date', String(startedAfterMs));
|
|
743
|
+
url.searchParams.set('end_date', String(startedBeforeMs));
|
|
744
|
+
url.searchParams.set('task_id', taskId);
|
|
745
|
+
url.searchParams.append('assignee_ids[]', ownerId);
|
|
746
|
+
const payload = await this.requestJson(token, url.toString());
|
|
747
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !Array.isArray(payload.data)) {
|
|
748
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
749
|
+
}
|
|
750
|
+
const ids = [];
|
|
751
|
+
for (const value of payload.data) {
|
|
752
|
+
if (!(0, vendor_shared_1.isRecord)(value)) {
|
|
753
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
754
|
+
}
|
|
755
|
+
ids.push(this.validate.requiredIdentifier(value.id));
|
|
756
|
+
}
|
|
757
|
+
return { ids, complete: false };
|
|
758
|
+
}
|
|
759
|
+
async assertTimeEntryDeletable(credentials, context, remoteTaskId, remoteEntryId) {
|
|
760
|
+
const now = Date.now();
|
|
761
|
+
const range = await this.listOwnTimeEntryIdsInRange(credentials, context, remoteTaskId, now - external_provider_models_1.TIME_ENTRY_HISTORY_WINDOW_DAYS * 86_400_000, now);
|
|
762
|
+
if (!range.ids.includes(remoteEntryId)) {
|
|
763
|
+
throw new external_provider_errors_1.ClickUpProviderError('not_found');
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
async getTaskTimeEntryHistory(credentials, _context, remoteTaskId) {
|
|
767
|
+
const token = this.requireToken(credentials);
|
|
768
|
+
const taskId = this.validate.requiredTaskId(remoteTaskId);
|
|
769
|
+
const ownerId = await this.getCurrentOwnerRemoteId(credentials);
|
|
770
|
+
const task = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/task/${encodeURIComponent(taskId)}`);
|
|
771
|
+
if (!(0, vendor_shared_1.isRecord)(task) || this.validate.requiredIdentifier(task.id) !== taskId) {
|
|
772
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
773
|
+
}
|
|
774
|
+
const workspaceId = this.validate.requiredIdentifier(task.team_id);
|
|
775
|
+
const now = Date.now();
|
|
776
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/team/${encodeURIComponent(workspaceId)}/time_entries`);
|
|
777
|
+
url.searchParams.set('start_date', String(now - external_provider_models_1.TIME_ENTRY_HISTORY_WINDOW_DAYS * 86_400_000));
|
|
778
|
+
url.searchParams.set('end_date', String(now));
|
|
779
|
+
url.searchParams.set('task_id', taskId);
|
|
780
|
+
url.searchParams.append('assignee_ids[]', ownerId);
|
|
781
|
+
const payload = await this.requestJson(token, url.toString());
|
|
782
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !Array.isArray(payload.data)) {
|
|
783
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
784
|
+
}
|
|
785
|
+
const entries = [];
|
|
786
|
+
let hasRunningTimer = false;
|
|
787
|
+
for (const value of payload.data) {
|
|
788
|
+
const normalized = this.normalizeTimeEntry(value, ownerId);
|
|
789
|
+
if (normalized.running) {
|
|
790
|
+
hasRunningTimer = true;
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
if (normalized.entry) {
|
|
794
|
+
entries.push(normalized.entry);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
this.sortTimeEntries(entries);
|
|
798
|
+
return {
|
|
799
|
+
windowDays: external_provider_models_1.TIME_ENTRY_HISTORY_WINDOW_DAYS,
|
|
800
|
+
truncated: entries.length > external_provider_models_1.MAX_TIME_ENTRY_HISTORY_ENTRIES,
|
|
801
|
+
hasRunningTimer,
|
|
802
|
+
entries: entries.slice(0, external_provider_models_1.MAX_TIME_ENTRY_HISTORY_ENTRIES),
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
normalizeTimeEntry(value, ownerId) {
|
|
806
|
+
if (!(0, vendor_shared_1.isRecord)(value)) {
|
|
807
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
808
|
+
}
|
|
809
|
+
const remoteId = this.validate.requiredIdentifier(value.id);
|
|
810
|
+
const duration = this.numericValue(value.duration);
|
|
811
|
+
if (!Number.isSafeInteger(duration)) {
|
|
812
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
813
|
+
}
|
|
814
|
+
if (duration <= 0) {
|
|
815
|
+
return { entry: null, running: true };
|
|
816
|
+
}
|
|
817
|
+
const start = this.numericValue(value.start);
|
|
818
|
+
let startedAt;
|
|
819
|
+
try {
|
|
820
|
+
startedAt = new Date(start).toISOString();
|
|
821
|
+
}
|
|
822
|
+
catch {
|
|
823
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
824
|
+
}
|
|
825
|
+
const owner = (0, vendor_shared_1.isRecord)(value.user) ? this.validate.requiredIdentifier(value.user.id) : null;
|
|
826
|
+
if (owner === null) {
|
|
827
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
828
|
+
}
|
|
829
|
+
if (owner !== ownerId) {
|
|
830
|
+
return { entry: null, running: false };
|
|
831
|
+
}
|
|
832
|
+
const description = value.description;
|
|
833
|
+
if (description !== null && description !== undefined && typeof description !== 'string') {
|
|
834
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
835
|
+
}
|
|
836
|
+
const note = description ?? '';
|
|
837
|
+
return {
|
|
838
|
+
entry: {
|
|
839
|
+
remoteId,
|
|
840
|
+
durationMs: duration,
|
|
841
|
+
startedAt,
|
|
842
|
+
note: note ? note.slice(0, external_provider_models_1.MAX_TIME_ENTRY_NOTE_LENGTH) : null,
|
|
843
|
+
noteTruncated: note.length > external_provider_models_1.MAX_TIME_ENTRY_NOTE_LENGTH,
|
|
844
|
+
canDelete: true,
|
|
845
|
+
},
|
|
846
|
+
running: false,
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
numericValue(value) {
|
|
850
|
+
const parsed = typeof value === 'number'
|
|
851
|
+
? value
|
|
852
|
+
: typeof value === 'string' && value.trim()
|
|
853
|
+
? Number(value)
|
|
854
|
+
: Number.NaN;
|
|
855
|
+
if (!Number.isFinite(parsed)) {
|
|
856
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
857
|
+
}
|
|
858
|
+
return parsed;
|
|
859
|
+
}
|
|
860
|
+
isNumericValue(value) {
|
|
861
|
+
if (typeof value === 'number') {
|
|
862
|
+
return Number.isFinite(value);
|
|
863
|
+
}
|
|
864
|
+
return typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value));
|
|
865
|
+
}
|
|
866
|
+
optionalIdentifier(value) {
|
|
867
|
+
if ((typeof value !== 'string' && typeof value !== 'number') ||
|
|
868
|
+
(typeof value === 'number' && !Number.isFinite(value)) ||
|
|
869
|
+
!String(value).trim()) {
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
return String(value).trim();
|
|
873
|
+
}
|
|
874
|
+
taskTotalDurationMs(value) {
|
|
875
|
+
if (value === null || value === undefined || value === '') {
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
const total = this.numericValue(value);
|
|
879
|
+
if (!Number.isSafeInteger(total) || total < 0) {
|
|
880
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
881
|
+
}
|
|
882
|
+
return total;
|
|
883
|
+
}
|
|
884
|
+
sortTimeEntries(entries) {
|
|
885
|
+
entries.sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt) ||
|
|
886
|
+
(0, vendor_shared_1.compareRemoteIds)(left.remoteId, right.remoteId));
|
|
887
|
+
}
|
|
888
|
+
async discoverMyWork(credentials, options) {
|
|
889
|
+
const account = await this.verifyCredentials(credentials);
|
|
890
|
+
const workspaces = await this.loadWorkspaces(credentials.token);
|
|
891
|
+
const now = Date.now();
|
|
892
|
+
const cutoff = now - vendor_shared_1.RECENT_COMPLETED_WINDOW_MS;
|
|
893
|
+
const tasks = new Map();
|
|
894
|
+
const workspacePages = await (0, vendor_shared_1.mapWithConcurrency)(workspaces, vendor_shared_1.VENDOR_DISCOVERY_CONCURRENCY, async (workspace) => {
|
|
895
|
+
const [active, completed] = await Promise.all([
|
|
896
|
+
this.loadTaskPages(credentials.token, workspace, account.remoteId, {
|
|
897
|
+
includeCompleted: false,
|
|
898
|
+
cutoff,
|
|
899
|
+
now,
|
|
900
|
+
}),
|
|
901
|
+
options.includeCompleted
|
|
902
|
+
? this.loadTaskPages(credentials.token, workspace, account.remoteId, {
|
|
903
|
+
includeCompleted: true,
|
|
904
|
+
cutoff,
|
|
905
|
+
now,
|
|
906
|
+
})
|
|
907
|
+
: Promise.resolve([]),
|
|
908
|
+
]);
|
|
909
|
+
return [...active, ...completed];
|
|
910
|
+
});
|
|
911
|
+
for (const page of workspacePages) {
|
|
912
|
+
this.addTasks(tasks, page);
|
|
913
|
+
}
|
|
914
|
+
const enriched = await this.enrichWorkAreas(credentials.token, options, [...tasks.values()]);
|
|
915
|
+
return {
|
|
916
|
+
capabilities: { timeTrackingEnabled: true },
|
|
917
|
+
workAreas: enriched.workAreas,
|
|
918
|
+
tasks: enriched.tasks,
|
|
919
|
+
refreshedAt: new Date().toISOString(),
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
async loadWorkspaces(token) {
|
|
923
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/team`);
|
|
924
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !Array.isArray(payload.teams)) {
|
|
925
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
926
|
+
}
|
|
927
|
+
return payload.teams.map((value) => {
|
|
928
|
+
if (!(0, vendor_shared_1.isRecord)(value)) {
|
|
929
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
930
|
+
}
|
|
931
|
+
const id = this.validate.requiredIdentifier(value.id);
|
|
932
|
+
const name = this.validate.requiredString(value.name);
|
|
933
|
+
return { id, name };
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
async loadTaskPages(token, workspace, ownerId, filter) {
|
|
937
|
+
const result = [];
|
|
938
|
+
for (let page = 0; page < CLICKUP_MAX_TASK_PAGES; page += 1) {
|
|
939
|
+
const url = new URL(`${CLICKUP_ORIGIN}/api/v2/team/${encodeURIComponent(workspace.id)}/task`);
|
|
940
|
+
url.searchParams.set('page', String(page));
|
|
941
|
+
url.searchParams.set('order_by', 'id');
|
|
942
|
+
url.searchParams.set('subtasks', 'true');
|
|
943
|
+
url.searchParams.append('assignees[]', ownerId);
|
|
944
|
+
url.searchParams.set('include_closed', String(filter.includeCompleted));
|
|
945
|
+
if (filter.includeCompleted) {
|
|
946
|
+
url.searchParams.set('date_done_gt', String(filter.cutoff));
|
|
947
|
+
url.searchParams.set('date_done_lt', String(filter.now));
|
|
948
|
+
}
|
|
949
|
+
const payload = await this.requestJson(token, url.toString());
|
|
950
|
+
if (!(0, vendor_shared_1.isRecord)(payload) || !Array.isArray(payload.tasks)) {
|
|
951
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
952
|
+
}
|
|
953
|
+
if (payload.tasks.length > CLICKUP_TASK_PAGE_SIZE) {
|
|
954
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
955
|
+
}
|
|
956
|
+
for (const value of payload.tasks) {
|
|
957
|
+
const task = this.normalizeTask(value, workspace, ownerId);
|
|
958
|
+
if (!task) {
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (filter.includeCompleted) {
|
|
962
|
+
if (task.task.status.category !== 'completed' ||
|
|
963
|
+
task.task.completedAt === null ||
|
|
964
|
+
Date.parse(task.task.completedAt) < filter.cutoff ||
|
|
965
|
+
Date.parse(task.task.completedAt) > filter.now) {
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
else if (task.task.status.category === 'completed') {
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
result.push(task);
|
|
973
|
+
}
|
|
974
|
+
if (payload.tasks.length < CLICKUP_TASK_PAGE_SIZE) {
|
|
975
|
+
return result;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
979
|
+
}
|
|
980
|
+
normalizeTask(value, workspace, ownerId) {
|
|
981
|
+
if (!(0, vendor_shared_1.isRecord)(value) ||
|
|
982
|
+
!(0, vendor_shared_1.isRecord)(value.status) ||
|
|
983
|
+
!(0, vendor_shared_1.isRecord)(value.list) ||
|
|
984
|
+
!Array.isArray(value.assignees)) {
|
|
985
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
986
|
+
}
|
|
987
|
+
const assignedToOwner = value.assignees.some((assignee) => (0, vendor_shared_1.isRecord)(assignee) &&
|
|
988
|
+
(typeof assignee.id === 'string' || typeof assignee.id === 'number') &&
|
|
989
|
+
String(assignee.id) === ownerId);
|
|
990
|
+
if (!assignedToOwner) {
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
const remoteId = this.validate.requiredIdentifier(value.id);
|
|
994
|
+
const statusType = this.validate.requiredString(value.status.type).toLowerCase();
|
|
995
|
+
const completedAt = this.optionalTimestamp(value.date_done ?? value.date_closed);
|
|
996
|
+
const workArea = {
|
|
997
|
+
remoteId: this.validate.requiredIdentifier(value.list.id),
|
|
998
|
+
scopeKey: workspace.id,
|
|
999
|
+
name: this.validate.requiredString(value.list.name),
|
|
1000
|
+
kind: 'list',
|
|
1001
|
+
description: null,
|
|
1002
|
+
assignedTaskCount: 0,
|
|
1003
|
+
hierarchy: [{ kind: 'workspace', remoteId: workspace.id, name: workspace.name }],
|
|
1004
|
+
workflow: { isOverridden: false, columns: [] },
|
|
1005
|
+
refresh: {
|
|
1006
|
+
state: 'error',
|
|
1007
|
+
refreshedAt: null,
|
|
1008
|
+
retryable: true,
|
|
1009
|
+
retryAt: null,
|
|
1010
|
+
},
|
|
1011
|
+
};
|
|
1012
|
+
return {
|
|
1013
|
+
workArea,
|
|
1014
|
+
task: {
|
|
1015
|
+
remoteId,
|
|
1016
|
+
parentRemoteTaskId: this.optionalTaskParentId(value.parent),
|
|
1017
|
+
title: this.validate.requiredString(value.name),
|
|
1018
|
+
status: {
|
|
1019
|
+
remoteId: value.status.id === null || value.status.id === undefined
|
|
1020
|
+
? null
|
|
1021
|
+
: this.validate.requiredIdentifier(value.status.id),
|
|
1022
|
+
name: this.validate.requiredString(value.status.status),
|
|
1023
|
+
category: this.classifyStatus(statusType),
|
|
1024
|
+
},
|
|
1025
|
+
updatedAt: this.requiredTimestamp(value.date_updated),
|
|
1026
|
+
dueAt: this.optionalTimestamp(value.due_date),
|
|
1027
|
+
completedAt,
|
|
1028
|
+
webUrl: this.safeTaskUrl(value.url),
|
|
1029
|
+
},
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
normalizeTaskSubtasks(value, parentRemoteTaskId) {
|
|
1033
|
+
if (value === null || value === undefined) {
|
|
1034
|
+
return { items: [], truncated: false };
|
|
1035
|
+
}
|
|
1036
|
+
if (!Array.isArray(value)) {
|
|
1037
|
+
return { items: [], truncated: true };
|
|
1038
|
+
}
|
|
1039
|
+
const items = [];
|
|
1040
|
+
let truncated = false;
|
|
1041
|
+
for (const candidate of value) {
|
|
1042
|
+
if (!(0, vendor_shared_1.isRecord)(candidate)) {
|
|
1043
|
+
truncated = true;
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
const candidateParentId = this.optionalTaskParentId(candidate.parent);
|
|
1047
|
+
if (candidateParentId === null) {
|
|
1048
|
+
truncated = true;
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
if (candidateParentId !== parentRemoteTaskId) {
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
try {
|
|
1055
|
+
items.push(this.normalizeTaskSubtask(candidate));
|
|
1056
|
+
}
|
|
1057
|
+
catch (error) {
|
|
1058
|
+
if (!(error instanceof external_provider_errors_1.ClickUpProviderError)) {
|
|
1059
|
+
throw error;
|
|
1060
|
+
}
|
|
1061
|
+
truncated = true;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
items.sort(vendor_shared_1.compareTaskSubtaskSummaries);
|
|
1065
|
+
return {
|
|
1066
|
+
items: items.slice(0, external_provider_models_1.MAX_TASK_DETAIL_SUBTASKS),
|
|
1067
|
+
truncated: truncated || items.length > external_provider_models_1.MAX_TASK_DETAIL_SUBTASKS,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
normalizeTaskSubtask(value) {
|
|
1071
|
+
if (!(0, vendor_shared_1.isRecord)(value.status)) {
|
|
1072
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1073
|
+
}
|
|
1074
|
+
const remoteId = this.validate.requiredIdentifier(value.id);
|
|
1075
|
+
const customId = value.custom_id;
|
|
1076
|
+
if (customId !== null && customId !== undefined && typeof customId !== 'string') {
|
|
1077
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1078
|
+
}
|
|
1079
|
+
return {
|
|
1080
|
+
remoteId,
|
|
1081
|
+
remoteKey: typeof customId === 'string' && customId.trim() ? customId.trim() : remoteId,
|
|
1082
|
+
title: this.validate.requiredString(value.name),
|
|
1083
|
+
status: {
|
|
1084
|
+
remoteId: value.status.id === null || value.status.id === undefined
|
|
1085
|
+
? null
|
|
1086
|
+
: this.validate.requiredIdentifier(value.status.id),
|
|
1087
|
+
name: this.validate.requiredString(value.status.status),
|
|
1088
|
+
category: this.classifyStatus(this.validate.requiredString(value.status.type).toLowerCase()),
|
|
1089
|
+
},
|
|
1090
|
+
webUrl: this.safeTaskUrl(value.url),
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
optionalTaskParentId(value) {
|
|
1094
|
+
if (value === null || value === undefined || value === '') {
|
|
1095
|
+
return null;
|
|
1096
|
+
}
|
|
1097
|
+
try {
|
|
1098
|
+
return this.validate.requiredIdentifier(value);
|
|
1099
|
+
}
|
|
1100
|
+
catch (error) {
|
|
1101
|
+
if (error instanceof external_provider_errors_1.ClickUpProviderError) {
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
throw error;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
addTasks(tasks, additions) {
|
|
1108
|
+
for (const item of additions) {
|
|
1109
|
+
const taskKey = `${item.workArea.scopeKey}:${item.task.remoteId}`;
|
|
1110
|
+
if (!tasks.has(taskKey)) {
|
|
1111
|
+
tasks.set(taskKey, item);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
async enrichWorkAreas(token, options, tasks) {
|
|
1116
|
+
const groups = new Map();
|
|
1117
|
+
for (const item of tasks) {
|
|
1118
|
+
const key = this.workAreaKey(item.workArea);
|
|
1119
|
+
const existing = groups.get(key);
|
|
1120
|
+
if (existing) {
|
|
1121
|
+
existing.assignedTaskCount += 1;
|
|
1122
|
+
}
|
|
1123
|
+
else {
|
|
1124
|
+
groups.set(key, { base: item.workArea, assignedTaskCount: 1 });
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
const groupEntries = [...groups];
|
|
1128
|
+
const enriched = await (0, vendor_shared_1.mapWithConcurrency)(groupEntries, vendor_shared_1.VENDOR_DISCOVERY_CONCURRENCY, ([, group]) => this.loadWorkAreaMetadata(token, options, group.base, group.assignedTaskCount));
|
|
1129
|
+
const enrichedByKey = new Map(groupEntries.map(([key], index) => [key, enriched[index]]));
|
|
1130
|
+
return {
|
|
1131
|
+
workAreas: [...enrichedByKey.values()],
|
|
1132
|
+
tasks: tasks.map((item) => ({
|
|
1133
|
+
workArea: enrichedByKey.get(this.workAreaKey(item.workArea)),
|
|
1134
|
+
task: item.task,
|
|
1135
|
+
})),
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
async loadWorkAreaMetadata(token, options, base, assignedTaskCount) {
|
|
1139
|
+
const cacheKey = JSON.stringify([
|
|
1140
|
+
options.connectionId,
|
|
1141
|
+
options.connectionGeneration,
|
|
1142
|
+
base.scopeKey,
|
|
1143
|
+
base.remoteId,
|
|
1144
|
+
]);
|
|
1145
|
+
const cached = this.listMetadataCache.get(cacheKey);
|
|
1146
|
+
const now = Date.now();
|
|
1147
|
+
if (cached && now - cached.fetchedAt <= vendor_shared_1.WORK_AREA_METADATA_TTL_MS) {
|
|
1148
|
+
return (0, vendor_shared_1.materializeWorkArea)(cached.value, assignedTaskCount, {
|
|
1149
|
+
state: 'fresh',
|
|
1150
|
+
refreshedAt: new Date(cached.fetchedAt).toISOString(),
|
|
1151
|
+
retryable: false,
|
|
1152
|
+
retryAt: null,
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
try {
|
|
1156
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/list/${encodeURIComponent(base.remoteId)}`);
|
|
1157
|
+
const metadata = this.normalizeListMetadata(payload, base);
|
|
1158
|
+
this.listMetadataCache.set(cacheKey, { value: metadata, fetchedAt: now });
|
|
1159
|
+
return (0, vendor_shared_1.materializeWorkArea)(metadata, assignedTaskCount, {
|
|
1160
|
+
state: 'fresh',
|
|
1161
|
+
refreshedAt: new Date(now).toISOString(),
|
|
1162
|
+
retryable: false,
|
|
1163
|
+
retryAt: null,
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
catch (error) {
|
|
1167
|
+
if (!(error instanceof external_provider_errors_1.ClickUpProviderError)) {
|
|
1168
|
+
throw error;
|
|
1169
|
+
}
|
|
1170
|
+
const retryAt = (0, vendor_shared_1.vendorRetryAt)(error);
|
|
1171
|
+
if (cached) {
|
|
1172
|
+
return (0, vendor_shared_1.materializeWorkArea)(cached.value, assignedTaskCount, {
|
|
1173
|
+
state: 'stale',
|
|
1174
|
+
refreshedAt: new Date(cached.fetchedAt).toISOString(),
|
|
1175
|
+
retryable: true,
|
|
1176
|
+
retryAt,
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
return {
|
|
1180
|
+
...base,
|
|
1181
|
+
assignedTaskCount,
|
|
1182
|
+
refresh: { state: 'error', refreshedAt: null, retryable: true, retryAt },
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
normalizeListMetadata(value, base) {
|
|
1187
|
+
if (!(0, vendor_shared_1.isRecord)(value) ||
|
|
1188
|
+
!(0, vendor_shared_1.isRecord)(value.space) ||
|
|
1189
|
+
!Array.isArray(value.statuses) ||
|
|
1190
|
+
typeof value.override_statuses !== 'boolean') {
|
|
1191
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1192
|
+
}
|
|
1193
|
+
const remoteId = this.validate.requiredIdentifier(value.id);
|
|
1194
|
+
if (remoteId !== base.remoteId) {
|
|
1195
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1196
|
+
}
|
|
1197
|
+
const hierarchy = [
|
|
1198
|
+
...base.hierarchy.filter((location) => location.kind === 'workspace'),
|
|
1199
|
+
{
|
|
1200
|
+
kind: 'space',
|
|
1201
|
+
remoteId: this.validate.requiredIdentifier(value.space.id),
|
|
1202
|
+
name: this.validate.requiredString(value.space.name),
|
|
1203
|
+
},
|
|
1204
|
+
];
|
|
1205
|
+
if (value.folder !== null && value.folder !== undefined) {
|
|
1206
|
+
if (!(0, vendor_shared_1.isRecord)(value.folder)) {
|
|
1207
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1208
|
+
}
|
|
1209
|
+
hierarchy.push({
|
|
1210
|
+
kind: 'folder',
|
|
1211
|
+
remoteId: this.validate.requiredIdentifier(value.folder.id),
|
|
1212
|
+
name: this.validate.requiredString(value.folder.name),
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
const columns = this.sortedColumns(value.statuses);
|
|
1216
|
+
return {
|
|
1217
|
+
remoteId,
|
|
1218
|
+
scopeKey: base.scopeKey,
|
|
1219
|
+
name: this.validate.requiredString(value.name),
|
|
1220
|
+
kind: 'list',
|
|
1221
|
+
description: this.optionalDescription(value.content),
|
|
1222
|
+
hierarchy,
|
|
1223
|
+
workflow: { isOverridden: value.override_statuses, columns },
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
normalizeColumn(value) {
|
|
1227
|
+
if (!(0, vendor_shared_1.isRecord)(value)) {
|
|
1228
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1229
|
+
}
|
|
1230
|
+
if ((typeof value.orderindex !== 'string' && typeof value.orderindex !== 'number') ||
|
|
1231
|
+
(typeof value.orderindex === 'string' && !value.orderindex.trim())) {
|
|
1232
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1233
|
+
}
|
|
1234
|
+
const position = Number(value.orderindex);
|
|
1235
|
+
if (!Number.isFinite(position)) {
|
|
1236
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1237
|
+
}
|
|
1238
|
+
return {
|
|
1239
|
+
remoteId: value.id === null || value.id === undefined
|
|
1240
|
+
? null
|
|
1241
|
+
: this.validate.requiredIdentifier(value.id),
|
|
1242
|
+
name: this.requiredExactString(value.status),
|
|
1243
|
+
color: this.requiredExactString(value.color),
|
|
1244
|
+
category: this.classifyStatus(this.validate.requiredString(value.type).toLowerCase()),
|
|
1245
|
+
position,
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
async loadAllowedStatuses(token, workAreaId) {
|
|
1249
|
+
const payload = await this.requestJson(token, `${CLICKUP_ORIGIN}/api/v2/list/${encodeURIComponent(workAreaId)}`);
|
|
1250
|
+
if (!(0, vendor_shared_1.isRecord)(payload) ||
|
|
1251
|
+
this.validate.requiredIdentifier(payload.id) !== workAreaId ||
|
|
1252
|
+
!Array.isArray(payload.statuses)) {
|
|
1253
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1254
|
+
}
|
|
1255
|
+
return this.sortedColumns(payload.statuses).map((column) => ({
|
|
1256
|
+
actionValue: column.name,
|
|
1257
|
+
...(column.remoteId !== null ? { remoteStatusIds: [column.remoteId] } : {}),
|
|
1258
|
+
remoteId: column.remoteId,
|
|
1259
|
+
name: column.name,
|
|
1260
|
+
color: column.color,
|
|
1261
|
+
category: column.category,
|
|
1262
|
+
position: column.position,
|
|
1263
|
+
}));
|
|
1264
|
+
}
|
|
1265
|
+
sortedColumns(statuses) {
|
|
1266
|
+
return statuses
|
|
1267
|
+
.map((status, index) => ({ column: this.normalizeColumn(status), index }))
|
|
1268
|
+
.sort((left, right) => left.column.position - right.column.position || left.index - right.index)
|
|
1269
|
+
.map(({ column }) => column);
|
|
1270
|
+
}
|
|
1271
|
+
boundedTaskDescription(value) {
|
|
1272
|
+
if (value === null || value === undefined || value === '') {
|
|
1273
|
+
return { value: null, truncated: false };
|
|
1274
|
+
}
|
|
1275
|
+
if (typeof value !== 'string') {
|
|
1276
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1277
|
+
}
|
|
1278
|
+
return {
|
|
1279
|
+
value: value.slice(0, external_provider_models_1.MAX_TASK_DETAIL_TEXT_LENGTH),
|
|
1280
|
+
truncated: value.length > external_provider_models_1.MAX_TASK_DETAIL_TEXT_LENGTH,
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
normalizePriority(value) {
|
|
1284
|
+
if (value === null || value === undefined) {
|
|
1285
|
+
return null;
|
|
1286
|
+
}
|
|
1287
|
+
if (!(0, vendor_shared_1.isRecord)(value)) {
|
|
1288
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1289
|
+
}
|
|
1290
|
+
return {
|
|
1291
|
+
name: this.requiredExactString(value.priority),
|
|
1292
|
+
color: this.requiredExactString(value.color),
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
requiredTaskUrl(value) {
|
|
1296
|
+
const url = this.safeTaskUrl(value);
|
|
1297
|
+
if (!url) {
|
|
1298
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1299
|
+
}
|
|
1300
|
+
return url;
|
|
1301
|
+
}
|
|
1302
|
+
workAreaKey(workArea) {
|
|
1303
|
+
return JSON.stringify([workArea.scopeKey, workArea.remoteId]);
|
|
1304
|
+
}
|
|
1305
|
+
optionalDescription(value) {
|
|
1306
|
+
if (value === null || value === undefined || value === '') {
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
if (typeof value !== 'string') {
|
|
1310
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1311
|
+
}
|
|
1312
|
+
return value;
|
|
1313
|
+
}
|
|
1314
|
+
requiredExactString(value) {
|
|
1315
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
1316
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1317
|
+
}
|
|
1318
|
+
return value;
|
|
1319
|
+
}
|
|
1320
|
+
requireToken(credentials) {
|
|
1321
|
+
if (credentials.provider !== this.provider || !credentials.token.trim()) {
|
|
1322
|
+
throw new external_provider_errors_1.ClickUpProviderError('request_rejected');
|
|
1323
|
+
}
|
|
1324
|
+
return credentials.token;
|
|
1325
|
+
}
|
|
1326
|
+
classifyStatus(value) {
|
|
1327
|
+
if (value === 'open' || value === 'custom') {
|
|
1328
|
+
return 'active';
|
|
1329
|
+
}
|
|
1330
|
+
if (value === 'done' || value === 'closed') {
|
|
1331
|
+
return 'completed';
|
|
1332
|
+
}
|
|
1333
|
+
return 'unknown';
|
|
1334
|
+
}
|
|
1335
|
+
requiredTimestamp(value) {
|
|
1336
|
+
const timestamp = this.optionalTimestamp(value);
|
|
1337
|
+
if (!timestamp) {
|
|
1338
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1339
|
+
}
|
|
1340
|
+
return timestamp;
|
|
1341
|
+
}
|
|
1342
|
+
optionalTimestamp(value) {
|
|
1343
|
+
if (value === null || value === undefined) {
|
|
1344
|
+
return null;
|
|
1345
|
+
}
|
|
1346
|
+
if (typeof value !== 'string' && typeof value !== 'number') {
|
|
1347
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1348
|
+
}
|
|
1349
|
+
if ((typeof value === 'string' && !value.trim()) || !Number.isFinite(Number(value))) {
|
|
1350
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1351
|
+
}
|
|
1352
|
+
const milliseconds = Number(value);
|
|
1353
|
+
try {
|
|
1354
|
+
return new Date(milliseconds).toISOString();
|
|
1355
|
+
}
|
|
1356
|
+
catch {
|
|
1357
|
+
throw new external_provider_errors_1.ClickUpProviderError('invalid_response');
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
safeTaskUrl(value) {
|
|
1361
|
+
return (0, external_task_source_1.normalizeExternalTaskSourceUrl)(this.provider, value);
|
|
1362
|
+
}
|
|
1363
|
+
async requestJson(token, url, request = {}) {
|
|
1364
|
+
try {
|
|
1365
|
+
return await this.http.requestJson({
|
|
1366
|
+
url,
|
|
1367
|
+
allowedOrigins: [CLICKUP_ORIGIN],
|
|
1368
|
+
...(request.method ? { method: request.method } : {}),
|
|
1369
|
+
...(request.body !== undefined ? { body: request.body } : {}),
|
|
1370
|
+
headers: {
|
|
1371
|
+
accept: 'application/json',
|
|
1372
|
+
authorization: token,
|
|
1373
|
+
...(request.body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
1374
|
+
},
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
catch (error) {
|
|
1378
|
+
throw (0, vendor_shared_1.mapVendorTransportError)(error, (reason, retryAt, dispatched) => new external_provider_errors_1.ClickUpProviderError(reason, retryAt, dispatched));
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
async requestNoContent(token, url, request) {
|
|
1382
|
+
try {
|
|
1383
|
+
await this.http.requestNoContent({
|
|
1384
|
+
url,
|
|
1385
|
+
allowedOrigins: [CLICKUP_ORIGIN],
|
|
1386
|
+
...request,
|
|
1387
|
+
headers: {
|
|
1388
|
+
accept: 'application/json',
|
|
1389
|
+
authorization: token,
|
|
1390
|
+
...(request.body === undefined ? {} : { 'content-type': 'application/json' }),
|
|
1391
|
+
},
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
catch (error) {
|
|
1395
|
+
throw (0, vendor_shared_1.mapVendorTransportError)(error, (reason, retryAt, dispatched) => new external_provider_errors_1.ClickUpProviderError(reason, retryAt, dispatched));
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
exports.ClickUpExternalTaskProvider = ClickUpExternalTaskProvider;
|
|
1400
|
+
exports.ClickUpExternalTaskProvider = ClickUpExternalTaskProvider = __decorate([
|
|
1401
|
+
(0, common_1.Injectable)(),
|
|
1402
|
+
__metadata("design:paramtypes", [safe_vendor_http_client_1.SafeVendorHttpClient])
|
|
1403
|
+
], ClickUpExternalTaskProvider);
|
|
1404
|
+
//# sourceMappingURL=clickup-external-task.provider.js.map
|