@elevasis/core 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/README.md +41 -41
- package/src/__tests__/publish.test.ts +18 -18
- 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 +53 -53
- 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 +38 -38
- 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 +11 -11
- 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/rls/RLSTestContext.ts +556 -556
- package/src/test-utils/rls/index.ts +1 -1
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OAuth Provider Credentials
|
|
3
|
-
* Maps provider IDs to environment variable names
|
|
4
|
-
* Single source of truth for credential lookup
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const PROVIDER_ENV_VARS: Record<string, { clientIdEnv: string; clientSecretEnv: string }> = {
|
|
8
|
-
'google-sheets': {
|
|
9
|
-
clientIdEnv: 'GOOGLE_OAUTH_CLIENT_ID',
|
|
10
|
-
clientSecretEnv: 'GOOGLE_OAUTH_CLIENT_SECRET'
|
|
11
|
-
},
|
|
12
|
-
dropbox: {
|
|
13
|
-
clientIdEnv: 'DROPBOX_APP_KEY',
|
|
14
|
-
clientSecretEnv: 'DROPBOX_APP_SECRET'
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get OAuth client credentials for a provider
|
|
20
|
-
* @throws Error if provider unknown or credentials missing
|
|
21
|
-
*/
|
|
22
|
-
export function getOAuthCredentials(providerId: string): { clientId: string; clientSecret: string } {
|
|
23
|
-
const config = PROVIDER_ENV_VARS[providerId]
|
|
24
|
-
if (!config) {
|
|
25
|
-
throw new Error(`Unknown OAuth provider: ${providerId}`)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const clientId = process.env[config.clientIdEnv]
|
|
29
|
-
const clientSecret = process.env[config.clientSecretEnv]
|
|
30
|
-
|
|
31
|
-
if (!clientId) {
|
|
32
|
-
throw new Error(`Missing environment variable: ${config.clientIdEnv}`)
|
|
33
|
-
}
|
|
34
|
-
if (!clientSecret) {
|
|
35
|
-
throw new Error(`Missing environment variable: ${config.clientSecretEnv}`)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return { clientId, clientSecret }
|
|
39
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* OAuth Provider Credentials
|
|
3
|
+
* Maps provider IDs to environment variable names
|
|
4
|
+
* Single source of truth for credential lookup
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const PROVIDER_ENV_VARS: Record<string, { clientIdEnv: string; clientSecretEnv: string }> = {
|
|
8
|
+
'google-sheets': {
|
|
9
|
+
clientIdEnv: 'GOOGLE_OAUTH_CLIENT_ID',
|
|
10
|
+
clientSecretEnv: 'GOOGLE_OAUTH_CLIENT_SECRET'
|
|
11
|
+
},
|
|
12
|
+
dropbox: {
|
|
13
|
+
clientIdEnv: 'DROPBOX_APP_KEY',
|
|
14
|
+
clientSecretEnv: 'DROPBOX_APP_SECRET'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get OAuth client credentials for a provider
|
|
20
|
+
* @throws Error if provider unknown or credentials missing
|
|
21
|
+
*/
|
|
22
|
+
export function getOAuthCredentials(providerId: string): { clientId: string; clientSecret: string } {
|
|
23
|
+
const config = PROVIDER_ENV_VARS[providerId]
|
|
24
|
+
if (!config) {
|
|
25
|
+
throw new Error(`Unknown OAuth provider: ${providerId}`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const clientId = process.env[config.clientIdEnv]
|
|
29
|
+
const clientSecret = process.env[config.clientSecretEnv]
|
|
30
|
+
|
|
31
|
+
if (!clientId) {
|
|
32
|
+
throw new Error(`Missing environment variable: ${config.clientIdEnv}`)
|
|
33
|
+
}
|
|
34
|
+
if (!clientSecret) {
|
|
35
|
+
throw new Error(`Missing environment variable: ${config.clientSecretEnv}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { clientId, clientSecret }
|
|
39
|
+
}
|
|
@@ -1,214 +1,214 @@
|
|
|
1
|
-
import { getProviderConfig } from '../provider-registry'
|
|
2
|
-
import type { OAuthToken } from '../types'
|
|
3
|
-
import { getOAuthCredentials } from './credentials'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* In-flight refresh deduplication map.
|
|
7
|
-
* Keyed by `provider:refreshToken` — concurrent callers with the same expired token
|
|
8
|
-
* share a single refresh request instead of racing against each other.
|
|
9
|
-
*/
|
|
10
|
-
const inflightRefreshes = new Map<string, Promise<OAuthToken>>()
|
|
11
|
-
|
|
12
|
-
/** @internal Exposed for testing — do not use in production code. */
|
|
13
|
-
export function _getInflightRefreshCount(): number {
|
|
14
|
-
return inflightRefreshes.size
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Refresh OAuth token if expired (pure function)
|
|
19
|
-
*
|
|
20
|
-
* Checks if token expires within 5 minutes and refreshes if needed.
|
|
21
|
-
* Automatically determines provider config from token.provider field.
|
|
22
|
-
* Respects provider-specific token exchange methods (basic-auth, form-encoded, json-body).
|
|
23
|
-
* Handles both RFC 6749-compliant (snake_case) and non-compliant (camelCase) providers.
|
|
24
|
-
*/
|
|
25
|
-
export async function refreshOAuthTokenIfExpired(token: OAuthToken): Promise<OAuthToken> {
|
|
26
|
-
// Validate token has provider field
|
|
27
|
-
if (!token.provider) {
|
|
28
|
-
throw new Error('Token missing provider field - cannot refresh')
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Validate refresh token exists
|
|
32
|
-
if (!token.refreshToken) {
|
|
33
|
-
throw new Error('Token cannot be refreshed (no refresh_token). User must re-authorize.')
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Check if token is still valid
|
|
37
|
-
const expiresAt = new Date(token.expiresAt).getTime()
|
|
38
|
-
const now = Date.now()
|
|
39
|
-
const bufferMs = 5 * 60 * 1000 // 5 minutes
|
|
40
|
-
|
|
41
|
-
if (expiresAt > now + bufferMs) {
|
|
42
|
-
console.log('[OAuth] Token still valid, no refresh needed', {
|
|
43
|
-
provider: token.provider,
|
|
44
|
-
expiresAt: token.expiresAt,
|
|
45
|
-
remainingMinutes: Math.floor((expiresAt - now) / 60000)
|
|
46
|
-
})
|
|
47
|
-
return token // Still valid
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Token expired, delegate to force refresh
|
|
51
|
-
return forceRefreshOAuthToken(token)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Force refresh OAuth token (bypasses expiry check)
|
|
56
|
-
*
|
|
57
|
-
* Use this when you receive a 401 from the API even though the token
|
|
58
|
-
* appeared valid based on expiresAt. This handles cases where:
|
|
59
|
-
* - The stored expiresAt is stale/incorrect
|
|
60
|
-
* - The token was revoked before expiry
|
|
61
|
-
* - Clock skew between systems
|
|
62
|
-
*/
|
|
63
|
-
export async function forceRefreshOAuthToken(token: OAuthToken): Promise<OAuthToken> {
|
|
64
|
-
// Validate token has provider field
|
|
65
|
-
if (!token.provider) {
|
|
66
|
-
throw new Error('Token missing provider field - cannot refresh')
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Validate refresh token exists
|
|
70
|
-
if (!token.refreshToken) {
|
|
71
|
-
throw new Error('Token cannot be refreshed (no refresh_token). User must re-authorize.')
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Deduplicate concurrent refreshes for the same token
|
|
75
|
-
const dedupeKey = `${token.provider}:${token.refreshToken}`
|
|
76
|
-
const inflight = inflightRefreshes.get(dedupeKey)
|
|
77
|
-
if (inflight) {
|
|
78
|
-
console.log('[OAuth] Reusing in-flight refresh', { provider: token.provider })
|
|
79
|
-
return inflight
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const refreshPromise = performTokenRefresh(token)
|
|
83
|
-
inflightRefreshes.set(dedupeKey, refreshPromise)
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
return await refreshPromise
|
|
87
|
-
} finally {
|
|
88
|
-
inflightRefreshes.delete(dedupeKey)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async function performTokenRefresh(token: OAuthToken): Promise<OAuthToken> {
|
|
93
|
-
console.log('[OAuth] Force refreshing token', {
|
|
94
|
-
provider: token.provider,
|
|
95
|
-
expiresAt: token.expiresAt
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
// Get provider configuration
|
|
99
|
-
const config = getProviderConfig(token.provider)
|
|
100
|
-
|
|
101
|
-
// Get client credentials from environment
|
|
102
|
-
const { clientId, clientSecret } = getOAuthCredentials(config.id)
|
|
103
|
-
|
|
104
|
-
// Perform token refresh using provider-specific exchange method
|
|
105
|
-
let response: Response
|
|
106
|
-
|
|
107
|
-
switch (config.tokenExchange) {
|
|
108
|
-
case 'basic-auth': {
|
|
109
|
-
// Notion pattern: Authorization: Basic {base64(clientId:clientSecret)}
|
|
110
|
-
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64')
|
|
111
|
-
response = await fetch(config.tokenUrl, {
|
|
112
|
-
method: 'POST',
|
|
113
|
-
headers: {
|
|
114
|
-
Authorization: `Basic ${credentials}`,
|
|
115
|
-
'Content-Type': 'application/json'
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify({
|
|
118
|
-
grant_type: 'refresh_token',
|
|
119
|
-
refresh_token: token.refreshToken
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
break
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
case 'form-encoded': {
|
|
126
|
-
// Google pattern: application/x-www-form-urlencoded body
|
|
127
|
-
const params = new URLSearchParams({
|
|
128
|
-
grant_type: 'refresh_token',
|
|
129
|
-
refresh_token: token.refreshToken,
|
|
130
|
-
client_id: clientId,
|
|
131
|
-
client_secret: clientSecret
|
|
132
|
-
})
|
|
133
|
-
response = await fetch(config.tokenUrl, {
|
|
134
|
-
method: 'POST',
|
|
135
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
136
|
-
body: params.toString()
|
|
137
|
-
})
|
|
138
|
-
break
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
case 'json-body': {
|
|
142
|
-
// Most providers: application/json body
|
|
143
|
-
response = await fetch(config.tokenUrl, {
|
|
144
|
-
method: 'POST',
|
|
145
|
-
headers: { 'Content-Type': 'application/json' },
|
|
146
|
-
body: JSON.stringify({
|
|
147
|
-
grant_type: 'refresh_token',
|
|
148
|
-
refresh_token: token.refreshToken,
|
|
149
|
-
client_id: clientId,
|
|
150
|
-
client_secret: clientSecret
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
break
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
default: {
|
|
157
|
-
throw new Error(`Unsupported token exchange method: ${config.tokenExchange}`)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Handle error response
|
|
162
|
-
if (!response.ok) {
|
|
163
|
-
let errorMessage = `Failed to refresh OAuth token for ${config.id}: ${response.status}`
|
|
164
|
-
|
|
165
|
-
try {
|
|
166
|
-
const errorData = (await response.json()) as Record<string, unknown>
|
|
167
|
-
// Parse OAuth error response (RFC 6749 Section 5.2)
|
|
168
|
-
if (errorData.error) {
|
|
169
|
-
errorMessage += ` - ${errorData.error}`
|
|
170
|
-
if (errorData.error_description) {
|
|
171
|
-
errorMessage += `: ${errorData.error_description}`
|
|
172
|
-
}
|
|
173
|
-
// Identify invalid_grant errors (user must re-authorize)
|
|
174
|
-
if (errorData.error === 'invalid_grant') {
|
|
175
|
-
errorMessage += ' (User must re-authorize)'
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
} catch {
|
|
179
|
-
// If error response is not JSON, use status text
|
|
180
|
-
errorMessage += ` - ${response.statusText}`
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
throw new Error(errorMessage)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const data = (await response.json()) as Record<string, unknown>
|
|
187
|
-
|
|
188
|
-
// Defensive normalization: handle both snake_case (RFC 6749) and camelCase
|
|
189
|
-
const accessToken = (data.access_token ?? data.accessToken) as string | undefined
|
|
190
|
-
const refreshToken = (data.refresh_token ?? data.refreshToken) as string | undefined
|
|
191
|
-
const expiresIn = (data.expires_in ?? data.expiresIn ?? 3600) as number
|
|
192
|
-
|
|
193
|
-
// Validate required fields
|
|
194
|
-
if (!accessToken) {
|
|
195
|
-
throw new Error(
|
|
196
|
-
`Invalid token refresh response: missing access_token. Received keys: ${Object.keys(data).join(', ')}`
|
|
197
|
-
)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
console.log('[OAuth] Token refreshed successfully', {
|
|
201
|
-
provider: token.provider,
|
|
202
|
-
hasNewRefreshToken: !!refreshToken,
|
|
203
|
-
expiresInSeconds: expiresIn,
|
|
204
|
-
validForHours: Math.floor(expiresIn / 3600)
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// Return refreshed token with all original fields preserved
|
|
208
|
-
return {
|
|
209
|
-
...token,
|
|
210
|
-
accessToken,
|
|
211
|
-
refreshToken: refreshToken || token.refreshToken, // Some providers don't return new refresh token
|
|
212
|
-
expiresAt: new Date(Date.now() + expiresIn * 1000).toISOString()
|
|
213
|
-
}
|
|
214
|
-
}
|
|
1
|
+
import { getProviderConfig } from '../provider-registry'
|
|
2
|
+
import type { OAuthToken } from '../types'
|
|
3
|
+
import { getOAuthCredentials } from './credentials'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* In-flight refresh deduplication map.
|
|
7
|
+
* Keyed by `provider:refreshToken` — concurrent callers with the same expired token
|
|
8
|
+
* share a single refresh request instead of racing against each other.
|
|
9
|
+
*/
|
|
10
|
+
const inflightRefreshes = new Map<string, Promise<OAuthToken>>()
|
|
11
|
+
|
|
12
|
+
/** @internal Exposed for testing — do not use in production code. */
|
|
13
|
+
export function _getInflightRefreshCount(): number {
|
|
14
|
+
return inflightRefreshes.size
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Refresh OAuth token if expired (pure function)
|
|
19
|
+
*
|
|
20
|
+
* Checks if token expires within 5 minutes and refreshes if needed.
|
|
21
|
+
* Automatically determines provider config from token.provider field.
|
|
22
|
+
* Respects provider-specific token exchange methods (basic-auth, form-encoded, json-body).
|
|
23
|
+
* Handles both RFC 6749-compliant (snake_case) and non-compliant (camelCase) providers.
|
|
24
|
+
*/
|
|
25
|
+
export async function refreshOAuthTokenIfExpired(token: OAuthToken): Promise<OAuthToken> {
|
|
26
|
+
// Validate token has provider field
|
|
27
|
+
if (!token.provider) {
|
|
28
|
+
throw new Error('Token missing provider field - cannot refresh')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Validate refresh token exists
|
|
32
|
+
if (!token.refreshToken) {
|
|
33
|
+
throw new Error('Token cannot be refreshed (no refresh_token). User must re-authorize.')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Check if token is still valid
|
|
37
|
+
const expiresAt = new Date(token.expiresAt).getTime()
|
|
38
|
+
const now = Date.now()
|
|
39
|
+
const bufferMs = 5 * 60 * 1000 // 5 minutes
|
|
40
|
+
|
|
41
|
+
if (expiresAt > now + bufferMs) {
|
|
42
|
+
console.log('[OAuth] Token still valid, no refresh needed', {
|
|
43
|
+
provider: token.provider,
|
|
44
|
+
expiresAt: token.expiresAt,
|
|
45
|
+
remainingMinutes: Math.floor((expiresAt - now) / 60000)
|
|
46
|
+
})
|
|
47
|
+
return token // Still valid
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Token expired, delegate to force refresh
|
|
51
|
+
return forceRefreshOAuthToken(token)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Force refresh OAuth token (bypasses expiry check)
|
|
56
|
+
*
|
|
57
|
+
* Use this when you receive a 401 from the API even though the token
|
|
58
|
+
* appeared valid based on expiresAt. This handles cases where:
|
|
59
|
+
* - The stored expiresAt is stale/incorrect
|
|
60
|
+
* - The token was revoked before expiry
|
|
61
|
+
* - Clock skew between systems
|
|
62
|
+
*/
|
|
63
|
+
export async function forceRefreshOAuthToken(token: OAuthToken): Promise<OAuthToken> {
|
|
64
|
+
// Validate token has provider field
|
|
65
|
+
if (!token.provider) {
|
|
66
|
+
throw new Error('Token missing provider field - cannot refresh')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Validate refresh token exists
|
|
70
|
+
if (!token.refreshToken) {
|
|
71
|
+
throw new Error('Token cannot be refreshed (no refresh_token). User must re-authorize.')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Deduplicate concurrent refreshes for the same token
|
|
75
|
+
const dedupeKey = `${token.provider}:${token.refreshToken}`
|
|
76
|
+
const inflight = inflightRefreshes.get(dedupeKey)
|
|
77
|
+
if (inflight) {
|
|
78
|
+
console.log('[OAuth] Reusing in-flight refresh', { provider: token.provider })
|
|
79
|
+
return inflight
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const refreshPromise = performTokenRefresh(token)
|
|
83
|
+
inflightRefreshes.set(dedupeKey, refreshPromise)
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
return await refreshPromise
|
|
87
|
+
} finally {
|
|
88
|
+
inflightRefreshes.delete(dedupeKey)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function performTokenRefresh(token: OAuthToken): Promise<OAuthToken> {
|
|
93
|
+
console.log('[OAuth] Force refreshing token', {
|
|
94
|
+
provider: token.provider,
|
|
95
|
+
expiresAt: token.expiresAt
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// Get provider configuration
|
|
99
|
+
const config = getProviderConfig(token.provider)
|
|
100
|
+
|
|
101
|
+
// Get client credentials from environment
|
|
102
|
+
const { clientId, clientSecret } = getOAuthCredentials(config.id)
|
|
103
|
+
|
|
104
|
+
// Perform token refresh using provider-specific exchange method
|
|
105
|
+
let response: Response
|
|
106
|
+
|
|
107
|
+
switch (config.tokenExchange) {
|
|
108
|
+
case 'basic-auth': {
|
|
109
|
+
// Notion pattern: Authorization: Basic {base64(clientId:clientSecret)}
|
|
110
|
+
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64')
|
|
111
|
+
response = await fetch(config.tokenUrl, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: {
|
|
114
|
+
Authorization: `Basic ${credentials}`,
|
|
115
|
+
'Content-Type': 'application/json'
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
grant_type: 'refresh_token',
|
|
119
|
+
refresh_token: token.refreshToken
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
break
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
case 'form-encoded': {
|
|
126
|
+
// Google pattern: application/x-www-form-urlencoded body
|
|
127
|
+
const params = new URLSearchParams({
|
|
128
|
+
grant_type: 'refresh_token',
|
|
129
|
+
refresh_token: token.refreshToken,
|
|
130
|
+
client_id: clientId,
|
|
131
|
+
client_secret: clientSecret
|
|
132
|
+
})
|
|
133
|
+
response = await fetch(config.tokenUrl, {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
136
|
+
body: params.toString()
|
|
137
|
+
})
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case 'json-body': {
|
|
142
|
+
// Most providers: application/json body
|
|
143
|
+
response = await fetch(config.tokenUrl, {
|
|
144
|
+
method: 'POST',
|
|
145
|
+
headers: { 'Content-Type': 'application/json' },
|
|
146
|
+
body: JSON.stringify({
|
|
147
|
+
grant_type: 'refresh_token',
|
|
148
|
+
refresh_token: token.refreshToken,
|
|
149
|
+
client_id: clientId,
|
|
150
|
+
client_secret: clientSecret
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
break
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
default: {
|
|
157
|
+
throw new Error(`Unsupported token exchange method: ${config.tokenExchange}`)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Handle error response
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
let errorMessage = `Failed to refresh OAuth token for ${config.id}: ${response.status}`
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const errorData = (await response.json()) as Record<string, unknown>
|
|
167
|
+
// Parse OAuth error response (RFC 6749 Section 5.2)
|
|
168
|
+
if (errorData.error) {
|
|
169
|
+
errorMessage += ` - ${errorData.error}`
|
|
170
|
+
if (errorData.error_description) {
|
|
171
|
+
errorMessage += `: ${errorData.error_description}`
|
|
172
|
+
}
|
|
173
|
+
// Identify invalid_grant errors (user must re-authorize)
|
|
174
|
+
if (errorData.error === 'invalid_grant') {
|
|
175
|
+
errorMessage += ' (User must re-authorize)'
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
// If error response is not JSON, use status text
|
|
180
|
+
errorMessage += ` - ${response.statusText}`
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
throw new Error(errorMessage)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const data = (await response.json()) as Record<string, unknown>
|
|
187
|
+
|
|
188
|
+
// Defensive normalization: handle both snake_case (RFC 6749) and camelCase
|
|
189
|
+
const accessToken = (data.access_token ?? data.accessToken) as string | undefined
|
|
190
|
+
const refreshToken = (data.refresh_token ?? data.refreshToken) as string | undefined
|
|
191
|
+
const expiresIn = (data.expires_in ?? data.expiresIn ?? 3600) as number
|
|
192
|
+
|
|
193
|
+
// Validate required fields
|
|
194
|
+
if (!accessToken) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Invalid token refresh response: missing access_token. Received keys: ${Object.keys(data).join(', ')}`
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
console.log('[OAuth] Token refreshed successfully', {
|
|
201
|
+
provider: token.provider,
|
|
202
|
+
hasNewRefreshToken: !!refreshToken,
|
|
203
|
+
expiresInSeconds: expiresIn,
|
|
204
|
+
validForHours: Math.floor(expiresIn / 3600)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
// Return refreshed token with all original fields preserved
|
|
208
|
+
return {
|
|
209
|
+
...token,
|
|
210
|
+
accessToken,
|
|
211
|
+
refreshToken: refreshToken || token.refreshToken, // Some providers don't return new refresh token
|
|
212
|
+
expiresAt: new Date(Date.now() + expiresIn * 1000).toISOString()
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
export interface OAuthToken extends Record<string, unknown> {
|
|
2
|
-
provider: string // OAuth provider ID (notion, google-sheets)
|
|
3
|
-
accessToken: string
|
|
4
|
-
refreshToken: string
|
|
5
|
-
expiresAt: string // ISO 8601 timestamp
|
|
6
|
-
tokenType: 'Bearer'
|
|
7
|
-
scope?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface OAuthProviderConfig {
|
|
11
|
-
id: string
|
|
12
|
-
name: string
|
|
13
|
-
authUrl: string
|
|
14
|
-
tokenUrl: string
|
|
15
|
-
scopes?: string[]
|
|
16
|
-
authParams?: Record<string, string> // Provider-specific auth params
|
|
17
|
-
tokenExchange: 'basic-auth' | 'form-encoded' | 'json-body'
|
|
18
|
-
usePKCE?: boolean
|
|
19
|
-
|
|
20
|
-
// Custom override hooks for edge cases (95% won't need these)
|
|
21
|
-
customAuthFlow?: (config: OAuthProviderConfig, state: OAuthState) => URL
|
|
22
|
-
customTokenExchange?: (
|
|
23
|
-
code: string,
|
|
24
|
-
config: OAuthProviderConfig
|
|
25
|
-
) => Promise<OAuthToken>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface OAuthState {
|
|
29
|
-
organizationId: string
|
|
30
|
-
nonce: string
|
|
31
|
-
timestamp: number
|
|
32
|
-
credentialName: string
|
|
33
|
-
provider: string // Which provider this flow is for
|
|
34
|
-
}
|
|
1
|
+
export interface OAuthToken extends Record<string, unknown> {
|
|
2
|
+
provider: string // OAuth provider ID (notion, google-sheets)
|
|
3
|
+
accessToken: string
|
|
4
|
+
refreshToken: string
|
|
5
|
+
expiresAt: string // ISO 8601 timestamp
|
|
6
|
+
tokenType: 'Bearer'
|
|
7
|
+
scope?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface OAuthProviderConfig {
|
|
11
|
+
id: string
|
|
12
|
+
name: string
|
|
13
|
+
authUrl: string
|
|
14
|
+
tokenUrl: string
|
|
15
|
+
scopes?: string[]
|
|
16
|
+
authParams?: Record<string, string> // Provider-specific auth params
|
|
17
|
+
tokenExchange: 'basic-auth' | 'form-encoded' | 'json-body'
|
|
18
|
+
usePKCE?: boolean
|
|
19
|
+
|
|
20
|
+
// Custom override hooks for edge cases (95% won't need these)
|
|
21
|
+
customAuthFlow?: (config: OAuthProviderConfig, state: OAuthState) => URL
|
|
22
|
+
customTokenExchange?: (
|
|
23
|
+
code: string,
|
|
24
|
+
config: OAuthProviderConfig
|
|
25
|
+
) => Promise<OAuthToken>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface OAuthState {
|
|
29
|
+
organizationId: string
|
|
30
|
+
nonce: string
|
|
31
|
+
timestamp: number
|
|
32
|
+
credentialName: string
|
|
33
|
+
provider: string // Which provider this flow is for
|
|
34
|
+
}
|