@37signals/basecamp 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +600 -0
- package/dist/auth-strategy.d.ts +36 -0
- package/dist/auth-strategy.d.ts.map +1 -0
- package/dist/auth-strategy.js +33 -0
- package/dist/auth-strategy.js.map +1 -0
- package/dist/client.d.ts +224 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +715 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +137 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +269 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/metadata.json +2281 -0
- package/dist/generated/openapi-stripped.json +21268 -0
- package/dist/generated/path-mapping.d.ts +8 -0
- package/dist/generated/path-mapping.d.ts.map +1 -0
- package/dist/generated/path-mapping.js +192 -0
- package/dist/generated/path-mapping.js.map +1 -0
- package/dist/generated/path-mapping.ts +199 -0
- package/dist/generated/schema.d.ts +14883 -0
- package/dist/generated/services/attachments.d.ts +27 -0
- package/dist/generated/services/attachments.d.ts.map +1 -0
- package/dist/generated/services/attachments.js +49 -0
- package/dist/generated/services/attachments.js.map +1 -0
- package/dist/generated/services/attachments.ts +59 -0
- package/dist/generated/services/boosts.d.ts +114 -0
- package/dist/generated/services/boosts.d.ts.map +1 -0
- package/dist/generated/services/boosts.js +179 -0
- package/dist/generated/services/boosts.js.map +1 -0
- package/dist/generated/services/boosts.ts +250 -0
- package/dist/generated/services/campfires.d.ts +202 -0
- package/dist/generated/services/campfires.d.ts.map +1 -0
- package/dist/generated/services/campfires.js +309 -0
- package/dist/generated/services/campfires.js.map +1 -0
- package/dist/generated/services/campfires.ts +433 -0
- package/dist/generated/services/card-columns.d.ts +163 -0
- package/dist/generated/services/card-columns.d.ts.map +1 -0
- package/dist/generated/services/card-columns.js +264 -0
- package/dist/generated/services/card-columns.js.map +1 -0
- package/dist/generated/services/card-columns.ts +360 -0
- package/dist/generated/services/card-steps.d.ts +105 -0
- package/dist/generated/services/card-steps.d.ts.map +1 -0
- package/dist/generated/services/card-steps.js +148 -0
- package/dist/generated/services/card-steps.js.map +1 -0
- package/dist/generated/services/card-steps.ts +221 -0
- package/dist/generated/services/card-tables.d.ts +27 -0
- package/dist/generated/services/card-tables.d.ts.map +1 -0
- package/dist/generated/services/card-tables.js +40 -0
- package/dist/generated/services/card-tables.js.map +1 -0
- package/dist/generated/services/card-tables.ts +55 -0
- package/dist/generated/services/cards.d.ts +118 -0
- package/dist/generated/services/cards.d.ts.map +1 -0
- package/dist/generated/services/cards.js +166 -0
- package/dist/generated/services/cards.js.map +1 -0
- package/dist/generated/services/cards.ts +247 -0
- package/dist/generated/services/checkins.d.ts +278 -0
- package/dist/generated/services/checkins.d.ts.map +1 -0
- package/dist/generated/services/checkins.js +420 -0
- package/dist/generated/services/checkins.js.map +1 -0
- package/dist/generated/services/checkins.ts +600 -0
- package/dist/generated/services/client-approvals.d.ts +45 -0
- package/dist/generated/services/client-approvals.d.ts.map +1 -0
- package/dist/generated/services/client-approvals.js +58 -0
- package/dist/generated/services/client-approvals.js.map +1 -0
- package/dist/generated/services/client-approvals.ts +89 -0
- package/dist/generated/services/client-correspondences.d.ts +45 -0
- package/dist/generated/services/client-correspondences.d.ts.map +1 -0
- package/dist/generated/services/client-correspondences.js +58 -0
- package/dist/generated/services/client-correspondences.js.map +1 -0
- package/dist/generated/services/client-correspondences.ts +89 -0
- package/dist/generated/services/client-replies.d.ts +47 -0
- package/dist/generated/services/client-replies.d.ts.map +1 -0
- package/dist/generated/services/client-replies.js +65 -0
- package/dist/generated/services/client-replies.js.map +1 -0
- package/dist/generated/services/client-replies.ts +95 -0
- package/dist/generated/services/client-visibility.d.ts +35 -0
- package/dist/generated/services/client-visibility.d.ts.map +1 -0
- package/dist/generated/services/client-visibility.js +44 -0
- package/dist/generated/services/client-visibility.js.map +1 -0
- package/dist/generated/services/client-visibility.ts +68 -0
- package/dist/generated/services/comments.d.ts +86 -0
- package/dist/generated/services/comments.d.ts.map +1 -0
- package/dist/generated/services/comments.js +129 -0
- package/dist/generated/services/comments.js.map +1 -0
- package/dist/generated/services/comments.ts +185 -0
- package/dist/generated/services/documents.d.ts +92 -0
- package/dist/generated/services/documents.d.ts.map +1 -0
- package/dist/generated/services/documents.js +129 -0
- package/dist/generated/services/documents.js.map +1 -0
- package/dist/generated/services/documents.ts +191 -0
- package/dist/generated/services/events.d.ts +34 -0
- package/dist/generated/services/events.d.ts.map +1 -0
- package/dist/generated/services/events.js +39 -0
- package/dist/generated/services/events.js.map +1 -0
- package/dist/generated/services/events.ts +64 -0
- package/dist/generated/services/forwards.d.ts +112 -0
- package/dist/generated/services/forwards.d.ts.map +1 -0
- package/dist/generated/services/forwards.js +172 -0
- package/dist/generated/services/forwards.js.map +1 -0
- package/dist/generated/services/forwards.ts +241 -0
- package/dist/generated/services/index.d.ts +39 -0
- package/dist/generated/services/index.d.ts.map +1 -0
- package/dist/generated/services/index.js +39 -0
- package/dist/generated/services/index.js.map +1 -0
- package/dist/generated/services/index.ts +38 -0
- package/dist/generated/services/lineup.d.ts +67 -0
- package/dist/generated/services/lineup.d.ts.map +1 -0
- package/dist/generated/services/lineup.js +99 -0
- package/dist/generated/services/lineup.js.map +1 -0
- package/dist/generated/services/lineup.ts +143 -0
- package/dist/generated/services/message-boards.d.ts +27 -0
- package/dist/generated/services/message-boards.d.ts.map +1 -0
- package/dist/generated/services/message-boards.js +40 -0
- package/dist/generated/services/message-boards.js.map +1 -0
- package/dist/generated/services/message-boards.ts +55 -0
- package/dist/generated/services/message-types.d.ts +100 -0
- package/dist/generated/services/message-types.d.ts.map +1 -0
- package/dist/generated/services/message-types.js +144 -0
- package/dist/generated/services/message-types.js.map +1 -0
- package/dist/generated/services/message-types.ts +210 -0
- package/dist/generated/services/messages.d.ts +122 -0
- package/dist/generated/services/messages.d.ts.map +1 -0
- package/dist/generated/services/messages.js +180 -0
- package/dist/generated/services/messages.js.map +1 -0
- package/dist/generated/services/messages.ts +258 -0
- package/dist/generated/services/people.d.ts +122 -0
- package/dist/generated/services/people.d.ts.map +1 -0
- package/dist/generated/services/people.js +167 -0
- package/dist/generated/services/people.js.map +1 -0
- package/dist/generated/services/people.ts +252 -0
- package/dist/generated/services/projects.d.ts +109 -0
- package/dist/generated/services/projects.d.ts.map +1 -0
- package/dist/generated/services/projects.js +153 -0
- package/dist/generated/services/projects.js.map +1 -0
- package/dist/generated/services/projects.ts +224 -0
- package/dist/generated/services/recordings.d.ts +93 -0
- package/dist/generated/services/recordings.d.ts.map +1 -0
- package/dist/generated/services/recordings.js +138 -0
- package/dist/generated/services/recordings.js.map +1 -0
- package/dist/generated/services/recordings.ts +191 -0
- package/dist/generated/services/reports.d.ts +90 -0
- package/dist/generated/services/reports.d.ts.map +1 -0
- package/dist/generated/services/reports.js +124 -0
- package/dist/generated/services/reports.js.map +1 -0
- package/dist/generated/services/reports.ts +187 -0
- package/dist/generated/services/schedules.d.ts +162 -0
- package/dist/generated/services/schedules.d.ts.map +1 -0
- package/dist/generated/services/schedules.js +228 -0
- package/dist/generated/services/schedules.js.map +1 -0
- package/dist/generated/services/schedules.ts +335 -0
- package/dist/generated/services/search.d.ts +45 -0
- package/dist/generated/services/search.d.ts.map +1 -0
- package/dist/generated/services/search.js +56 -0
- package/dist/generated/services/search.js.map +1 -0
- package/dist/generated/services/search.ts +89 -0
- package/dist/generated/services/subscriptions.d.ts +73 -0
- package/dist/generated/services/subscriptions.d.ts.map +1 -0
- package/dist/generated/services/subscriptions.js +119 -0
- package/dist/generated/services/subscriptions.js.map +1 -0
- package/dist/generated/services/subscriptions.ts +160 -0
- package/dist/generated/services/templates.d.ts +140 -0
- package/dist/generated/services/templates.d.ts.map +1 -0
- package/dist/generated/services/templates.js +207 -0
- package/dist/generated/services/templates.js.map +1 -0
- package/dist/generated/services/templates.ts +294 -0
- package/dist/generated/services/timeline.d.ts +31 -0
- package/dist/generated/services/timeline.d.ts.map +1 -0
- package/dist/generated/services/timeline.js +39 -0
- package/dist/generated/services/timeline.js.map +1 -0
- package/dist/generated/services/timeline.ts +62 -0
- package/dist/generated/services/timesheets.d.ts +145 -0
- package/dist/generated/services/timesheets.d.ts.map +1 -0
- package/dist/generated/services/timesheets.js +186 -0
- package/dist/generated/services/timesheets.js.map +1 -0
- package/dist/generated/services/timesheets.ts +289 -0
- package/dist/generated/services/todolist-groups.d.ts +74 -0
- package/dist/generated/services/todolist-groups.d.ts.map +1 -0
- package/dist/generated/services/todolist-groups.js +100 -0
- package/dist/generated/services/todolist-groups.js.map +1 -0
- package/dist/generated/services/todolist-groups.ts +151 -0
- package/dist/generated/services/todolists.d.ts +95 -0
- package/dist/generated/services/todolists.d.ts.map +1 -0
- package/dist/generated/services/todolists.js +130 -0
- package/dist/generated/services/todolists.js.map +1 -0
- package/dist/generated/services/todolists.ts +192 -0
- package/dist/generated/services/todos.d.ts +175 -0
- package/dist/generated/services/todos.d.ts.map +1 -0
- package/dist/generated/services/todos.js +255 -0
- package/dist/generated/services/todos.js.map +1 -0
- package/dist/generated/services/todos.ts +369 -0
- package/dist/generated/services/todosets.d.ts +27 -0
- package/dist/generated/services/todosets.d.ts.map +1 -0
- package/dist/generated/services/todosets.js +40 -0
- package/dist/generated/services/todosets.js.map +1 -0
- package/dist/generated/services/todosets.ts +55 -0
- package/dist/generated/services/tools.d.ts +122 -0
- package/dist/generated/services/tools.d.ts.map +1 -0
- package/dist/generated/services/tools.js +197 -0
- package/dist/generated/services/tools.js.map +1 -0
- package/dist/generated/services/tools.ts +267 -0
- package/dist/generated/services/uploads.d.ts +109 -0
- package/dist/generated/services/uploads.d.ts.map +1 -0
- package/dist/generated/services/uploads.js +153 -0
- package/dist/generated/services/uploads.js.map +1 -0
- package/dist/generated/services/uploads.ts +227 -0
- package/dist/generated/services/vaults.d.ts +86 -0
- package/dist/generated/services/vaults.d.ts.map +1 -0
- package/dist/generated/services/vaults.js +126 -0
- package/dist/generated/services/vaults.js.map +1 -0
- package/dist/generated/services/vaults.ts +182 -0
- package/dist/generated/services/webhooks.d.ts +106 -0
- package/dist/generated/services/webhooks.d.ts.map +1 -0
- package/dist/generated/services/webhooks.js +157 -0
- package/dist/generated/services/webhooks.js.map +1 -0
- package/dist/generated/services/webhooks.ts +226 -0
- package/dist/hooks/otel.d.ts +136 -0
- package/dist/hooks/otel.d.ts.map +1 -0
- package/dist/hooks/otel.js +240 -0
- package/dist/hooks/otel.js.map +1 -0
- package/dist/hooks.d.ts +171 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +196 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +122 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth/authorize.d.ts +48 -0
- package/dist/oauth/authorize.d.ts.map +1 -0
- package/dist/oauth/authorize.js +56 -0
- package/dist/oauth/authorize.js.map +1 -0
- package/dist/oauth/callback-server.d.ts +56 -0
- package/dist/oauth/callback-server.d.ts.map +1 -0
- package/dist/oauth/callback-server.js +150 -0
- package/dist/oauth/callback-server.js.map +1 -0
- package/dist/oauth/discovery.d.ts +54 -0
- package/dist/oauth/discovery.d.ts.map +1 -0
- package/dist/oauth/discovery.js +116 -0
- package/dist/oauth/discovery.js.map +1 -0
- package/dist/oauth/exchange.d.ts +96 -0
- package/dist/oauth/exchange.d.ts.map +1 -0
- package/dist/oauth/exchange.js +324 -0
- package/dist/oauth/exchange.js.map +1 -0
- package/dist/oauth/identity.d.ts +30 -0
- package/dist/oauth/identity.d.ts.map +1 -0
- package/dist/oauth/identity.js +82 -0
- package/dist/oauth/identity.js.map +1 -0
- package/dist/oauth/index.d.ts +50 -0
- package/dist/oauth/index.d.ts.map +1 -0
- package/dist/oauth/index.js +58 -0
- package/dist/oauth/index.js.map +1 -0
- package/dist/oauth/interactive-login.d.ts +62 -0
- package/dist/oauth/interactive-login.d.ts.map +1 -0
- package/dist/oauth/interactive-login.js +106 -0
- package/dist/oauth/interactive-login.js.map +1 -0
- package/dist/oauth/pkce.d.ts +68 -0
- package/dist/oauth/pkce.d.ts.map +1 -0
- package/dist/oauth/pkce.js +80 -0
- package/dist/oauth/pkce.js.map +1 -0
- package/dist/oauth/token-manager.d.ts +92 -0
- package/dist/oauth/token-manager.d.ts.map +1 -0
- package/dist/oauth/token-manager.js +126 -0
- package/dist/oauth/token-manager.js.map +1 -0
- package/dist/oauth/token-store.d.ts +45 -0
- package/dist/oauth/token-store.d.ts.map +1 -0
- package/dist/oauth/token-store.js +105 -0
- package/dist/oauth/token-store.js.map +1 -0
- package/dist/oauth/types.d.ts +98 -0
- package/dist/oauth/types.d.ts.map +1 -0
- package/dist/oauth/types.js +8 -0
- package/dist/oauth/types.js.map +1 -0
- package/dist/pagination-utils.d.ts +27 -0
- package/dist/pagination-utils.d.ts.map +1 -0
- package/dist/pagination-utils.js +54 -0
- package/dist/pagination-utils.js.map +1 -0
- package/dist/pagination.d.ts +56 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +57 -0
- package/dist/pagination.js.map +1 -0
- package/dist/security.d.ts +68 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +107 -0
- package/dist/security.js.map +1 -0
- package/dist/services/authorization.d.ts +124 -0
- package/dist/services/authorization.d.ts.map +1 -0
- package/dist/services/authorization.js +117 -0
- package/dist/services/authorization.js.map +1 -0
- package/dist/services/base.d.ts +102 -0
- package/dist/services/base.d.ts.map +1 -0
- package/dist/services/base.js +230 -0
- package/dist/services/base.js.map +1 -0
- package/dist/webhooks/adapters/node-http.d.ts +14 -0
- package/dist/webhooks/adapters/node-http.d.ts.map +1 -0
- package/dist/webhooks/adapters/node-http.js +60 -0
- package/dist/webhooks/adapters/node-http.js.map +1 -0
- package/dist/webhooks/events.d.ts +52 -0
- package/dist/webhooks/events.d.ts.map +1 -0
- package/dist/webhooks/events.js +52 -0
- package/dist/webhooks/events.js.map +1 -0
- package/dist/webhooks/handler.d.ts +62 -0
- package/dist/webhooks/handler.d.ts.map +1 -0
- package/dist/webhooks/handler.js +226 -0
- package/dist/webhooks/handler.js.map +1 -0
- package/dist/webhooks/index.d.ts +5 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +5 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/verify.d.ts +11 -0
- package/dist/webhooks/verify.d.ts.map +1 -0
- package/dist/webhooks/verify.js +25 -0
- package/dist/webhooks/verify.js.map +1 -0
- package/package.json +70 -0
- package/src/generated/metadata.json +2281 -0
- package/src/generated/openapi-stripped.json +21268 -0
- package/src/generated/path-mapping.ts +199 -0
- package/src/generated/schema.d.ts +14883 -0
- package/src/generated/services/attachments.ts +59 -0
- package/src/generated/services/boosts.ts +250 -0
- package/src/generated/services/campfires.ts +433 -0
- package/src/generated/services/card-columns.ts +360 -0
- package/src/generated/services/card-steps.ts +221 -0
- package/src/generated/services/card-tables.ts +55 -0
- package/src/generated/services/cards.ts +247 -0
- package/src/generated/services/checkins.ts +600 -0
- package/src/generated/services/client-approvals.ts +89 -0
- package/src/generated/services/client-correspondences.ts +89 -0
- package/src/generated/services/client-replies.ts +95 -0
- package/src/generated/services/client-visibility.ts +68 -0
- package/src/generated/services/comments.ts +185 -0
- package/src/generated/services/documents.ts +191 -0
- package/src/generated/services/events.ts +64 -0
- package/src/generated/services/forwards.ts +241 -0
- package/src/generated/services/index.ts +38 -0
- package/src/generated/services/lineup.ts +143 -0
- package/src/generated/services/message-boards.ts +55 -0
- package/src/generated/services/message-types.ts +210 -0
- package/src/generated/services/messages.ts +258 -0
- package/src/generated/services/people.ts +252 -0
- package/src/generated/services/projects.ts +224 -0
- package/src/generated/services/recordings.ts +191 -0
- package/src/generated/services/reports.ts +187 -0
- package/src/generated/services/schedules.ts +335 -0
- package/src/generated/services/search.ts +89 -0
- package/src/generated/services/subscriptions.ts +160 -0
- package/src/generated/services/templates.ts +294 -0
- package/src/generated/services/timeline.ts +62 -0
- package/src/generated/services/timesheets.ts +289 -0
- package/src/generated/services/todolist-groups.ts +151 -0
- package/src/generated/services/todolists.ts +192 -0
- package/src/generated/services/todos.ts +369 -0
- package/src/generated/services/todosets.ts +55 -0
- package/src/generated/services/tools.ts +267 -0
- package/src/generated/services/uploads.ts +227 -0
- package/src/generated/services/vaults.ts +182 -0
- package/src/generated/services/webhooks.ts +226 -0
package/README.md
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
# Basecamp TypeScript SDK
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@37signals/basecamp)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
[](https://github.com/basecamp/basecamp-sdk/actions/workflows/test.yml)
|
|
6
|
+
|
|
7
|
+
Official TypeScript SDK for the [Basecamp 3 API](https://github.com/basecamp/bc3-api).
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Full type safety with TypeScript generics
|
|
12
|
+
- 30+ services covering the complete Basecamp API
|
|
13
|
+
- OAuth 2.0 with PKCE support
|
|
14
|
+
- ETag-based HTTP caching
|
|
15
|
+
- Automatic retry with exponential backoff
|
|
16
|
+
- Pagination helpers for large result sets
|
|
17
|
+
- Observability hooks for logging, metrics, and tracing
|
|
18
|
+
- OpenTelemetry integration
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @37signals/basecamp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Requires Node.js 18+ and TypeScript 5.0+.
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { createBasecampClient } from "@37signals/basecamp";
|
|
32
|
+
|
|
33
|
+
const client = createBasecampClient({
|
|
34
|
+
accountId: process.env.BASECAMP_ACCOUNT_ID!,
|
|
35
|
+
accessToken: process.env.BASECAMP_TOKEN!,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// List all projects
|
|
39
|
+
const projects = await client.projects.list();
|
|
40
|
+
for (const project of projects) {
|
|
41
|
+
console.log(`${project.id}: ${project.name}`);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
### Client Options
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createBasecampClient } from "@37signals/basecamp";
|
|
51
|
+
|
|
52
|
+
const client = createBasecampClient({
|
|
53
|
+
// Required
|
|
54
|
+
accountId: "12345",
|
|
55
|
+
accessToken: "your-token", // or async token provider
|
|
56
|
+
|
|
57
|
+
// Optional
|
|
58
|
+
baseUrl: "https://3.basecampapi.com/12345", // default
|
|
59
|
+
userAgent: "my-app/1.0",
|
|
60
|
+
enableCache: true, // ETag caching (default: true)
|
|
61
|
+
enableRetry: true, // Auto retry 429 and 503 (default: true)
|
|
62
|
+
hooks: myHooks, // Observability hooks
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Token Providers
|
|
67
|
+
|
|
68
|
+
For simple use cases, pass a static token string:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const client = createBasecampClient({
|
|
72
|
+
accountId: "12345",
|
|
73
|
+
accessToken: "your-access-token",
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
For token refresh scenarios, pass an async function:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
const client = createBasecampClient({
|
|
81
|
+
accountId: "12345",
|
|
82
|
+
accessToken: async () => {
|
|
83
|
+
// Fetch or refresh your token
|
|
84
|
+
const token = await myTokenStore.getValidToken();
|
|
85
|
+
return token.accessToken;
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## OAuth 2.0
|
|
91
|
+
|
|
92
|
+
The SDK includes utilities for implementing OAuth 2.0 with PKCE support.
|
|
93
|
+
|
|
94
|
+
### Authorization Flow
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import {
|
|
98
|
+
discoverLaunchpad,
|
|
99
|
+
generatePKCE,
|
|
100
|
+
generateState,
|
|
101
|
+
exchangeCode,
|
|
102
|
+
refreshToken,
|
|
103
|
+
isTokenExpired,
|
|
104
|
+
} from "@37signals/basecamp";
|
|
105
|
+
|
|
106
|
+
// 1. Discover OAuth endpoints
|
|
107
|
+
const config = await discoverLaunchpad();
|
|
108
|
+
|
|
109
|
+
// 2. Generate PKCE challenge and state
|
|
110
|
+
const pkce = await generatePKCE();
|
|
111
|
+
const state = generateState();
|
|
112
|
+
|
|
113
|
+
// Store pkce.verifier and state in session for later
|
|
114
|
+
|
|
115
|
+
// 3. Build authorization URL with PKCE challenge
|
|
116
|
+
const authUrl = new URL(config.authorizationEndpoint);
|
|
117
|
+
authUrl.searchParams.set("type", "web_server");
|
|
118
|
+
authUrl.searchParams.set("client_id", CLIENT_ID);
|
|
119
|
+
authUrl.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
120
|
+
authUrl.searchParams.set("state", state);
|
|
121
|
+
authUrl.searchParams.set("code_challenge", pkce.challenge);
|
|
122
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
123
|
+
// Redirect user to authUrl.toString()
|
|
124
|
+
|
|
125
|
+
// 4. Exchange code for tokens (in callback handler)
|
|
126
|
+
const token = await exchangeCode({
|
|
127
|
+
tokenEndpoint: config.tokenEndpoint,
|
|
128
|
+
code: callbackParams.code,
|
|
129
|
+
redirectUri: REDIRECT_URI,
|
|
130
|
+
clientId: CLIENT_ID,
|
|
131
|
+
clientSecret: CLIENT_SECRET,
|
|
132
|
+
codeVerifier: pkce.verifier, // PKCE verifier from step 2
|
|
133
|
+
useLegacyFormat: true, // Required for Basecamp Launchpad
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 5. Refresh when expired
|
|
137
|
+
if (isTokenExpired(token)) {
|
|
138
|
+
const newToken = await refreshToken({
|
|
139
|
+
tokenEndpoint: config.tokenEndpoint,
|
|
140
|
+
refreshToken: token.refreshToken!,
|
|
141
|
+
useLegacyFormat: true,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Services
|
|
147
|
+
|
|
148
|
+
The SDK provides typed services for the complete Basecamp API:
|
|
149
|
+
|
|
150
|
+
### Projects & Organization
|
|
151
|
+
|
|
152
|
+
| Service | Methods |
|
|
153
|
+
|---------|---------|
|
|
154
|
+
| `projects` | list, get, create, update, trash |
|
|
155
|
+
| `templates` | list, get, createProject |
|
|
156
|
+
| `tools` | list, get, update |
|
|
157
|
+
| `people` | list, get, me, listPingable |
|
|
158
|
+
|
|
159
|
+
### To-dos
|
|
160
|
+
|
|
161
|
+
| Service | Methods |
|
|
162
|
+
|---------|---------|
|
|
163
|
+
| `todos` | list, get, create, update, trash, complete, uncomplete, reposition |
|
|
164
|
+
| `todolists` | list, get, create, update, trash |
|
|
165
|
+
| `todosets` | get |
|
|
166
|
+
| `todolistGroups` | list, get, create, reposition |
|
|
167
|
+
|
|
168
|
+
### Messages & Communication
|
|
169
|
+
|
|
170
|
+
| Service | Methods |
|
|
171
|
+
|---------|---------|
|
|
172
|
+
| `messages` | list, get, create, update, pin, unpin |
|
|
173
|
+
| `messageBoards` | get |
|
|
174
|
+
| `messageTypes` | list, get, create, update, delete |
|
|
175
|
+
| `comments` | list, get, create, update |
|
|
176
|
+
| `campfires` | list, get, listLines, getLine, createLine, deleteLine |
|
|
177
|
+
|
|
178
|
+
### Card Tables (Kanban)
|
|
179
|
+
|
|
180
|
+
| Service | Methods |
|
|
181
|
+
|---------|---------|
|
|
182
|
+
| `cardTables` | get, listColumns |
|
|
183
|
+
| `cards` | list, get, create, update, move |
|
|
184
|
+
| `cardColumns` | get, create, update, move |
|
|
185
|
+
| `cardSteps` | list, get, create, update, complete, uncomplete |
|
|
186
|
+
|
|
187
|
+
### Scheduling
|
|
188
|
+
|
|
189
|
+
| Service | Methods |
|
|
190
|
+
|---------|---------|
|
|
191
|
+
| `schedules` | get, listEntries, getEntry, createEntry, updateEntry, trashEntry |
|
|
192
|
+
| `lineup` | create, update, delete |
|
|
193
|
+
| `checkins` | get, listQuestions, getQuestion, listAnswers, getAnswer |
|
|
194
|
+
|
|
195
|
+
### Files & Documents
|
|
196
|
+
|
|
197
|
+
| Service | Methods |
|
|
198
|
+
|---------|---------|
|
|
199
|
+
| `vaults` | list, get, create, update |
|
|
200
|
+
| `documents` | list, get, create, update, trash |
|
|
201
|
+
| `uploads` | list, get, create, update, trash |
|
|
202
|
+
| `attachments` | createUploadUrl, create |
|
|
203
|
+
|
|
204
|
+
### Integrations & Events
|
|
205
|
+
|
|
206
|
+
| Service | Methods |
|
|
207
|
+
|---------|---------|
|
|
208
|
+
| `webhooks` | list, get, create, update, delete |
|
|
209
|
+
| `subscriptions` | get, subscribe, unsubscribe, update |
|
|
210
|
+
| `events` | list, listForRecording |
|
|
211
|
+
| `recordings` | archive, unarchive, trash |
|
|
212
|
+
|
|
213
|
+
### Search & Reports
|
|
214
|
+
|
|
215
|
+
| Service | Methods |
|
|
216
|
+
|---------|---------|
|
|
217
|
+
| `search` | search |
|
|
218
|
+
| `reports` | progress, upcoming, assigned, overdue, personProgress |
|
|
219
|
+
| `timesheets` | forRecording, forProject, report |
|
|
220
|
+
| `timeline` | get |
|
|
221
|
+
|
|
222
|
+
### Client Portal
|
|
223
|
+
|
|
224
|
+
| Service | Methods |
|
|
225
|
+
|---------|---------|
|
|
226
|
+
| `clientApprovals` | list, get |
|
|
227
|
+
| `clientCorrespondences` | list, get |
|
|
228
|
+
| `clientReplies` | list, get |
|
|
229
|
+
| `clientVisibility` | get, update |
|
|
230
|
+
|
|
231
|
+
### Email
|
|
232
|
+
|
|
233
|
+
| Service | Methods |
|
|
234
|
+
|---------|---------|
|
|
235
|
+
| `forwards` | list, get, createReply |
|
|
236
|
+
|
|
237
|
+
## Pagination
|
|
238
|
+
|
|
239
|
+
List methods return a single page of results by default. Use the pagination helpers with low-level API calls to fetch all pages:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { fetchAllPages, paginateAll } from "@37signals/basecamp";
|
|
243
|
+
|
|
244
|
+
// First, fetch the initial page using the low-level client
|
|
245
|
+
const initialResponse = await client.GET("/projects.json");
|
|
246
|
+
|
|
247
|
+
// Option 1: fetchAllPages - returns all results as an array
|
|
248
|
+
const allProjects = await fetchAllPages(
|
|
249
|
+
initialResponse.response,
|
|
250
|
+
(response) => response.json()
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// Option 2: paginateAll - async generator for streaming large result sets
|
|
254
|
+
for await (const page of paginateAll(
|
|
255
|
+
initialResponse.response,
|
|
256
|
+
(response) => response.json()
|
|
257
|
+
)) {
|
|
258
|
+
for (const project of page) {
|
|
259
|
+
console.log(project.name);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Paginated endpoints include an `X-Total-Count` HTTP header when available. You can access this header via the `response.headers` field on low-level `client.GET`/`client.POST` calls.
|
|
265
|
+
|
|
266
|
+
## Low-Level API Access
|
|
267
|
+
|
|
268
|
+
For endpoints not covered by services or advanced use cases, use the raw typed client:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
// Direct API calls with full type inference
|
|
272
|
+
const { data, error, response } = await client.GET("/projects.json");
|
|
273
|
+
|
|
274
|
+
if (error) {
|
|
275
|
+
console.error("Failed:", error);
|
|
276
|
+
} else {
|
|
277
|
+
console.log(data.map((p) => p.name));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// With path parameters
|
|
281
|
+
const { data: project } = await client.GET("/projects/{projectId}", {
|
|
282
|
+
params: { path: { projectId: 12345 } },
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// POST with body
|
|
286
|
+
const { data: newProject } = await client.POST("/projects.json", {
|
|
287
|
+
body: { name: "My Project", description: "A new project" },
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Error Handling
|
|
292
|
+
|
|
293
|
+
The SDK provides structured errors with codes, hints, and exit codes for CLI applications:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
import { BasecampError, isBasecampError, isErrorCode } from "@37signals/basecamp";
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
await client.todos.get(todoId);
|
|
300
|
+
} catch (err) {
|
|
301
|
+
if (isBasecampError(err)) {
|
|
302
|
+
console.error(`Error [${err.code}]: ${err.message}`);
|
|
303
|
+
|
|
304
|
+
if (err.hint) {
|
|
305
|
+
console.error(`Hint: ${err.hint}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (err.retryable && err.retryAfter) {
|
|
309
|
+
console.log(`Retry after ${err.retryAfter} seconds`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Use exit codes for CLI applications
|
|
313
|
+
process.exit(err.exitCode);
|
|
314
|
+
}
|
|
315
|
+
throw err;
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Error Codes
|
|
320
|
+
|
|
321
|
+
| Code | HTTP Status | Exit Code | Description |
|
|
322
|
+
|------|-------------|-----------|-------------|
|
|
323
|
+
| `auth` | 401 | 3 | Authentication required |
|
|
324
|
+
| `forbidden` | 403 | 4 | Access denied |
|
|
325
|
+
| `not_found` | 404 | 2 | Resource not found |
|
|
326
|
+
| `rate_limit` | 429 | 5 | Rate limit exceeded (retryable) |
|
|
327
|
+
| `validation` | 400, 422 | 1 | Invalid request data |
|
|
328
|
+
| `network` | - | 6 | Network error (retryable) |
|
|
329
|
+
| `api_error` | 5xx | 7 | Server error |
|
|
330
|
+
| `usage` | - | 1 | Configuration or argument error |
|
|
331
|
+
|
|
332
|
+
## Retry Behavior
|
|
333
|
+
|
|
334
|
+
The SDK automatically retries requests on transient failures:
|
|
335
|
+
|
|
336
|
+
- **Retryable errors**: 429 (rate limit) and 503 (service unavailable)
|
|
337
|
+
- **Backoff**: Exponential with jitter
|
|
338
|
+
- **Rate limits**: Respects `Retry-After` header
|
|
339
|
+
- **Max retries**: 3 attempts by default
|
|
340
|
+
|
|
341
|
+
Disable retry for specific use cases:
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
const client = createBasecampClient({
|
|
345
|
+
accountId: "12345",
|
|
346
|
+
accessToken: "token",
|
|
347
|
+
enableRetry: false,
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Caching
|
|
352
|
+
|
|
353
|
+
The SDK uses ETag-based HTTP caching to reduce API calls and respect Basecamp's rate limits:
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
// First request fetches from API
|
|
357
|
+
const projects = await client.projects.list();
|
|
358
|
+
|
|
359
|
+
// Second request returns cached data if unchanged (304 Not Modified)
|
|
360
|
+
const projects2 = await client.projects.list();
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Disable caching if needed:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const client = createBasecampClient({
|
|
367
|
+
accountId: "12345",
|
|
368
|
+
accessToken: "token",
|
|
369
|
+
enableCache: false,
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Observability
|
|
374
|
+
|
|
375
|
+
### Console Logging
|
|
376
|
+
|
|
377
|
+
For debugging or verbose CLI modes:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
import { createBasecampClient, consoleHooks } from "@37signals/basecamp";
|
|
381
|
+
|
|
382
|
+
const client = createBasecampClient({
|
|
383
|
+
accountId: "12345",
|
|
384
|
+
accessToken: "token",
|
|
385
|
+
hooks: consoleHooks({
|
|
386
|
+
logOperations: true,
|
|
387
|
+
logRequests: true, // More verbose
|
|
388
|
+
logRetries: true,
|
|
389
|
+
minDurationMs: 100, // Only log slow requests
|
|
390
|
+
}),
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Output:
|
|
395
|
+
```
|
|
396
|
+
[Basecamp] Projects.List
|
|
397
|
+
[Basecamp] -> GET https://3.basecampapi.com/12345/projects.json
|
|
398
|
+
[Basecamp] <- GET https://3.basecampapi.com/12345/projects.json 200 (145ms)
|
|
399
|
+
[Basecamp] Projects.List completed (147ms)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Custom Hooks
|
|
403
|
+
|
|
404
|
+
Implement the `BasecampHooks` interface for custom observability:
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
import type { BasecampHooks } from "@37signals/basecamp";
|
|
408
|
+
|
|
409
|
+
const metricsHooks: BasecampHooks = {
|
|
410
|
+
onOperationStart(info) {
|
|
411
|
+
metrics.startTimer(`${info.service}.${info.operation}`);
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
onOperationEnd(info, result) {
|
|
415
|
+
metrics.recordDuration(`${info.service}.${info.operation}`, result.durationMs);
|
|
416
|
+
if (result.error) {
|
|
417
|
+
metrics.incrementError(`${info.service}.${info.operation}`);
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
onRetry(info, attempt, error, delayMs) {
|
|
422
|
+
logger.warn(`Retrying ${info.method} ${info.url} (attempt ${attempt})`);
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const client = createBasecampClient({
|
|
427
|
+
accountId: "12345",
|
|
428
|
+
accessToken: "token",
|
|
429
|
+
hooks: metricsHooks,
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### OpenTelemetry Integration
|
|
434
|
+
|
|
435
|
+
For distributed tracing and metrics:
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
import { createBasecampClient, otelHooks } from "@37signals/basecamp";
|
|
439
|
+
import { trace, metrics } from "@opentelemetry/api";
|
|
440
|
+
|
|
441
|
+
const tracer = trace.getTracer("my-app");
|
|
442
|
+
const meter = metrics.getMeter("my-app");
|
|
443
|
+
|
|
444
|
+
const client = createBasecampClient({
|
|
445
|
+
accountId: "12345",
|
|
446
|
+
accessToken: "token",
|
|
447
|
+
hooks: otelHooks({
|
|
448
|
+
tracer,
|
|
449
|
+
meter,
|
|
450
|
+
recordRequestSpans: true, // Include HTTP-level spans
|
|
451
|
+
}),
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Creates spans and metrics:
|
|
456
|
+
- `basecamp.operation.duration` - Histogram of operation durations
|
|
457
|
+
- `basecamp.operations.total` - Counter of operations
|
|
458
|
+
- `basecamp.errors.total` - Counter of errors
|
|
459
|
+
- `basecamp.retries.total` - Counter of retry attempts
|
|
460
|
+
|
|
461
|
+
### Combining Multiple Hooks
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
import { chainHooks, consoleHooks, otelHooks } from "@37signals/basecamp";
|
|
465
|
+
|
|
466
|
+
const client = createBasecampClient({
|
|
467
|
+
accountId: "12345",
|
|
468
|
+
accessToken: "token",
|
|
469
|
+
hooks: chainHooks(
|
|
470
|
+
consoleHooks(),
|
|
471
|
+
otelHooks({ tracer, meter }),
|
|
472
|
+
myCustomHooks,
|
|
473
|
+
),
|
|
474
|
+
});
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## Examples
|
|
478
|
+
|
|
479
|
+
### Working with Todos
|
|
480
|
+
|
|
481
|
+
```ts
|
|
482
|
+
// List todos in a todolist
|
|
483
|
+
const todos = await client.todos.list(todolistId);
|
|
484
|
+
|
|
485
|
+
// Create a todo with assignees
|
|
486
|
+
const todo = await client.todos.create(todolistId, {
|
|
487
|
+
content: "Review pull request",
|
|
488
|
+
description: "<p>Check the new auth flow</p>",
|
|
489
|
+
dueOn: "2026-02-01",
|
|
490
|
+
assigneeIds: [12345, 67890],
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// Complete a todo
|
|
494
|
+
await client.todos.complete(todo.id);
|
|
495
|
+
|
|
496
|
+
// Reposition a todo to the top
|
|
497
|
+
await client.todos.reposition(todo.id, { position: 1 });
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Working with Messages
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
// Get a message board
|
|
504
|
+
const board = await client.messageBoards.get(boardId);
|
|
505
|
+
|
|
506
|
+
// List messages
|
|
507
|
+
const messages = await client.messages.list(board.id);
|
|
508
|
+
|
|
509
|
+
// Create a message
|
|
510
|
+
const msg = await client.messages.create(board.id, {
|
|
511
|
+
subject: "Weekly Update",
|
|
512
|
+
content: "<p>Here's what we accomplished...</p>",
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// Pin a message
|
|
516
|
+
await client.messages.pin(msg.id);
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Working with Campfire
|
|
520
|
+
|
|
521
|
+
```ts
|
|
522
|
+
// List campfires
|
|
523
|
+
const campfires = await client.campfires.list();
|
|
524
|
+
|
|
525
|
+
// Send a message
|
|
526
|
+
await client.campfires.createLine(campfireId, {
|
|
527
|
+
content: "Hello, team!",
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// List recent messages
|
|
531
|
+
const lines = await client.campfires.listLines(campfireId);
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Working with Webhooks
|
|
535
|
+
|
|
536
|
+
```ts
|
|
537
|
+
const bucketId = 12345; // project/bucket ID
|
|
538
|
+
|
|
539
|
+
// Create a webhook
|
|
540
|
+
const webhook = await client.webhooks.create(bucketId, {
|
|
541
|
+
payloadUrl: "https://example.com/webhook",
|
|
542
|
+
types: ["Todo", "Comment"],
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// List webhooks
|
|
546
|
+
const webhooks = await client.webhooks.list(bucketId);
|
|
547
|
+
|
|
548
|
+
// Delete a webhook
|
|
549
|
+
await client.webhooks.delete(webhook.id);
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## TypeScript Types
|
|
553
|
+
|
|
554
|
+
All types are exported for use in your code:
|
|
555
|
+
|
|
556
|
+
```ts
|
|
557
|
+
import type {
|
|
558
|
+
Project,
|
|
559
|
+
Todo,
|
|
560
|
+
Message,
|
|
561
|
+
Person,
|
|
562
|
+
CreateTodoRequest,
|
|
563
|
+
BasecampError,
|
|
564
|
+
ErrorCode,
|
|
565
|
+
} from "@37signals/basecamp";
|
|
566
|
+
|
|
567
|
+
function processTodo(todo: Todo): void {
|
|
568
|
+
console.log(todo.content);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function createTodo(data: CreateTodoRequest): Promise<Todo> {
|
|
572
|
+
return client.todos.create(todolistId, data);
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## Development
|
|
577
|
+
|
|
578
|
+
```bash
|
|
579
|
+
# Install dependencies
|
|
580
|
+
npm install
|
|
581
|
+
|
|
582
|
+
# Generate types from OpenAPI spec
|
|
583
|
+
npm run generate
|
|
584
|
+
|
|
585
|
+
# Build
|
|
586
|
+
npm run build
|
|
587
|
+
|
|
588
|
+
# Run tests
|
|
589
|
+
npm test
|
|
590
|
+
|
|
591
|
+
# Type check
|
|
592
|
+
npm run typecheck
|
|
593
|
+
|
|
594
|
+
# Lint
|
|
595
|
+
npm run lint
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
## License
|
|
599
|
+
|
|
600
|
+
MIT
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication strategy for the Basecamp SDK.
|
|
3
|
+
*
|
|
4
|
+
* AuthStrategy controls how authentication is applied to HTTP requests.
|
|
5
|
+
* The default strategy is bearerAuth, which uses a TokenProvider to set
|
|
6
|
+
* the Authorization header with a Bearer token.
|
|
7
|
+
*
|
|
8
|
+
* Custom strategies can implement alternative auth schemes such as
|
|
9
|
+
* cookie-based auth, API keys, or mutual TLS.
|
|
10
|
+
*/
|
|
11
|
+
import type { TokenProvider } from "./client.js";
|
|
12
|
+
/**
|
|
13
|
+
* AuthStrategy controls how authentication is applied to HTTP requests.
|
|
14
|
+
* Called before every HTTP request to apply credentials to headers.
|
|
15
|
+
*/
|
|
16
|
+
export interface AuthStrategy {
|
|
17
|
+
/**
|
|
18
|
+
* Apply authentication to the given request headers.
|
|
19
|
+
* Called before every HTTP request.
|
|
20
|
+
*/
|
|
21
|
+
authenticate(headers: Headers): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Bearer token authentication strategy (default).
|
|
25
|
+
* Sets the Authorization header with "Bearer {token}".
|
|
26
|
+
*/
|
|
27
|
+
export declare class BearerAuth implements AuthStrategy {
|
|
28
|
+
private tokenProvider;
|
|
29
|
+
constructor(tokenProvider: TokenProvider);
|
|
30
|
+
authenticate(headers: Headers): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a BearerAuth strategy from a TokenProvider.
|
|
34
|
+
*/
|
|
35
|
+
export declare function bearerAuth(tokenProvider: TokenProvider): AuthStrategy;
|
|
36
|
+
//# sourceMappingURL=auth-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-strategy.d.ts","sourceRoot":"","sources":["../src/auth-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED;;;GAGG;AACH,qBAAa,UAAW,YAAW,YAAY;IAC7C,OAAO,CAAC,aAAa,CAAgB;gBAEzB,aAAa,EAAE,aAAa;IAIlC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAOpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,aAAa,EAAE,aAAa,GAAG,YAAY,CAErE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication strategy for the Basecamp SDK.
|
|
3
|
+
*
|
|
4
|
+
* AuthStrategy controls how authentication is applied to HTTP requests.
|
|
5
|
+
* The default strategy is bearerAuth, which uses a TokenProvider to set
|
|
6
|
+
* the Authorization header with a Bearer token.
|
|
7
|
+
*
|
|
8
|
+
* Custom strategies can implement alternative auth schemes such as
|
|
9
|
+
* cookie-based auth, API keys, or mutual TLS.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Bearer token authentication strategy (default).
|
|
13
|
+
* Sets the Authorization header with "Bearer {token}".
|
|
14
|
+
*/
|
|
15
|
+
export class BearerAuth {
|
|
16
|
+
tokenProvider;
|
|
17
|
+
constructor(tokenProvider) {
|
|
18
|
+
this.tokenProvider = tokenProvider;
|
|
19
|
+
}
|
|
20
|
+
async authenticate(headers) {
|
|
21
|
+
const token = typeof this.tokenProvider === "function"
|
|
22
|
+
? await this.tokenProvider()
|
|
23
|
+
: this.tokenProvider;
|
|
24
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Creates a BearerAuth strategy from a TokenProvider.
|
|
29
|
+
*/
|
|
30
|
+
export function bearerAuth(tokenProvider) {
|
|
31
|
+
return new BearerAuth(tokenProvider);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=auth-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-strategy.js","sourceRoot":"","sources":["../src/auth-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgBH;;;GAGG;AACH,MAAM,OAAO,UAAU;IACb,aAAa,CAAgB;IAErC,YAAY,aAA4B;QACtC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,KAAK,GACT,OAAO,IAAI,CAAC,aAAa,KAAK,UAAU;YACtC,CAAC,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE;YAC5B,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,aAA4B;IACrD,OAAO,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;AACvC,CAAC"}
|