@elevasis/core 0.7.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/test-utils/index.d.ts +3122 -0
- package/dist/test-utils/index.js +386 -0
- package/package.json +6 -1
- package/src/README.md +39 -36
- package/src/__tests__/publish.test.ts +18 -13
- package/src/__tests__/{template-foundations-compatibility.test.ts → template-core-compatibility.test.ts} +99 -99
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +1135 -1131
- package/src/_gen/__tests__/scaffold-contracts.test.ts +47 -36
- package/src/_gen/scaffold-contracts.ts +45 -45
- package/src/auth/multi-tenancy/credentials/README.md +38 -38
- package/src/auth/multi-tenancy/credentials/index.ts +6 -6
- package/src/auth/multi-tenancy/credentials/server/encryption.ts +39 -39
- package/src/auth/multi-tenancy/credentials/server/service.ts +60 -60
- package/src/auth/multi-tenancy/index.ts +17 -17
- package/src/auth/multi-tenancy/invitations/api-schemas.ts +107 -107
- package/src/auth/multi-tenancy/invitations/index.ts +37 -37
- package/src/auth/multi-tenancy/invitations/invitation.ts +86 -86
- package/src/auth/multi-tenancy/invitations/server/index.ts +25 -25
- package/src/auth/multi-tenancy/invitations/server/transforms.ts +24 -24
- package/src/auth/multi-tenancy/invitations/server/workos.ts +24 -24
- package/src/auth/multi-tenancy/invitations/supabase.ts +50 -50
- package/src/auth/multi-tenancy/memberships/api-schemas.ts +126 -126
- package/src/auth/multi-tenancy/memberships/index.ts +21 -21
- package/src/auth/multi-tenancy/memberships/membership.ts +138 -138
- package/src/auth/multi-tenancy/memberships/server/index.ts +15 -15
- package/src/auth/multi-tenancy/memberships/server/transforms.ts +32 -32
- package/src/auth/multi-tenancy/memberships/server/workos.ts +21 -21
- package/src/auth/multi-tenancy/memberships/supabase.ts +46 -46
- package/src/auth/multi-tenancy/organizations/api-schemas.ts +128 -128
- package/src/auth/multi-tenancy/organizations/index.ts +23 -23
- package/src/auth/multi-tenancy/organizations/organization.ts +24 -24
- package/src/auth/multi-tenancy/organizations/server/index.ts +10 -10
- package/src/auth/multi-tenancy/organizations/server/transforms.ts +35 -35
- package/src/auth/multi-tenancy/organizations/server/workos.ts +20 -20
- package/src/auth/multi-tenancy/types.ts +83 -83
- package/src/auth/multi-tenancy/users/api-schemas.ts +194 -194
- package/src/auth/multi-tenancy/users/index.ts +27 -27
- package/src/auth/multi-tenancy/users/server/index.ts +19 -19
- package/src/auth/multi-tenancy/users/server/transforms.ts +21 -21
- package/src/auth/multi-tenancy/users/server/workos.ts +16 -16
- package/src/auth/multi-tenancy/users/user.ts +65 -65
- package/src/business/README.md +52 -52
- package/src/business/__tests__/entities-published.test.ts +33 -33
- package/src/business/acquisition/api-schemas.ts +759 -759
- package/src/business/acquisition/index.ts +109 -109
- package/src/business/acquisition/types.ts +402 -402
- package/src/business/base-entities.test.ts +481 -481
- package/src/business/base-entities.ts +241 -241
- package/src/business/entities-published.ts +24 -24
- package/src/business/index.ts +15 -15
- package/src/business/pdf/browser/pdfmake-browser.ts +229 -229
- package/src/business/pdf/index.ts +10 -10
- package/src/business/pdf/server/index.ts +21 -21
- package/src/business/pdf/server/themes/default.ts +8 -8
- package/src/business/pdf/server/themes/index.ts +9 -9
- package/src/business/pdf/server/themes/types.ts +8 -8
- package/src/business/pdf/types.ts +272 -272
- package/src/business/projects/index.ts +2 -2
- package/src/business/projects/sse-events.ts +21 -21
- package/src/business/projects/types.ts +89 -89
- package/src/business/sales/api-schemas.ts +75 -75
- package/src/business/seo/__tests__/linking.test.ts +549 -549
- package/src/business/seo/__tests__/types.test.ts +404 -404
- package/src/business/seo/index.ts +2 -2
- package/src/business/seo/linking.ts +281 -281
- package/src/business/seo/types.ts +199 -199
- package/src/commands/queue/index.ts +3 -3
- package/src/commands/queue/schemas.test.ts +593 -593
- package/src/commands/queue/schemas.ts +125 -125
- package/src/commands/queue/sse-events.ts +61 -61
- package/src/commands/queue/types/action.ts +52 -52
- package/src/commands/queue/types/checkpoint.ts +44 -44
- package/src/commands/queue/types/index.ts +7 -7
- package/src/commands/queue/types/task.ts +116 -116
- package/src/commands/queue/types.ts +14 -14
- package/src/content/distribution-metadata.ts +61 -61
- package/src/content/index.ts +10 -10
- package/src/deployments/index.ts +22 -22
- package/src/execution/core/__tests__/archived-logs.test.ts +72 -72
- package/src/execution/core/index.ts +11 -11
- package/src/execution/core/runner-types.ts +80 -80
- package/src/execution/core/server/environment.ts +31 -31
- package/src/execution/core/sse-executions.ts +119 -119
- package/src/execution/core/types.ts +29 -29
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +4 -4
- package/src/execution/engine/__tests__/timeout.test.ts +565 -565
- package/src/execution/engine/agent/__tests__/errors.test.ts +508 -508
- package/src/execution/engine/agent/actions/__tests__/processor.test.ts +531 -531
- package/src/execution/engine/agent/actions/executor.ts +205 -205
- package/src/execution/engine/agent/actions/navigate-knowledge-executor.ts +230 -230
- package/src/execution/engine/agent/actions/processor.ts +116 -116
- package/src/execution/engine/agent/actions/types.ts +70 -70
- package/src/execution/engine/agent/core/agent.ts +810 -810
- package/src/execution/engine/agent/core/types.ts +155 -155
- package/src/execution/engine/agent/errors.ts +251 -251
- package/src/execution/engine/agent/index.ts +78 -78
- package/src/execution/engine/agent/knowledge-map/types.ts +106 -106
- package/src/execution/engine/agent/knowledge-map/utils.ts +101 -101
- package/src/execution/engine/agent/memory/__tests__/manager.test.ts +754 -754
- package/src/execution/engine/agent/memory/domains.ts +99 -99
- package/src/execution/engine/agent/memory/manager.ts +365 -365
- package/src/execution/engine/agent/memory/processor.ts +66 -66
- package/src/execution/engine/agent/memory/types.ts +90 -90
- package/src/execution/engine/agent/memory/utils.ts +134 -134
- package/src/execution/engine/agent/observability/logging.ts +467 -467
- package/src/execution/engine/agent/observability/types.ts +64 -64
- package/src/execution/engine/agent/reasoning/adapters/agent-adapter-helpers.ts +349 -349
- package/src/execution/engine/agent/reasoning/processor.ts +92 -92
- package/src/execution/engine/agent/reasoning/prompt-sections/base-actions.ts +134 -134
- package/src/execution/engine/agent/reasoning/prompt-sections/completion.ts +49 -49
- package/src/execution/engine/agent/reasoning/prompt-sections/knowledge-map.ts +93 -93
- package/src/execution/engine/agent/reasoning/prompt-sections/memory.ts +65 -65
- package/src/execution/engine/agent/reasoning/prompt-sections/tools.ts +44 -44
- package/src/execution/engine/agent/reasoning/request-builder.ts +169 -169
- package/src/execution/engine/agent/reasoning/types.ts +18 -18
- package/src/execution/engine/base/errors.ts +118 -118
- package/src/execution/engine/base/index.ts +2 -2
- package/src/execution/engine/base/logging.ts +31 -31
- package/src/execution/engine/base/serialization.ts +324 -324
- package/src/execution/engine/base/types.ts +126 -126
- package/src/execution/engine/base/utils.ts +41 -41
- package/src/execution/engine/index.ts +434 -434
- package/src/execution/engine/interface/index.ts +1 -1
- package/src/execution/engine/interface/types.ts +62 -62
- package/src/execution/engine/llm/__tests__/model-info.test.ts +50 -50
- package/src/execution/engine/llm/__tests__/model-validation.test.ts +321 -321
- package/src/execution/engine/llm/__tests__/response-schema-validator.test.ts +115 -115
- package/src/execution/engine/llm/adapters/__tests__/adapter-factory.test.ts +375 -375
- package/src/execution/engine/llm/adapters/__tests__/anthropic-adapter.test.ts +463 -463
- package/src/execution/engine/llm/adapters/__tests__/anthropic.integration.test.ts +177 -177
- package/src/execution/engine/llm/adapters/__tests__/google-adapter.test.ts +722 -722
- package/src/execution/engine/llm/adapters/__tests__/google.integration.test.ts +376 -376
- package/src/execution/engine/llm/adapters/__tests__/openai-adapter.test.ts +551 -551
- package/src/execution/engine/llm/adapters/__tests__/openrouter-adapter.test.ts +563 -563
- package/src/execution/engine/llm/adapters/__tests__/openrouter.integration.test.ts +105 -105
- package/src/execution/engine/llm/adapters/__tests__/universal-adapter.test.ts +537 -537
- package/src/execution/engine/llm/adapters/circuit-breaker.ts +147 -147
- package/src/execution/engine/llm/adapters/index.ts +17 -17
- package/src/execution/engine/llm/adapters/mock-adapter.ts +116 -116
- package/src/execution/engine/llm/adapters/server/adapter-factory.ts +130 -130
- package/src/execution/engine/llm/adapters/server/anthropic.ts +137 -137
- package/src/execution/engine/llm/adapters/server/google.ts +283 -283
- package/src/execution/engine/llm/adapters/server/index.ts +12 -12
- package/src/execution/engine/llm/adapters/server/openai.ts +206 -206
- package/src/execution/engine/llm/adapters/server/openrouter.ts +235 -235
- package/src/execution/engine/llm/adapters/universal-adapter.ts +230 -230
- package/src/execution/engine/llm/errors.ts +186 -186
- package/src/execution/engine/llm/model-info.ts +332 -332
- package/src/execution/engine/llm/response-schema-validator.ts +113 -113
- package/src/execution/engine/llm/types.ts +86 -86
- package/src/execution/engine/test-utils/index.ts +6 -6
- package/src/execution/engine/test-utils/mocks.ts +56 -56
- package/src/execution/engine/tools/integration/base-integration-adapter.ts +50 -50
- package/src/execution/engine/tools/integration/index.ts +53 -53
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/anymailfinder-adapter.ts +73 -73
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/anymailfinder-tools.ts +209 -209
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/find-company-email/index.ts +82 -82
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/find-decision-maker-email/index.ts +122 -122
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/find-person-email/index.ts +89 -89
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/fetch/verify-email/index.ts +84 -84
- package/src/execution/engine/tools/integration/server/adapters/anymailfinder/index.ts +16 -16
- package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +293 -293
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +100 -100
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-tools.ts +217 -217
- package/src/execution/engine/tools/integration/server/adapters/apify/fetch/get-dataset-items/index.ts +92 -92
- package/src/execution/engine/tools/integration/server/adapters/apify/fetch/run-actor/index.ts +218 -218
- package/src/execution/engine/tools/integration/server/adapters/apify/fetch/start-actor/index.ts +87 -87
- package/src/execution/engine/tools/integration/server/adapters/apify/index.ts +11 -11
- package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +361 -361
- package/src/execution/engine/tools/integration/server/adapters/attio/attio-adapter.ts +162 -162
- package/src/execution/engine/tools/integration/server/adapters/attio/attio-tools.ts +594 -594
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/create-attribute/index.ts +214 -214
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/create-note/index.ts +152 -152
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/create-record/index.ts +141 -141
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/delete-note/index.ts +86 -86
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/delete-record/index.ts +105 -105
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.ts +118 -118
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-attributes/index.ts +165 -165
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-notes/index.ts +96 -96
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-objects/index.ts +104 -104
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.ts +156 -156
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/update-attribute/index.ts +220 -220
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/update-record/index.ts +140 -140
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/utils/types.ts +146 -146
- package/src/execution/engine/tools/integration/server/adapters/attio/index.ts +31 -31
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +210 -210
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +104 -104
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/google-sheets-adapter.ts +1189 -1189
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/google-sheets-tools.ts +641 -641
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/index.ts +18 -18
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/activate-campaign/index.ts +86 -86
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/add-to-campaign/__tests__/index.test.ts +289 -289
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/add-to-campaign/index.ts +154 -154
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/bulk-add-leads/__tests__/index.test.ts +325 -325
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/bulk-add-leads/index.ts +153 -153
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/bulk-delete-leads/index.ts +84 -84
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/create-campaign/index.ts +125 -125
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/create-inbox-test/index.ts +107 -107
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/delete-campaign/index.ts +85 -85
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-account-health/index.ts +91 -91
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-campaign/index.ts +92 -92
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-campaign-analytics/__tests__/index.test.ts +195 -195
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-campaign-analytics/index.ts +113 -113
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-daily-campaign-analytics/index.ts +104 -104
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-emails/index.ts +155 -155
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-step-analytics/__tests__/index.test.ts +196 -196
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/get-step-analytics/index.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/list-campaigns/__tests__/index.test.ts +189 -189
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/list-campaigns/index.ts +87 -87
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/list-leads/index.ts +112 -112
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/patch-lead/index.ts +76 -76
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/pause-campaign/index.ts +86 -86
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/remove-from-subsequence/index.ts +98 -98
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/send-reply/index.ts +126 -126
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-campaign/__tests__/index.test.ts +193 -193
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-campaign/index.ts +99 -99
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-interest-status/__tests__/index.test.ts +621 -621
- package/src/execution/engine/tools/integration/server/adapters/instantly/fetch/update-interest-status/index.ts +125 -125
- package/src/execution/engine/tools/integration/server/adapters/instantly/index.ts +29 -29
- package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-adapter.ts +178 -178
- package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1473 -1473
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/fetch/check-credits/index.ts +59 -59
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/fetch/verify-email/index.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/index.ts +17 -17
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-adapter.ts +80 -80
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/get-email/index.ts +102 -102
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +134 -134
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +75 -75
- package/src/execution/engine/tools/integration/server/adapters/resend/index.ts +27 -27
- package/src/execution/engine/tools/integration/server/adapters/resend/resend-adapter.ts +108 -108
- package/src/execution/engine/tools/integration/server/adapters/resend/resend-tools.ts +132 -132
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/create-envelope/index.ts +274 -274
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/download-document/index.ts +230 -230
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/get-envelope/index.ts +133 -133
- package/src/execution/engine/tools/integration/server/adapters/signature-api/fetch/void-envelope/index.ts +90 -90
- package/src/execution/engine/tools/integration/server/adapters/stripe/fetch/utils/types.ts +210 -210
- package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-adapter.ts +517 -517
- package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +309 -309
- package/src/execution/engine/tools/integration/server/adapters/tomba/fetch/domain-search/index.ts +133 -133
- package/src/execution/engine/tools/integration/server/adapters/tomba/fetch/email-finder/index.ts +122 -122
- package/src/execution/engine/tools/integration/server/adapters/tomba/fetch/email-verifier/index.ts +111 -111
- package/src/execution/engine/tools/integration/server/adapters/tomba/index.ts +11 -11
- package/src/execution/engine/tools/integration/server/adapters/tomba/tomba-adapter.ts +78 -78
- package/src/execution/engine/tools/integration/server/adapters/tomba/tomba-tools.ts +222 -222
- package/src/execution/engine/tools/integration/server/index.ts +61 -61
- package/src/execution/engine/tools/integration/service.ts +161 -161
- package/src/execution/engine/tools/integration/tool.ts +253 -253
- package/src/execution/engine/tools/integration/types/anymailfinder.ts +74 -74
- package/src/execution/engine/tools/integration/types/apify.ts +92 -92
- package/src/execution/engine/tools/integration/types/index.ts +19 -19
- package/src/execution/engine/tools/integration/types/instantly.ts +557 -557
- package/src/execution/engine/tools/integration/types/millionverifier.ts +56 -56
- package/src/execution/engine/tools/integration/types/stripe.ts +162 -162
- package/src/execution/engine/tools/integration/types/tomba.ts +94 -94
- package/src/execution/engine/tools/lead-service-types.ts +884 -884
- package/src/execution/engine/tools/llm/index.ts +11 -11
- package/src/execution/engine/tools/llm/server/index.ts +8 -8
- package/src/execution/engine/tools/llm/server/llm-call-tool.ts +118 -118
- package/src/execution/engine/tools/platform/__tests__/pdf.test.ts +441 -441
- package/src/execution/engine/tools/platform/acquisition/company-tools.ts +248 -248
- package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +319 -319
- package/src/execution/engine/tools/platform/acquisition/index.ts +43 -43
- package/src/execution/engine/tools/platform/acquisition/list-tools.ts +148 -148
- package/src/execution/engine/tools/platform/acquisition/types.ts +260 -260
- package/src/execution/engine/tools/platform/email/index.ts +122 -122
- package/src/execution/engine/tools/platform/email/types.ts +96 -96
- package/src/execution/engine/tools/platform/index.ts +157 -157
- package/src/execution/engine/tools/platform/notification.ts +81 -81
- package/src/execution/engine/tools/platform/pdf/index.ts +110 -110
- package/src/execution/engine/tools/platform/pdf/types.ts +77 -77
- package/src/execution/engine/tools/platform/scheduler.ts +87 -87
- package/src/execution/engine/tools/platform/storage/index.ts +370 -370
- package/src/execution/engine/tools/platform/types.ts +148 -148
- package/src/execution/engine/tools/registry.ts +700 -700
- package/src/execution/engine/tools/tool-maps.ts +786 -786
- package/src/execution/engine/tools/types.ts +233 -233
- package/src/execution/engine/workflow/__tests__/errors.test.ts +139 -139
- package/src/execution/engine/workflow/errors.ts +63 -63
- package/src/execution/engine/workflow/helpers/index.ts +11 -11
- package/src/execution/engine/workflow/helpers/server/index.ts +8 -8
- package/src/execution/engine/workflow/helpers/server/llm-call.ts +93 -93
- package/src/execution/engine/workflow/index.ts +19 -19
- package/src/execution/engine/workflow/log-truncate.ts +26 -26
- package/src/execution/engine/workflow/logging.ts +191 -191
- package/src/execution/engine/workflow/types.ts +182 -182
- package/src/execution/engine/workflow/utils.ts +280 -280
- package/src/execution/engine/workflow/workflow.ts +168 -168
- package/src/execution/index.ts +3 -3
- package/src/execution/scheduler/__tests__/api-schemas.test.ts +733 -733
- package/src/execution/scheduler/__tests__/utils.test.ts +1009 -1009
- package/src/execution/scheduler/api-schemas.ts +296 -296
- package/src/execution/scheduler/index.ts +50 -50
- package/src/execution/scheduler/schemas.ts +264 -264
- package/src/execution/scheduler/types.ts +111 -111
- package/src/execution/scheduler/utils.ts +364 -364
- package/src/forms/index.ts +7 -7
- package/src/forms/schemas.ts +69 -69
- package/src/forms/types.ts +70 -70
- package/src/index.ts +71 -60
- package/src/integrations/credentials/__tests__/schemas.test.ts +82 -82
- package/src/integrations/credentials/__tests__/utils.test.ts +144 -144
- package/src/integrations/credentials/api-schemas.ts +143 -143
- package/src/integrations/credentials/index.ts +32 -32
- package/src/integrations/credentials/schemas.ts +164 -164
- package/src/integrations/credentials/utils.ts +59 -59
- package/src/integrations/oauth/__tests__/provider-registry.test.ts +59 -59
- package/src/integrations/oauth/api-schemas.ts +92 -92
- package/src/integrations/oauth/index.ts +19 -19
- package/src/integrations/oauth/provider-registry.ts +61 -61
- package/src/integrations/oauth/server/__tests__/refresh-concurrent.test.ts +183 -183
- package/src/integrations/oauth/server/__tests__/refresh.test.ts +577 -577
- package/src/integrations/oauth/server/credentials.ts +39 -39
- package/src/integrations/oauth/server/refresh.ts +214 -214
- package/src/integrations/oauth/types.ts +34 -34
- package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +318 -318
- package/src/integrations/webhook-endpoints/api-schemas.ts +102 -102
- package/src/integrations/webhook-endpoints/index.ts +28 -28
- package/src/integrations/webhook-endpoints/types.ts +51 -51
- package/src/operations/activities/api-schemas.ts +79 -79
- package/src/operations/activities/index.ts +9 -9
- package/src/operations/activities/sse-events.ts +30 -30
- package/src/operations/activities/types.ts +63 -63
- package/src/operations/debug-logs/client.ts +60 -60
- package/src/operations/debug-logs/debug-logger.ts +83 -83
- package/src/operations/debug-logs/index.ts +8 -8
- package/src/operations/debug-logs/server.ts +19 -19
- package/src/operations/debug-logs/types.ts +33 -33
- package/src/operations/index.ts +50 -50
- package/src/operations/notifications/api-schemas.ts +91 -91
- package/src/operations/notifications/index.ts +3 -3
- package/src/operations/notifications/sse-events.ts +21 -21
- package/src/operations/notifications/types.ts +47 -47
- package/src/operations/observability/__tests__/openrouter-cost-flow.test.ts +297 -297
- package/src/operations/observability/__tests__/utils.test.ts +54 -54
- package/src/operations/observability/ai-usage-collector.ts +64 -64
- package/src/operations/observability/index.ts +13 -13
- package/src/operations/observability/metrics-collector.ts +49 -49
- package/src/operations/observability/schemas.ts +39 -39
- package/src/operations/observability/types.ts +463 -463
- package/src/operations/observability/utils.ts +77 -77
- package/src/operations/sessions/__tests__/manager.test.ts +821 -821
- package/src/operations/sessions/index.ts +26 -26
- package/src/operations/sessions/server/manager.ts +90 -90
- package/src/operations/sessions/server/session.ts +180 -180
- package/src/operations/sessions/types.ts +98 -98
- package/src/operations/triggers/index.ts +12 -12
- package/src/operations/triggers/webhook/definitions/instantly-account-error.ts +44 -44
- package/src/operations/triggers/webhook/definitions/instantly-auto-reply-received.ts +51 -51
- package/src/operations/triggers/webhook/definitions/instantly-campaign-completed.ts +45 -45
- package/src/operations/triggers/webhook/definitions/instantly-email-bounced.ts +49 -49
- package/src/operations/triggers/webhook/definitions/instantly-lead-unsubscribed.ts +45 -45
- package/src/operations/triggers/webhook/definitions/instantly-reply-received.ts +54 -54
- package/src/operations/triggers/webhook/index.ts +35 -35
- package/src/operations/triggers/webhook/types.ts +74 -74
- package/src/organization-model/README.md +97 -97
- package/src/organization-model/__tests__/defaults.test.ts +175 -175
- package/src/organization-model/__tests__/domains/customers.test.ts +295 -295
- package/src/organization-model/__tests__/domains/goals.test.ts +479 -479
- package/src/organization-model/__tests__/domains/identity.test.ts +279 -279
- package/src/organization-model/__tests__/domains/navigation.test.ts +212 -212
- package/src/organization-model/__tests__/domains/offerings.test.ts +419 -419
- package/src/organization-model/__tests__/domains/operations.test.ts +203 -203
- package/src/organization-model/__tests__/domains/resource-mappings.test.ts +362 -362
- package/src/organization-model/__tests__/domains/roles.test.ts +347 -347
- package/src/organization-model/__tests__/domains/statuses.test.ts +243 -243
- package/src/organization-model/__tests__/foundation.test.ts +105 -105
- package/src/organization-model/__tests__/graph.test.ts +894 -894
- package/src/organization-model/__tests__/resolve.test.ts +690 -690
- package/src/organization-model/__tests__/schema.test.ts +407 -407
- package/src/organization-model/contracts.ts +14 -14
- package/src/organization-model/defaults.ts +148 -148
- package/src/organization-model/domains/branding.ts +22 -22
- package/src/organization-model/domains/customers.ts +75 -75
- package/src/organization-model/domains/features.ts +22 -22
- package/src/organization-model/domains/goals.ts +80 -80
- package/src/organization-model/domains/identity.ts +94 -94
- package/src/organization-model/domains/navigation.ts +391 -391
- package/src/organization-model/domains/offerings.ts +66 -66
- package/src/organization-model/domains/operations.ts +85 -85
- package/src/organization-model/domains/projects.ts +48 -48
- package/src/organization-model/domains/prospecting.ts +33 -33
- package/src/organization-model/domains/roles.ts +55 -55
- package/src/organization-model/domains/sales.ts +94 -94
- package/src/organization-model/domains/shared.ts +62 -62
- package/src/organization-model/domains/statuses.ts +130 -130
- package/src/organization-model/foundation.ts +97 -97
- package/src/organization-model/graph/build.ts +399 -399
- package/src/organization-model/graph/index.ts +4 -4
- package/src/organization-model/graph/schema.ts +48 -48
- package/src/organization-model/graph/types.ts +40 -40
- package/src/organization-model/index.ts +13 -13
- package/src/organization-model/organization-graph.mdx +272 -272
- package/src/organization-model/organization-model.mdx +320 -320
- package/src/organization-model/published.ts +85 -85
- package/src/organization-model/resolve.ts +66 -66
- package/src/organization-model/schema.ts +287 -287
- package/src/organization-model/types.ts +46 -46
- package/src/platform/api/index.ts +1 -1
- package/src/platform/api/types.ts +35 -35
- package/src/platform/constants/http.ts +37 -37
- package/src/platform/constants/index.ts +5 -5
- package/src/platform/constants/limits.ts +32 -32
- package/src/platform/constants/resilience.ts +51 -51
- package/src/platform/constants/timeouts.ts +20 -20
- package/src/platform/constants/versions.ts +3 -3
- package/src/platform/registry/__tests__/resource-registry-static.test.ts +347 -347
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +1028 -1028
- package/src/platform/registry/__tests__/resource-registry.list-executable.test.ts +393 -393
- package/src/platform/registry/__tests__/resource-registry.test.ts +2005 -2005
- package/src/platform/registry/__tests__/serialization.test.ts +1127 -1127
- package/src/platform/registry/command-view.ts +180 -180
- package/src/platform/registry/domains.ts +165 -165
- package/src/platform/registry/index.ts +93 -93
- package/src/platform/registry/reserved.ts +24 -24
- package/src/platform/registry/resource-metadata.ts +59 -59
- package/src/platform/registry/resource-registry.command-queue-groups.test.ts +129 -129
- package/src/platform/registry/resource-registry.ts +876 -876
- package/src/platform/registry/serialization.ts +273 -273
- package/src/platform/registry/serialized-types.ts +231 -231
- package/src/platform/registry/stats-types.ts +66 -66
- package/src/platform/registry/types.ts +404 -404
- package/src/platform/registry/validation.ts +513 -513
- package/src/platform/resilience/__tests__/rate-limiter.test.ts +471 -471
- package/src/platform/resilience/circuit-breaker.ts +164 -164
- package/src/platform/resilience/errors.ts +68 -68
- package/src/platform/resilience/http-error-mapper.ts +129 -129
- package/src/platform/resilience/index.ts +93 -93
- package/src/platform/resilience/rate-limiter-types.ts +46 -46
- package/src/platform/resilience/rate-limiter.ts +140 -140
- package/src/platform/resilience/retry.ts +89 -89
- package/src/platform/resilience/timeout.ts +63 -63
- package/src/platform/sse/events.ts +37 -37
- package/src/platform/sse/index.ts +7 -7
- package/src/platform/utils/__tests__/validation.test.ts +1083 -1083
- package/src/platform/utils/currency.ts +96 -96
- package/src/platform/utils/debounce.ts +52 -52
- package/src/platform/utils/error.ts +41 -41
- package/src/platform/utils/hmac.test.ts +97 -97
- package/src/platform/utils/index.ts +32 -32
- package/src/platform/utils/server/betterstack-logger.ts +210 -210
- package/src/platform/utils/server/hmac.ts +44 -44
- package/src/platform/utils/server/unsubscribe.ts +111 -111
- package/src/platform/utils/token-counter.ts +96 -96
- package/src/platform/utils/validation.ts +425 -425
- package/src/projects/api-schemas.ts +268 -268
- package/src/published.ts +1 -1
- package/src/reference/_generated/contracts.md +607 -607
- package/src/reference/glossary.md +105 -105
- package/src/requests/__tests__/api-schemas.test.ts +277 -277
- package/src/requests/api-schemas.ts +83 -83
- package/src/requests/index.ts +1 -1
- package/src/scaffold-registry/__tests__/index.test.ts +17 -0
- package/src/scaffold-registry/__tests__/schema.test.ts +329 -230
- package/src/scaffold-registry/index.ts +205 -189
- package/src/scaffold-registry/schema.ts +196 -128
- package/src/server.ts +272 -272
- package/src/supabase/database.types.ts +2719 -2719
- package/src/supabase/helpers.ts +20 -20
- package/src/supabase/index.ts +52 -52
- package/src/supabase/server/client.ts +58 -58
- package/src/test-utils/README.md +30 -138
- package/src/test-utils/browser-mocks.ts +54 -54
- package/src/test-utils/fixtures/api-keys.ts +52 -52
- package/src/test-utils/fixtures/index.ts +4 -4
- package/src/test-utils/fixtures/memberships.ts +80 -80
- package/src/test-utils/fixtures/organizations.ts +69 -69
- package/src/test-utils/fixtures/users.ts +79 -79
- package/src/test-utils/index.ts +7 -8
- package/src/test-utils/mocks/index.ts +2 -2
- package/src/test-utils/mocks/supabase.ts +142 -142
- package/src/test-utils/mocks/workos.ts +108 -108
- package/src/test-utils/published.ts +4 -0
- package/src/test-utils/rls/RLSTestContext.ts +554 -554
- package/src/test-utils/rls/index.ts +1 -1
|
@@ -1,621 +1,621 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Instantly updateInterestStatus fetch implementation
|
|
3
|
-
*
|
|
4
|
-
* Tests the native fetch implementation of updateInterestStatus method:
|
|
5
|
-
* 1. Success cases for different interest values (-1, 0, 1)
|
|
6
|
-
* 2. Success case with optional campaign_id
|
|
7
|
-
* 3. Success case with disable_auto_interest option
|
|
8
|
-
* 4. Error cases for validation failures
|
|
9
|
-
* 5. Error cases for API errors (401, 422, etc.)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
13
|
-
import { updateInterestStatus } from '../index.js'
|
|
14
|
-
import { ToolingError } from '../../../../../../../types.js'
|
|
15
|
-
|
|
16
|
-
// Mock fetch globally
|
|
17
|
-
const mockFetch = vi.fn()
|
|
18
|
-
global.fetch = mockFetch as typeof fetch
|
|
19
|
-
|
|
20
|
-
describe('updateInterestStatus', () => {
|
|
21
|
-
const validCredentials = { apiKey: 'test-api-key' }
|
|
22
|
-
const testContext = {
|
|
23
|
-
organizationId: 'org-123',
|
|
24
|
-
organizationName: 'Test Org',
|
|
25
|
-
executionId: 'exec-456',
|
|
26
|
-
resourceId: 'resource-789',
|
|
27
|
-
executionDepth: 0,
|
|
28
|
-
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
29
|
-
store: new Map()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
beforeEach(() => {
|
|
33
|
-
vi.clearAllMocks()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
describe('Success Cases', () => {
|
|
37
|
-
it('should update interest status to Not Interested (interest_value=-1)', async () => {
|
|
38
|
-
mockFetch.mockResolvedValue({
|
|
39
|
-
ok: true,
|
|
40
|
-
json: async () => ({})
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const result = await updateInterestStatus(
|
|
44
|
-
validCredentials,
|
|
45
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
46
|
-
testContext
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
expect(result).toEqual({
|
|
50
|
-
success: true,
|
|
51
|
-
lead_email: 'test@example.com'
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
55
|
-
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
56
|
-
expect.objectContaining({
|
|
57
|
-
method: 'POST',
|
|
58
|
-
headers: {
|
|
59
|
-
Authorization: 'Bearer test-api-key',
|
|
60
|
-
'Content-Type': 'application/json'
|
|
61
|
-
},
|
|
62
|
-
body: JSON.stringify({
|
|
63
|
-
lead_email: 'test@example.com',
|
|
64
|
-
interest_value: -1
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('should update interest status to Interested (interest_value=1)', async () => {
|
|
71
|
-
mockFetch.mockResolvedValue({
|
|
72
|
-
ok: true,
|
|
73
|
-
json: async () => ({})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
const result = await updateInterestStatus(
|
|
77
|
-
validCredentials,
|
|
78
|
-
{ lead_email: 'interested@example.com', interest_value: 1 },
|
|
79
|
-
testContext
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
expect(result).toEqual({
|
|
83
|
-
success: true,
|
|
84
|
-
lead_email: 'interested@example.com'
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
88
|
-
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
89
|
-
expect.objectContaining({
|
|
90
|
-
method: 'POST',
|
|
91
|
-
body: JSON.stringify({
|
|
92
|
-
lead_email: 'interested@example.com',
|
|
93
|
-
interest_value: 1
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('should reset interest status to Lead/default (interest_value=0)', async () => {
|
|
100
|
-
mockFetch.mockResolvedValue({
|
|
101
|
-
ok: true,
|
|
102
|
-
json: async () => ({})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
const result = await updateInterestStatus(
|
|
106
|
-
validCredentials,
|
|
107
|
-
{ lead_email: 'reset@example.com', interest_value: 0 },
|
|
108
|
-
testContext
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
expect(result).toEqual({
|
|
112
|
-
success: true,
|
|
113
|
-
lead_email: 'reset@example.com'
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
117
|
-
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
118
|
-
expect.objectContaining({
|
|
119
|
-
method: 'POST',
|
|
120
|
-
body: JSON.stringify({
|
|
121
|
-
lead_email: 'reset@example.com',
|
|
122
|
-
interest_value: 0
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('should include campaign_id when provided', async () => {
|
|
129
|
-
mockFetch.mockResolvedValue({
|
|
130
|
-
ok: true,
|
|
131
|
-
json: async () => ({})
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
const result = await updateInterestStatus(
|
|
135
|
-
validCredentials,
|
|
136
|
-
{
|
|
137
|
-
lead_email: 'campaign@example.com',
|
|
138
|
-
interest_value: -1,
|
|
139
|
-
campaign_id: 'campaign-123'
|
|
140
|
-
},
|
|
141
|
-
testContext
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
expect(result).toEqual({
|
|
145
|
-
success: true,
|
|
146
|
-
lead_email: 'campaign@example.com'
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
150
|
-
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
151
|
-
expect.objectContaining({
|
|
152
|
-
method: 'POST',
|
|
153
|
-
body: JSON.stringify({
|
|
154
|
-
lead_email: 'campaign@example.com',
|
|
155
|
-
interest_value: -1,
|
|
156
|
-
campaign_id: 'campaign-123'
|
|
157
|
-
})
|
|
158
|
-
})
|
|
159
|
-
)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should include disable_auto_interest when provided', async () => {
|
|
163
|
-
mockFetch.mockResolvedValue({
|
|
164
|
-
ok: true,
|
|
165
|
-
json: async () => ({})
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
const result = await updateInterestStatus(
|
|
169
|
-
validCredentials,
|
|
170
|
-
{
|
|
171
|
-
lead_email: 'auto@example.com',
|
|
172
|
-
interest_value: 1,
|
|
173
|
-
disable_auto_interest: true
|
|
174
|
-
},
|
|
175
|
-
testContext
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
expect(result).toEqual({
|
|
179
|
-
success: true,
|
|
180
|
-
lead_email: 'auto@example.com'
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
184
|
-
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
185
|
-
expect.objectContaining({
|
|
186
|
-
method: 'POST',
|
|
187
|
-
body: JSON.stringify({
|
|
188
|
-
lead_email: 'auto@example.com',
|
|
189
|
-
interest_value: 1,
|
|
190
|
-
disable_auto_interest: true
|
|
191
|
-
})
|
|
192
|
-
})
|
|
193
|
-
)
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
it('should work without execution context', async () => {
|
|
197
|
-
mockFetch.mockResolvedValue({
|
|
198
|
-
ok: true,
|
|
199
|
-
json: async () => ({})
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
const result = await updateInterestStatus(validCredentials, {
|
|
203
|
-
lead_email: 'nocontext@example.com',
|
|
204
|
-
interest_value: -1
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
expect(result).toEqual({
|
|
208
|
-
success: true,
|
|
209
|
-
lead_email: 'nocontext@example.com'
|
|
210
|
-
})
|
|
211
|
-
})
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
describe('Validation Error Cases', () => {
|
|
215
|
-
it('should throw validation_error when lead_email is missing', async () => {
|
|
216
|
-
await expect(
|
|
217
|
-
updateInterestStatus(validCredentials, { lead_email: '', interest_value: -1 }, testContext)
|
|
218
|
-
).rejects.toThrow(ToolingError)
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
await updateInterestStatus(validCredentials, { lead_email: '', interest_value: -1 }, testContext)
|
|
222
|
-
} catch (error) {
|
|
223
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
224
|
-
expect((error as ToolingError).message).toBe('Missing required parameter: lead_email')
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Fetch should not be called on validation error
|
|
228
|
-
expect(mockFetch).not.toHaveBeenCalled()
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
it('should throw validation_error when interest_value is undefined', async () => {
|
|
232
|
-
await expect(
|
|
233
|
-
updateInterestStatus(
|
|
234
|
-
validCredentials,
|
|
235
|
-
{ lead_email: 'test@example.com', interest_value: undefined as unknown as number },
|
|
236
|
-
testContext
|
|
237
|
-
)
|
|
238
|
-
).rejects.toThrow(ToolingError)
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
await updateInterestStatus(
|
|
242
|
-
validCredentials,
|
|
243
|
-
{ lead_email: 'test@example.com', interest_value: undefined as unknown as number },
|
|
244
|
-
testContext
|
|
245
|
-
)
|
|
246
|
-
} catch (error) {
|
|
247
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
248
|
-
expect((error as ToolingError).message).toBe('Missing required parameter: interest_value')
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
expect(mockFetch).not.toHaveBeenCalled()
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('should throw validation_error when interest_value is null', async () => {
|
|
255
|
-
await expect(
|
|
256
|
-
updateInterestStatus(
|
|
257
|
-
validCredentials,
|
|
258
|
-
{ lead_email: 'test@example.com', interest_value: null as unknown as number },
|
|
259
|
-
testContext
|
|
260
|
-
)
|
|
261
|
-
).rejects.toThrow(ToolingError)
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
await updateInterestStatus(
|
|
265
|
-
validCredentials,
|
|
266
|
-
{ lead_email: 'test@example.com', interest_value: null as unknown as number },
|
|
267
|
-
testContext
|
|
268
|
-
)
|
|
269
|
-
} catch (error) {
|
|
270
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
271
|
-
expect((error as ToolingError).message).toBe('Missing required parameter: interest_value')
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
expect(mockFetch).not.toHaveBeenCalled()
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('should throw validation_error when interest_value is 2 (invalid)', async () => {
|
|
278
|
-
await expect(
|
|
279
|
-
updateInterestStatus(validCredentials, { lead_email: 'test@example.com', interest_value: 2 }, testContext)
|
|
280
|
-
).rejects.toThrow(ToolingError)
|
|
281
|
-
|
|
282
|
-
try {
|
|
283
|
-
await updateInterestStatus(validCredentials, { lead_email: 'test@example.com', interest_value: 2 }, testContext)
|
|
284
|
-
} catch (error) {
|
|
285
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
286
|
-
expect((error as ToolingError).message).toBe(
|
|
287
|
-
'interest_value must be 1 (interested), 0 (default), or -1 (not-interested)'
|
|
288
|
-
)
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
expect(mockFetch).not.toHaveBeenCalled()
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
it('should throw validation_error when interest_value is -2 (invalid)', async () => {
|
|
295
|
-
await expect(
|
|
296
|
-
updateInterestStatus(validCredentials, { lead_email: 'test@example.com', interest_value: -2 }, testContext)
|
|
297
|
-
).rejects.toThrow(ToolingError)
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
await updateInterestStatus(
|
|
301
|
-
validCredentials,
|
|
302
|
-
{ lead_email: 'test@example.com', interest_value: -2 },
|
|
303
|
-
testContext
|
|
304
|
-
)
|
|
305
|
-
} catch (error) {
|
|
306
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
307
|
-
expect((error as ToolingError).message).toBe(
|
|
308
|
-
'interest_value must be 1 (interested), 0 (default), or -1 (not-interested)'
|
|
309
|
-
)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
expect(mockFetch).not.toHaveBeenCalled()
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
it('should throw validation_error when interest_value is 100 (invalid)', async () => {
|
|
316
|
-
try {
|
|
317
|
-
await updateInterestStatus(
|
|
318
|
-
validCredentials,
|
|
319
|
-
{ lead_email: 'test@example.com', interest_value: 100 },
|
|
320
|
-
testContext
|
|
321
|
-
)
|
|
322
|
-
} catch (error) {
|
|
323
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
324
|
-
expect((error as ToolingError).message).toContain('interest_value must be')
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
expect(mockFetch).not.toHaveBeenCalled()
|
|
328
|
-
})
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
describe('API Error Cases', () => {
|
|
332
|
-
it('should throw credentials_invalid on 401 Unauthorized', async () => {
|
|
333
|
-
mockFetch.mockResolvedValue({
|
|
334
|
-
ok: false,
|
|
335
|
-
status: 401,
|
|
336
|
-
statusText: 'Unauthorized',
|
|
337
|
-
text: async () =>
|
|
338
|
-
JSON.stringify({
|
|
339
|
-
error: {
|
|
340
|
-
type: 'authentication_error',
|
|
341
|
-
message: 'Invalid API key'
|
|
342
|
-
}
|
|
343
|
-
})
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
await updateInterestStatus(
|
|
348
|
-
{ apiKey: 'invalid-key' },
|
|
349
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
350
|
-
testContext
|
|
351
|
-
)
|
|
352
|
-
// Should not reach here
|
|
353
|
-
expect(true).toBe(false)
|
|
354
|
-
} catch (error) {
|
|
355
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
356
|
-
expect((error as ToolingError).errorType).toBe('credentials_invalid')
|
|
357
|
-
expect((error as ToolingError).message).toContain('Invalid API key')
|
|
358
|
-
}
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
it('should throw credentials_invalid on 403 Forbidden', async () => {
|
|
362
|
-
mockFetch.mockResolvedValue({
|
|
363
|
-
ok: false,
|
|
364
|
-
status: 403,
|
|
365
|
-
statusText: 'Forbidden',
|
|
366
|
-
text: async () =>
|
|
367
|
-
JSON.stringify({
|
|
368
|
-
message: 'Access denied'
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
try {
|
|
373
|
-
await updateInterestStatus(
|
|
374
|
-
validCredentials,
|
|
375
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
376
|
-
testContext
|
|
377
|
-
)
|
|
378
|
-
expect(true).toBe(false)
|
|
379
|
-
} catch (error) {
|
|
380
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
381
|
-
expect((error as ToolingError).errorType).toBe('credentials_invalid')
|
|
382
|
-
}
|
|
383
|
-
})
|
|
384
|
-
|
|
385
|
-
it('should throw validation_error on 400 Bad Request', async () => {
|
|
386
|
-
mockFetch.mockResolvedValue({
|
|
387
|
-
ok: false,
|
|
388
|
-
status: 400,
|
|
389
|
-
statusText: 'Bad Request',
|
|
390
|
-
text: async () =>
|
|
391
|
-
JSON.stringify({
|
|
392
|
-
error: {
|
|
393
|
-
message: 'Invalid lead email format'
|
|
394
|
-
}
|
|
395
|
-
})
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
try {
|
|
399
|
-
await updateInterestStatus(validCredentials, { lead_email: 'invalid-email', interest_value: -1 }, testContext)
|
|
400
|
-
expect(true).toBe(false)
|
|
401
|
-
} catch (error) {
|
|
402
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
403
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
404
|
-
expect((error as ToolingError).message).toContain('Invalid lead email format')
|
|
405
|
-
}
|
|
406
|
-
})
|
|
407
|
-
|
|
408
|
-
it('should throw validation_error on 422 Unprocessable Entity', async () => {
|
|
409
|
-
mockFetch.mockResolvedValue({
|
|
410
|
-
ok: false,
|
|
411
|
-
status: 422,
|
|
412
|
-
statusText: 'Unprocessable Entity',
|
|
413
|
-
text: async () =>
|
|
414
|
-
JSON.stringify({
|
|
415
|
-
error: {
|
|
416
|
-
message: 'Lead not found in any campaign'
|
|
417
|
-
}
|
|
418
|
-
})
|
|
419
|
-
})
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
await updateInterestStatus(
|
|
423
|
-
validCredentials,
|
|
424
|
-
{ lead_email: 'notfound@example.com', interest_value: -1 },
|
|
425
|
-
testContext
|
|
426
|
-
)
|
|
427
|
-
expect(true).toBe(false)
|
|
428
|
-
} catch (error) {
|
|
429
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
430
|
-
// 422 falls into 400-499 range which maps to validation_error
|
|
431
|
-
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
432
|
-
}
|
|
433
|
-
})
|
|
434
|
-
|
|
435
|
-
it('should throw rate_limit_exceeded on 429 Too Many Requests', async () => {
|
|
436
|
-
mockFetch.mockResolvedValue({
|
|
437
|
-
ok: false,
|
|
438
|
-
status: 429,
|
|
439
|
-
statusText: 'Too Many Requests',
|
|
440
|
-
text: async () =>
|
|
441
|
-
JSON.stringify({
|
|
442
|
-
message: 'Rate limit exceeded. Please try again later.'
|
|
443
|
-
})
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
try {
|
|
447
|
-
await updateInterestStatus(
|
|
448
|
-
validCredentials,
|
|
449
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
450
|
-
testContext
|
|
451
|
-
)
|
|
452
|
-
expect(true).toBe(false)
|
|
453
|
-
} catch (error) {
|
|
454
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
455
|
-
expect((error as ToolingError).errorType).toBe('api_error')
|
|
456
|
-
}
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
it('should throw server_unavailable on 500 Internal Server Error', async () => {
|
|
460
|
-
mockFetch.mockResolvedValue({
|
|
461
|
-
ok: false,
|
|
462
|
-
status: 500,
|
|
463
|
-
statusText: 'Internal Server Error',
|
|
464
|
-
text: async () => 'Internal server error'
|
|
465
|
-
})
|
|
466
|
-
|
|
467
|
-
try {
|
|
468
|
-
await updateInterestStatus(
|
|
469
|
-
validCredentials,
|
|
470
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
471
|
-
testContext
|
|
472
|
-
)
|
|
473
|
-
expect(true).toBe(false)
|
|
474
|
-
} catch (error) {
|
|
475
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
476
|
-
expect((error as ToolingError).errorType).toBe('api_error')
|
|
477
|
-
}
|
|
478
|
-
})
|
|
479
|
-
|
|
480
|
-
it('should throw server_unavailable on 503 Service Unavailable', async () => {
|
|
481
|
-
mockFetch.mockResolvedValue({
|
|
482
|
-
ok: false,
|
|
483
|
-
status: 503,
|
|
484
|
-
statusText: 'Service Unavailable',
|
|
485
|
-
text: async () => 'Service temporarily unavailable'
|
|
486
|
-
})
|
|
487
|
-
|
|
488
|
-
try {
|
|
489
|
-
await updateInterestStatus(
|
|
490
|
-
validCredentials,
|
|
491
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
492
|
-
testContext
|
|
493
|
-
)
|
|
494
|
-
expect(true).toBe(false)
|
|
495
|
-
} catch (error) {
|
|
496
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
497
|
-
expect((error as ToolingError).errorType).toBe('api_error')
|
|
498
|
-
}
|
|
499
|
-
})
|
|
500
|
-
|
|
501
|
-
it('should handle non-JSON error responses', async () => {
|
|
502
|
-
mockFetch.mockResolvedValue({
|
|
503
|
-
ok: false,
|
|
504
|
-
status: 500,
|
|
505
|
-
statusText: 'Internal Server Error',
|
|
506
|
-
text: async () => 'Plain text error message'
|
|
507
|
-
})
|
|
508
|
-
|
|
509
|
-
try {
|
|
510
|
-
await updateInterestStatus(
|
|
511
|
-
validCredentials,
|
|
512
|
-
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
513
|
-
testContext
|
|
514
|
-
)
|
|
515
|
-
expect(true).toBe(false)
|
|
516
|
-
} catch (error) {
|
|
517
|
-
expect(error).toBeInstanceOf(ToolingError)
|
|
518
|
-
expect((error as ToolingError).message).toBe('Failed after 3 retries: Plain text error message')
|
|
519
|
-
}
|
|
520
|
-
})
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
describe('Request Body Construction', () => {
|
|
524
|
-
it('should construct correct request body with all parameters', async () => {
|
|
525
|
-
mockFetch.mockResolvedValue({
|
|
526
|
-
ok: true,
|
|
527
|
-
json: async () => ({})
|
|
528
|
-
})
|
|
529
|
-
|
|
530
|
-
await updateInterestStatus(
|
|
531
|
-
validCredentials,
|
|
532
|
-
{
|
|
533
|
-
lead_email: 'full@example.com',
|
|
534
|
-
interest_value: -1,
|
|
535
|
-
campaign_id: 'campaign-abc',
|
|
536
|
-
disable_auto_interest: true
|
|
537
|
-
},
|
|
538
|
-
testContext
|
|
539
|
-
)
|
|
540
|
-
|
|
541
|
-
const callArgs = mockFetch.mock.calls[0]
|
|
542
|
-
const requestBody = JSON.parse(callArgs[1].body)
|
|
543
|
-
|
|
544
|
-
expect(requestBody).toEqual({
|
|
545
|
-
lead_email: 'full@example.com',
|
|
546
|
-
interest_value: -1,
|
|
547
|
-
campaign_id: 'campaign-abc',
|
|
548
|
-
disable_auto_interest: true
|
|
549
|
-
})
|
|
550
|
-
})
|
|
551
|
-
|
|
552
|
-
it('should not include undefined optional parameters', async () => {
|
|
553
|
-
mockFetch.mockResolvedValue({
|
|
554
|
-
ok: true,
|
|
555
|
-
json: async () => ({})
|
|
556
|
-
})
|
|
557
|
-
|
|
558
|
-
await updateInterestStatus(
|
|
559
|
-
validCredentials,
|
|
560
|
-
{
|
|
561
|
-
lead_email: 'minimal@example.com',
|
|
562
|
-
interest_value: 0
|
|
563
|
-
},
|
|
564
|
-
testContext
|
|
565
|
-
)
|
|
566
|
-
|
|
567
|
-
const callArgs = mockFetch.mock.calls[0]
|
|
568
|
-
const requestBody = JSON.parse(callArgs[1].body)
|
|
569
|
-
|
|
570
|
-
expect(requestBody).toEqual({
|
|
571
|
-
lead_email: 'minimal@example.com',
|
|
572
|
-
interest_value: 0
|
|
573
|
-
})
|
|
574
|
-
expect(requestBody).not.toHaveProperty('campaign_id')
|
|
575
|
-
expect(requestBody).not.toHaveProperty('disable_auto_interest')
|
|
576
|
-
})
|
|
577
|
-
|
|
578
|
-
it('should include disable_auto_interest when set to false', async () => {
|
|
579
|
-
mockFetch.mockResolvedValue({
|
|
580
|
-
ok: true,
|
|
581
|
-
json: async () => ({})
|
|
582
|
-
})
|
|
583
|
-
|
|
584
|
-
await updateInterestStatus(
|
|
585
|
-
validCredentials,
|
|
586
|
-
{
|
|
587
|
-
lead_email: 'test@example.com',
|
|
588
|
-
interest_value: 1,
|
|
589
|
-
disable_auto_interest: false
|
|
590
|
-
},
|
|
591
|
-
testContext
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
const callArgs = mockFetch.mock.calls[0]
|
|
595
|
-
const requestBody = JSON.parse(callArgs[1].body)
|
|
596
|
-
|
|
597
|
-
expect(requestBody.disable_auto_interest).toBe(false)
|
|
598
|
-
})
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
describe('Authorization Header', () => {
|
|
602
|
-
it('should use Bearer token authorization', async () => {
|
|
603
|
-
mockFetch.mockResolvedValue({
|
|
604
|
-
ok: true,
|
|
605
|
-
json: async () => ({})
|
|
606
|
-
})
|
|
607
|
-
|
|
608
|
-
await updateInterestStatus(
|
|
609
|
-
{ apiKey: 'my-secret-api-key' },
|
|
610
|
-
{ lead_email: 'test@example.com', interest_value: 1 },
|
|
611
|
-
testContext
|
|
612
|
-
)
|
|
613
|
-
|
|
614
|
-
const callArgs = mockFetch.mock.calls[0]
|
|
615
|
-
expect(callArgs[1].headers).toEqual({
|
|
616
|
-
Authorization: 'Bearer my-secret-api-key',
|
|
617
|
-
'Content-Type': 'application/json'
|
|
618
|
-
})
|
|
619
|
-
})
|
|
620
|
-
})
|
|
621
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Instantly updateInterestStatus fetch implementation
|
|
3
|
+
*
|
|
4
|
+
* Tests the native fetch implementation of updateInterestStatus method:
|
|
5
|
+
* 1. Success cases for different interest values (-1, 0, 1)
|
|
6
|
+
* 2. Success case with optional campaign_id
|
|
7
|
+
* 3. Success case with disable_auto_interest option
|
|
8
|
+
* 4. Error cases for validation failures
|
|
9
|
+
* 5. Error cases for API errors (401, 422, etc.)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
13
|
+
import { updateInterestStatus } from '../index.js'
|
|
14
|
+
import { ToolingError } from '../../../../../../../types.js'
|
|
15
|
+
|
|
16
|
+
// Mock fetch globally
|
|
17
|
+
const mockFetch = vi.fn()
|
|
18
|
+
global.fetch = mockFetch as typeof fetch
|
|
19
|
+
|
|
20
|
+
describe('updateInterestStatus', () => {
|
|
21
|
+
const validCredentials = { apiKey: 'test-api-key' }
|
|
22
|
+
const testContext = {
|
|
23
|
+
organizationId: 'org-123',
|
|
24
|
+
organizationName: 'Test Org',
|
|
25
|
+
executionId: 'exec-456',
|
|
26
|
+
resourceId: 'resource-789',
|
|
27
|
+
executionDepth: 0,
|
|
28
|
+
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
29
|
+
store: new Map()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
vi.clearAllMocks()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('Success Cases', () => {
|
|
37
|
+
it('should update interest status to Not Interested (interest_value=-1)', async () => {
|
|
38
|
+
mockFetch.mockResolvedValue({
|
|
39
|
+
ok: true,
|
|
40
|
+
json: async () => ({})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const result = await updateInterestStatus(
|
|
44
|
+
validCredentials,
|
|
45
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
46
|
+
testContext
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
expect(result).toEqual({
|
|
50
|
+
success: true,
|
|
51
|
+
lead_email: 'test@example.com'
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
55
|
+
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
56
|
+
expect.objectContaining({
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: 'Bearer test-api-key',
|
|
60
|
+
'Content-Type': 'application/json'
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
lead_email: 'test@example.com',
|
|
64
|
+
interest_value: -1
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should update interest status to Interested (interest_value=1)', async () => {
|
|
71
|
+
mockFetch.mockResolvedValue({
|
|
72
|
+
ok: true,
|
|
73
|
+
json: async () => ({})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const result = await updateInterestStatus(
|
|
77
|
+
validCredentials,
|
|
78
|
+
{ lead_email: 'interested@example.com', interest_value: 1 },
|
|
79
|
+
testContext
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
expect(result).toEqual({
|
|
83
|
+
success: true,
|
|
84
|
+
lead_email: 'interested@example.com'
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
88
|
+
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
89
|
+
expect.objectContaining({
|
|
90
|
+
method: 'POST',
|
|
91
|
+
body: JSON.stringify({
|
|
92
|
+
lead_email: 'interested@example.com',
|
|
93
|
+
interest_value: 1
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should reset interest status to Lead/default (interest_value=0)', async () => {
|
|
100
|
+
mockFetch.mockResolvedValue({
|
|
101
|
+
ok: true,
|
|
102
|
+
json: async () => ({})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const result = await updateInterestStatus(
|
|
106
|
+
validCredentials,
|
|
107
|
+
{ lead_email: 'reset@example.com', interest_value: 0 },
|
|
108
|
+
testContext
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
expect(result).toEqual({
|
|
112
|
+
success: true,
|
|
113
|
+
lead_email: 'reset@example.com'
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
117
|
+
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
118
|
+
expect.objectContaining({
|
|
119
|
+
method: 'POST',
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
lead_email: 'reset@example.com',
|
|
122
|
+
interest_value: 0
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('should include campaign_id when provided', async () => {
|
|
129
|
+
mockFetch.mockResolvedValue({
|
|
130
|
+
ok: true,
|
|
131
|
+
json: async () => ({})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
const result = await updateInterestStatus(
|
|
135
|
+
validCredentials,
|
|
136
|
+
{
|
|
137
|
+
lead_email: 'campaign@example.com',
|
|
138
|
+
interest_value: -1,
|
|
139
|
+
campaign_id: 'campaign-123'
|
|
140
|
+
},
|
|
141
|
+
testContext
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
expect(result).toEqual({
|
|
145
|
+
success: true,
|
|
146
|
+
lead_email: 'campaign@example.com'
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
150
|
+
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
151
|
+
expect.objectContaining({
|
|
152
|
+
method: 'POST',
|
|
153
|
+
body: JSON.stringify({
|
|
154
|
+
lead_email: 'campaign@example.com',
|
|
155
|
+
interest_value: -1,
|
|
156
|
+
campaign_id: 'campaign-123'
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('should include disable_auto_interest when provided', async () => {
|
|
163
|
+
mockFetch.mockResolvedValue({
|
|
164
|
+
ok: true,
|
|
165
|
+
json: async () => ({})
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const result = await updateInterestStatus(
|
|
169
|
+
validCredentials,
|
|
170
|
+
{
|
|
171
|
+
lead_email: 'auto@example.com',
|
|
172
|
+
interest_value: 1,
|
|
173
|
+
disable_auto_interest: true
|
|
174
|
+
},
|
|
175
|
+
testContext
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
expect(result).toEqual({
|
|
179
|
+
success: true,
|
|
180
|
+
lead_email: 'auto@example.com'
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
184
|
+
'https://api.instantly.ai/api/v2/leads/update-interest-status',
|
|
185
|
+
expect.objectContaining({
|
|
186
|
+
method: 'POST',
|
|
187
|
+
body: JSON.stringify({
|
|
188
|
+
lead_email: 'auto@example.com',
|
|
189
|
+
interest_value: 1,
|
|
190
|
+
disable_auto_interest: true
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should work without execution context', async () => {
|
|
197
|
+
mockFetch.mockResolvedValue({
|
|
198
|
+
ok: true,
|
|
199
|
+
json: async () => ({})
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
const result = await updateInterestStatus(validCredentials, {
|
|
203
|
+
lead_email: 'nocontext@example.com',
|
|
204
|
+
interest_value: -1
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
expect(result).toEqual({
|
|
208
|
+
success: true,
|
|
209
|
+
lead_email: 'nocontext@example.com'
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
describe('Validation Error Cases', () => {
|
|
215
|
+
it('should throw validation_error when lead_email is missing', async () => {
|
|
216
|
+
await expect(
|
|
217
|
+
updateInterestStatus(validCredentials, { lead_email: '', interest_value: -1 }, testContext)
|
|
218
|
+
).rejects.toThrow(ToolingError)
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
await updateInterestStatus(validCredentials, { lead_email: '', interest_value: -1 }, testContext)
|
|
222
|
+
} catch (error) {
|
|
223
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
224
|
+
expect((error as ToolingError).message).toBe('Missing required parameter: lead_email')
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Fetch should not be called on validation error
|
|
228
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('should throw validation_error when interest_value is undefined', async () => {
|
|
232
|
+
await expect(
|
|
233
|
+
updateInterestStatus(
|
|
234
|
+
validCredentials,
|
|
235
|
+
{ lead_email: 'test@example.com', interest_value: undefined as unknown as number },
|
|
236
|
+
testContext
|
|
237
|
+
)
|
|
238
|
+
).rejects.toThrow(ToolingError)
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
await updateInterestStatus(
|
|
242
|
+
validCredentials,
|
|
243
|
+
{ lead_email: 'test@example.com', interest_value: undefined as unknown as number },
|
|
244
|
+
testContext
|
|
245
|
+
)
|
|
246
|
+
} catch (error) {
|
|
247
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
248
|
+
expect((error as ToolingError).message).toBe('Missing required parameter: interest_value')
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it('should throw validation_error when interest_value is null', async () => {
|
|
255
|
+
await expect(
|
|
256
|
+
updateInterestStatus(
|
|
257
|
+
validCredentials,
|
|
258
|
+
{ lead_email: 'test@example.com', interest_value: null as unknown as number },
|
|
259
|
+
testContext
|
|
260
|
+
)
|
|
261
|
+
).rejects.toThrow(ToolingError)
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
await updateInterestStatus(
|
|
265
|
+
validCredentials,
|
|
266
|
+
{ lead_email: 'test@example.com', interest_value: null as unknown as number },
|
|
267
|
+
testContext
|
|
268
|
+
)
|
|
269
|
+
} catch (error) {
|
|
270
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
271
|
+
expect((error as ToolingError).message).toBe('Missing required parameter: interest_value')
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('should throw validation_error when interest_value is 2 (invalid)', async () => {
|
|
278
|
+
await expect(
|
|
279
|
+
updateInterestStatus(validCredentials, { lead_email: 'test@example.com', interest_value: 2 }, testContext)
|
|
280
|
+
).rejects.toThrow(ToolingError)
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
await updateInterestStatus(validCredentials, { lead_email: 'test@example.com', interest_value: 2 }, testContext)
|
|
284
|
+
} catch (error) {
|
|
285
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
286
|
+
expect((error as ToolingError).message).toBe(
|
|
287
|
+
'interest_value must be 1 (interested), 0 (default), or -1 (not-interested)'
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
it('should throw validation_error when interest_value is -2 (invalid)', async () => {
|
|
295
|
+
await expect(
|
|
296
|
+
updateInterestStatus(validCredentials, { lead_email: 'test@example.com', interest_value: -2 }, testContext)
|
|
297
|
+
).rejects.toThrow(ToolingError)
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
await updateInterestStatus(
|
|
301
|
+
validCredentials,
|
|
302
|
+
{ lead_email: 'test@example.com', interest_value: -2 },
|
|
303
|
+
testContext
|
|
304
|
+
)
|
|
305
|
+
} catch (error) {
|
|
306
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
307
|
+
expect((error as ToolingError).message).toBe(
|
|
308
|
+
'interest_value must be 1 (interested), 0 (default), or -1 (not-interested)'
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('should throw validation_error when interest_value is 100 (invalid)', async () => {
|
|
316
|
+
try {
|
|
317
|
+
await updateInterestStatus(
|
|
318
|
+
validCredentials,
|
|
319
|
+
{ lead_email: 'test@example.com', interest_value: 100 },
|
|
320
|
+
testContext
|
|
321
|
+
)
|
|
322
|
+
} catch (error) {
|
|
323
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
324
|
+
expect((error as ToolingError).message).toContain('interest_value must be')
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
328
|
+
})
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
describe('API Error Cases', () => {
|
|
332
|
+
it('should throw credentials_invalid on 401 Unauthorized', async () => {
|
|
333
|
+
mockFetch.mockResolvedValue({
|
|
334
|
+
ok: false,
|
|
335
|
+
status: 401,
|
|
336
|
+
statusText: 'Unauthorized',
|
|
337
|
+
text: async () =>
|
|
338
|
+
JSON.stringify({
|
|
339
|
+
error: {
|
|
340
|
+
type: 'authentication_error',
|
|
341
|
+
message: 'Invalid API key'
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
await updateInterestStatus(
|
|
348
|
+
{ apiKey: 'invalid-key' },
|
|
349
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
350
|
+
testContext
|
|
351
|
+
)
|
|
352
|
+
// Should not reach here
|
|
353
|
+
expect(true).toBe(false)
|
|
354
|
+
} catch (error) {
|
|
355
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
356
|
+
expect((error as ToolingError).errorType).toBe('credentials_invalid')
|
|
357
|
+
expect((error as ToolingError).message).toContain('Invalid API key')
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
it('should throw credentials_invalid on 403 Forbidden', async () => {
|
|
362
|
+
mockFetch.mockResolvedValue({
|
|
363
|
+
ok: false,
|
|
364
|
+
status: 403,
|
|
365
|
+
statusText: 'Forbidden',
|
|
366
|
+
text: async () =>
|
|
367
|
+
JSON.stringify({
|
|
368
|
+
message: 'Access denied'
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
await updateInterestStatus(
|
|
374
|
+
validCredentials,
|
|
375
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
376
|
+
testContext
|
|
377
|
+
)
|
|
378
|
+
expect(true).toBe(false)
|
|
379
|
+
} catch (error) {
|
|
380
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
381
|
+
expect((error as ToolingError).errorType).toBe('credentials_invalid')
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it('should throw validation_error on 400 Bad Request', async () => {
|
|
386
|
+
mockFetch.mockResolvedValue({
|
|
387
|
+
ok: false,
|
|
388
|
+
status: 400,
|
|
389
|
+
statusText: 'Bad Request',
|
|
390
|
+
text: async () =>
|
|
391
|
+
JSON.stringify({
|
|
392
|
+
error: {
|
|
393
|
+
message: 'Invalid lead email format'
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
await updateInterestStatus(validCredentials, { lead_email: 'invalid-email', interest_value: -1 }, testContext)
|
|
400
|
+
expect(true).toBe(false)
|
|
401
|
+
} catch (error) {
|
|
402
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
403
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
404
|
+
expect((error as ToolingError).message).toContain('Invalid lead email format')
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it('should throw validation_error on 422 Unprocessable Entity', async () => {
|
|
409
|
+
mockFetch.mockResolvedValue({
|
|
410
|
+
ok: false,
|
|
411
|
+
status: 422,
|
|
412
|
+
statusText: 'Unprocessable Entity',
|
|
413
|
+
text: async () =>
|
|
414
|
+
JSON.stringify({
|
|
415
|
+
error: {
|
|
416
|
+
message: 'Lead not found in any campaign'
|
|
417
|
+
}
|
|
418
|
+
})
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
await updateInterestStatus(
|
|
423
|
+
validCredentials,
|
|
424
|
+
{ lead_email: 'notfound@example.com', interest_value: -1 },
|
|
425
|
+
testContext
|
|
426
|
+
)
|
|
427
|
+
expect(true).toBe(false)
|
|
428
|
+
} catch (error) {
|
|
429
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
430
|
+
// 422 falls into 400-499 range which maps to validation_error
|
|
431
|
+
expect((error as ToolingError).errorType).toBe('validation_error')
|
|
432
|
+
}
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
it('should throw rate_limit_exceeded on 429 Too Many Requests', async () => {
|
|
436
|
+
mockFetch.mockResolvedValue({
|
|
437
|
+
ok: false,
|
|
438
|
+
status: 429,
|
|
439
|
+
statusText: 'Too Many Requests',
|
|
440
|
+
text: async () =>
|
|
441
|
+
JSON.stringify({
|
|
442
|
+
message: 'Rate limit exceeded. Please try again later.'
|
|
443
|
+
})
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
await updateInterestStatus(
|
|
448
|
+
validCredentials,
|
|
449
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
450
|
+
testContext
|
|
451
|
+
)
|
|
452
|
+
expect(true).toBe(false)
|
|
453
|
+
} catch (error) {
|
|
454
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
455
|
+
expect((error as ToolingError).errorType).toBe('api_error')
|
|
456
|
+
}
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
it('should throw server_unavailable on 500 Internal Server Error', async () => {
|
|
460
|
+
mockFetch.mockResolvedValue({
|
|
461
|
+
ok: false,
|
|
462
|
+
status: 500,
|
|
463
|
+
statusText: 'Internal Server Error',
|
|
464
|
+
text: async () => 'Internal server error'
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
try {
|
|
468
|
+
await updateInterestStatus(
|
|
469
|
+
validCredentials,
|
|
470
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
471
|
+
testContext
|
|
472
|
+
)
|
|
473
|
+
expect(true).toBe(false)
|
|
474
|
+
} catch (error) {
|
|
475
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
476
|
+
expect((error as ToolingError).errorType).toBe('api_error')
|
|
477
|
+
}
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
it('should throw server_unavailable on 503 Service Unavailable', async () => {
|
|
481
|
+
mockFetch.mockResolvedValue({
|
|
482
|
+
ok: false,
|
|
483
|
+
status: 503,
|
|
484
|
+
statusText: 'Service Unavailable',
|
|
485
|
+
text: async () => 'Service temporarily unavailable'
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
await updateInterestStatus(
|
|
490
|
+
validCredentials,
|
|
491
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
492
|
+
testContext
|
|
493
|
+
)
|
|
494
|
+
expect(true).toBe(false)
|
|
495
|
+
} catch (error) {
|
|
496
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
497
|
+
expect((error as ToolingError).errorType).toBe('api_error')
|
|
498
|
+
}
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
it('should handle non-JSON error responses', async () => {
|
|
502
|
+
mockFetch.mockResolvedValue({
|
|
503
|
+
ok: false,
|
|
504
|
+
status: 500,
|
|
505
|
+
statusText: 'Internal Server Error',
|
|
506
|
+
text: async () => 'Plain text error message'
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
await updateInterestStatus(
|
|
511
|
+
validCredentials,
|
|
512
|
+
{ lead_email: 'test@example.com', interest_value: -1 },
|
|
513
|
+
testContext
|
|
514
|
+
)
|
|
515
|
+
expect(true).toBe(false)
|
|
516
|
+
} catch (error) {
|
|
517
|
+
expect(error).toBeInstanceOf(ToolingError)
|
|
518
|
+
expect((error as ToolingError).message).toBe('Failed after 3 retries: Plain text error message')
|
|
519
|
+
}
|
|
520
|
+
})
|
|
521
|
+
})
|
|
522
|
+
|
|
523
|
+
describe('Request Body Construction', () => {
|
|
524
|
+
it('should construct correct request body with all parameters', async () => {
|
|
525
|
+
mockFetch.mockResolvedValue({
|
|
526
|
+
ok: true,
|
|
527
|
+
json: async () => ({})
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
await updateInterestStatus(
|
|
531
|
+
validCredentials,
|
|
532
|
+
{
|
|
533
|
+
lead_email: 'full@example.com',
|
|
534
|
+
interest_value: -1,
|
|
535
|
+
campaign_id: 'campaign-abc',
|
|
536
|
+
disable_auto_interest: true
|
|
537
|
+
},
|
|
538
|
+
testContext
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
const callArgs = mockFetch.mock.calls[0]
|
|
542
|
+
const requestBody = JSON.parse(callArgs[1].body)
|
|
543
|
+
|
|
544
|
+
expect(requestBody).toEqual({
|
|
545
|
+
lead_email: 'full@example.com',
|
|
546
|
+
interest_value: -1,
|
|
547
|
+
campaign_id: 'campaign-abc',
|
|
548
|
+
disable_auto_interest: true
|
|
549
|
+
})
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
it('should not include undefined optional parameters', async () => {
|
|
553
|
+
mockFetch.mockResolvedValue({
|
|
554
|
+
ok: true,
|
|
555
|
+
json: async () => ({})
|
|
556
|
+
})
|
|
557
|
+
|
|
558
|
+
await updateInterestStatus(
|
|
559
|
+
validCredentials,
|
|
560
|
+
{
|
|
561
|
+
lead_email: 'minimal@example.com',
|
|
562
|
+
interest_value: 0
|
|
563
|
+
},
|
|
564
|
+
testContext
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
const callArgs = mockFetch.mock.calls[0]
|
|
568
|
+
const requestBody = JSON.parse(callArgs[1].body)
|
|
569
|
+
|
|
570
|
+
expect(requestBody).toEqual({
|
|
571
|
+
lead_email: 'minimal@example.com',
|
|
572
|
+
interest_value: 0
|
|
573
|
+
})
|
|
574
|
+
expect(requestBody).not.toHaveProperty('campaign_id')
|
|
575
|
+
expect(requestBody).not.toHaveProperty('disable_auto_interest')
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
it('should include disable_auto_interest when set to false', async () => {
|
|
579
|
+
mockFetch.mockResolvedValue({
|
|
580
|
+
ok: true,
|
|
581
|
+
json: async () => ({})
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
await updateInterestStatus(
|
|
585
|
+
validCredentials,
|
|
586
|
+
{
|
|
587
|
+
lead_email: 'test@example.com',
|
|
588
|
+
interest_value: 1,
|
|
589
|
+
disable_auto_interest: false
|
|
590
|
+
},
|
|
591
|
+
testContext
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
const callArgs = mockFetch.mock.calls[0]
|
|
595
|
+
const requestBody = JSON.parse(callArgs[1].body)
|
|
596
|
+
|
|
597
|
+
expect(requestBody.disable_auto_interest).toBe(false)
|
|
598
|
+
})
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
describe('Authorization Header', () => {
|
|
602
|
+
it('should use Bearer token authorization', async () => {
|
|
603
|
+
mockFetch.mockResolvedValue({
|
|
604
|
+
ok: true,
|
|
605
|
+
json: async () => ({})
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
await updateInterestStatus(
|
|
609
|
+
{ apiKey: 'my-secret-api-key' },
|
|
610
|
+
{ lead_email: 'test@example.com', interest_value: 1 },
|
|
611
|
+
testContext
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
const callArgs = mockFetch.mock.calls[0]
|
|
615
|
+
expect(callArgs[1].headers).toEqual({
|
|
616
|
+
Authorization: 'Bearer my-secret-api-key',
|
|
617
|
+
'Content-Type': 'application/json'
|
|
618
|
+
})
|
|
619
|
+
})
|
|
620
|
+
})
|
|
621
|
+
})
|