@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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse "todo_created" → { type: "todo", action: "created" }.
|
|
3
|
+
* For compound types like "question_answer_created" → { type: "question_answer", action: "created" }.
|
|
4
|
+
* The action is always the last underscore-separated segment.
|
|
5
|
+
*/
|
|
6
|
+
export function parseEventKind(kind) {
|
|
7
|
+
const lastUnderscore = kind.lastIndexOf("_");
|
|
8
|
+
if (lastUnderscore === -1) {
|
|
9
|
+
return { type: kind, action: "" };
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
type: kind.slice(0, lastUnderscore),
|
|
13
|
+
action: kind.slice(lastUnderscore + 1),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Known webhook event kind strings (convenience constants, not exhaustive). */
|
|
17
|
+
export const WebhookEventKind = {
|
|
18
|
+
TodoCreated: "todo_created",
|
|
19
|
+
TodoCompleted: "todo_completed",
|
|
20
|
+
TodoUncompleted: "todo_uncompleted",
|
|
21
|
+
TodoChanged: "todo_changed",
|
|
22
|
+
TodolistCreated: "todolist_created",
|
|
23
|
+
TodolistChanged: "todolist_changed",
|
|
24
|
+
MessageCreated: "message_created",
|
|
25
|
+
MessageChanged: "message_changed",
|
|
26
|
+
CommentCreated: "comment_created",
|
|
27
|
+
CommentChanged: "comment_changed",
|
|
28
|
+
DocumentCreated: "document_created",
|
|
29
|
+
DocumentChanged: "document_changed",
|
|
30
|
+
UploadCreated: "upload_created",
|
|
31
|
+
UploadChanged: "upload_changed",
|
|
32
|
+
QuestionAnswerCreated: "question_answer_created",
|
|
33
|
+
QuestionAnswerChanged: "question_answer_changed",
|
|
34
|
+
ScheduleEntryCreated: "schedule_entry_created",
|
|
35
|
+
ScheduleEntryChanged: "schedule_entry_changed",
|
|
36
|
+
CloudFileCreated: "cloud_file_created",
|
|
37
|
+
VaultCreated: "vault_created",
|
|
38
|
+
InboxForwardCreated: "inbox_forward_created",
|
|
39
|
+
ForwardReplyCreated: "forward_reply_created",
|
|
40
|
+
ClientReplyCreated: "client_reply_created",
|
|
41
|
+
ClientApprovalCreated: "client_approval_created",
|
|
42
|
+
ClientApprovalChanged: "client_approval_changed",
|
|
43
|
+
TodoCopied: "todo_copied",
|
|
44
|
+
MessageCopied: "message_copied",
|
|
45
|
+
TodoArchived: "todo_archived",
|
|
46
|
+
TodoUnarchived: "todo_unarchived",
|
|
47
|
+
TodoTrashed: "todo_trashed",
|
|
48
|
+
MessageArchived: "message_archived",
|
|
49
|
+
MessageUnarchived: "message_unarchived",
|
|
50
|
+
MessageTrashed: "message_trashed",
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/webhooks/events.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpC,CAAC;IACD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC;QACnC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,cAAc;IAC3B,aAAa,EAAE,gBAAgB;IAC/B,eAAe,EAAE,kBAAkB;IACnC,WAAW,EAAE,cAAc;IAC3B,eAAe,EAAE,kBAAkB;IACnC,eAAe,EAAE,kBAAkB;IACnC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,eAAe,EAAE,kBAAkB;IACnC,eAAe,EAAE,kBAAkB;IACnC,aAAa,EAAE,gBAAgB;IAC/B,aAAa,EAAE,gBAAgB;IAC/B,qBAAqB,EAAE,yBAAyB;IAChD,qBAAqB,EAAE,yBAAyB;IAChD,oBAAoB,EAAE,wBAAwB;IAC9C,oBAAoB,EAAE,wBAAwB;IAC9C,gBAAgB,EAAE,oBAAoB;IACtC,YAAY,EAAE,eAAe;IAC7B,mBAAmB,EAAE,uBAAuB;IAC5C,mBAAmB,EAAE,uBAAuB;IAC5C,kBAAkB,EAAE,sBAAsB;IAC1C,qBAAqB,EAAE,yBAAyB;IAChD,qBAAqB,EAAE,yBAAyB;IAChD,UAAU,EAAE,aAAa;IACzB,aAAa,EAAE,gBAAgB;IAC/B,YAAY,EAAE,eAAe;IAC7B,cAAc,EAAE,iBAAiB;IACjC,WAAW,EAAE,cAAc;IAC3B,eAAe,EAAE,kBAAkB;IACnC,iBAAiB,EAAE,oBAAoB;IACvC,cAAc,EAAE,iBAAiB;CACzB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { WebhookEvent } from "./events.js";
|
|
2
|
+
/** Handler function for webhook events. */
|
|
3
|
+
export type WebhookEventHandler = (event: WebhookEvent) => void | Promise<void>;
|
|
4
|
+
/** Middleware function that wraps event processing. Call next() to continue the chain. */
|
|
5
|
+
export type WebhookMiddleware = (event: WebhookEvent, next: () => Promise<void>) => Promise<void>;
|
|
6
|
+
/** Header accessor: either a record of headers or a function that retrieves a header by name. */
|
|
7
|
+
export type HeaderAccessor = Record<string, string | string[] | undefined> | ((name: string) => string | undefined);
|
|
8
|
+
export interface WebhookReceiverOptions {
|
|
9
|
+
/** HMAC secret for signature verification. If unset, verification is skipped. */
|
|
10
|
+
secret?: string;
|
|
11
|
+
/** HTTP header containing the signature (default: "x-basecamp-signature"). */
|
|
12
|
+
signatureHeader?: string;
|
|
13
|
+
/** Number of recent event IDs to track for deduplication (default: 1000, 0 to disable). */
|
|
14
|
+
dedupWindowSize?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Error thrown when webhook signature verification fails. */
|
|
17
|
+
export declare class WebhookVerificationError extends Error {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Receives and routes webhook events from Basecamp.
|
|
22
|
+
*
|
|
23
|
+
* Framework-agnostic: works with raw body bytes and a header accessor.
|
|
24
|
+
* Use adapters (e.g., createNodeHandler) for framework-specific integration.
|
|
25
|
+
*/
|
|
26
|
+
export declare class WebhookReceiver {
|
|
27
|
+
private readonly secret?;
|
|
28
|
+
private readonly signatureHeader;
|
|
29
|
+
private readonly dedupWindowSize;
|
|
30
|
+
private readonly handlers;
|
|
31
|
+
private readonly anyHandlers;
|
|
32
|
+
private readonly middlewareChain;
|
|
33
|
+
private readonly dedupSeen;
|
|
34
|
+
private readonly dedupOrder;
|
|
35
|
+
private readonly dedupPending;
|
|
36
|
+
constructor(options?: WebhookReceiverOptions);
|
|
37
|
+
/**
|
|
38
|
+
* Register a handler for a specific event kind pattern.
|
|
39
|
+
* Supports exact match ("todo_created") and glob patterns ("todo_*", "*_created").
|
|
40
|
+
*/
|
|
41
|
+
on(pattern: string, handler: WebhookEventHandler): this;
|
|
42
|
+
/** Register a handler that fires for all events. */
|
|
43
|
+
onAny(handler: WebhookEventHandler): this;
|
|
44
|
+
/** Add middleware to the processing chain. Middleware runs in registration order before handlers. */
|
|
45
|
+
use(middleware: WebhookMiddleware): this;
|
|
46
|
+
/**
|
|
47
|
+
* Process a raw webhook request.
|
|
48
|
+
* Returns the parsed WebhookEvent.
|
|
49
|
+
* Duplicate events (by ID) return the event but do not trigger handlers.
|
|
50
|
+
* @throws {WebhookVerificationError} if signature verification fails
|
|
51
|
+
*/
|
|
52
|
+
handleRequest(rawBody: string | Buffer, headers: HeaderAccessor): Promise<WebhookEvent>;
|
|
53
|
+
private getHeader;
|
|
54
|
+
/** Returns true if the event was claimed (caller should process it). Returns false if already seen or in-flight. */
|
|
55
|
+
private claim;
|
|
56
|
+
/** Promote from pending to seen after successful handling. */
|
|
57
|
+
private commitSeen;
|
|
58
|
+
/** Release claim on handler error so retries can re-attempt. */
|
|
59
|
+
private releaseClaim;
|
|
60
|
+
private dispatchHandlers;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/webhooks/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,2CAA2C;AAC3C,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhF,0FAA0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAElG,iGAAiG;AACjG,MAAM,MAAM,cAAc,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC7C,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,8DAA8D;AAC9D,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,SAA8B;CAIlD;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2B;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;gBAEtC,OAAO,CAAC,EAAE,sBAAsB;IAM5C;;;OAGG;IACH,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAUvD,oDAAoD;IACpD,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAKzC,qGAAqG;IACrG,GAAG,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKxC;;;;;OAKG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,YAAY,CAAC;IA6CxB,OAAO,CAAC,SAAS;IASjB,oHAAoH;IACpH,OAAO,CAAC,KAAK;IAOb,8DAA8D;IAC9D,OAAO,CAAC,UAAU;IAclB,gEAAgE;IAChE,OAAO,CAAC,YAAY;YAIN,gBAAgB;CAe/B"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { verifyWebhookSignature } from "./verify.js";
|
|
2
|
+
/** Error thrown when webhook signature verification fails. */
|
|
3
|
+
export class WebhookVerificationError extends Error {
|
|
4
|
+
constructor(message = "invalid webhook signature") {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "WebhookVerificationError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Receives and routes webhook events from Basecamp.
|
|
11
|
+
*
|
|
12
|
+
* Framework-agnostic: works with raw body bytes and a header accessor.
|
|
13
|
+
* Use adapters (e.g., createNodeHandler) for framework-specific integration.
|
|
14
|
+
*/
|
|
15
|
+
export class WebhookReceiver {
|
|
16
|
+
secret;
|
|
17
|
+
signatureHeader;
|
|
18
|
+
dedupWindowSize;
|
|
19
|
+
handlers = new Map();
|
|
20
|
+
anyHandlers = [];
|
|
21
|
+
middlewareChain = [];
|
|
22
|
+
dedupSeen = new Set();
|
|
23
|
+
dedupOrder = [];
|
|
24
|
+
dedupPending = new Set();
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.secret = options?.secret;
|
|
27
|
+
this.signatureHeader = options?.signatureHeader ?? "x-basecamp-signature";
|
|
28
|
+
this.dedupWindowSize = options?.dedupWindowSize ?? 1000;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Register a handler for a specific event kind pattern.
|
|
32
|
+
* Supports exact match ("todo_created") and glob patterns ("todo_*", "*_created").
|
|
33
|
+
*/
|
|
34
|
+
on(pattern, handler) {
|
|
35
|
+
const existing = this.handlers.get(pattern);
|
|
36
|
+
if (existing) {
|
|
37
|
+
existing.push(handler);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.handlers.set(pattern, [handler]);
|
|
41
|
+
}
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
/** Register a handler that fires for all events. */
|
|
45
|
+
onAny(handler) {
|
|
46
|
+
this.anyHandlers.push(handler);
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/** Add middleware to the processing chain. Middleware runs in registration order before handlers. */
|
|
50
|
+
use(middleware) {
|
|
51
|
+
this.middlewareChain.push(middleware);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Process a raw webhook request.
|
|
56
|
+
* Returns the parsed WebhookEvent.
|
|
57
|
+
* Duplicate events (by ID) return the event but do not trigger handlers.
|
|
58
|
+
* @throws {WebhookVerificationError} if signature verification fails
|
|
59
|
+
*/
|
|
60
|
+
async handleRequest(rawBody, headers) {
|
|
61
|
+
// Verify signature if secret is configured
|
|
62
|
+
if (this.secret) {
|
|
63
|
+
const sig = this.getHeader(headers, this.signatureHeader);
|
|
64
|
+
if (!sig || !verifyWebhookSignature(rawBody, sig, this.secret)) {
|
|
65
|
+
throw new WebhookVerificationError();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Parse event — extract ID as string from raw JSON to avoid int64 precision loss
|
|
69
|
+
const bodyStr = typeof rawBody === "string" ? rawBody : rawBody.toString("utf8");
|
|
70
|
+
const eventIdStr = extractIdString(bodyStr);
|
|
71
|
+
const event = JSON.parse(bodyStr);
|
|
72
|
+
// Atomic dedup: check seen + pending, claim before handlers, commit on success, release on error
|
|
73
|
+
if (!this.claim(eventIdStr)) {
|
|
74
|
+
return event;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
// Build middleware chain → handlers
|
|
78
|
+
const runHandlers = async () => {
|
|
79
|
+
await this.dispatchHandlers(event);
|
|
80
|
+
};
|
|
81
|
+
let chain = runHandlers;
|
|
82
|
+
for (let i = this.middlewareChain.length - 1; i >= 0; i--) {
|
|
83
|
+
const mw = this.middlewareChain[i];
|
|
84
|
+
const next = chain;
|
|
85
|
+
chain = () => mw(event, next);
|
|
86
|
+
}
|
|
87
|
+
await chain();
|
|
88
|
+
// Promote from pending to seen on success
|
|
89
|
+
this.commitSeen(eventIdStr);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
// Release claim so retries can re-attempt
|
|
93
|
+
this.releaseClaim(eventIdStr);
|
|
94
|
+
throw err;
|
|
95
|
+
}
|
|
96
|
+
return event;
|
|
97
|
+
}
|
|
98
|
+
getHeader(headers, name) {
|
|
99
|
+
if (typeof headers === "function") {
|
|
100
|
+
return headers(name);
|
|
101
|
+
}
|
|
102
|
+
const val = headers[name] ?? headers[name.toLowerCase()];
|
|
103
|
+
if (Array.isArray(val))
|
|
104
|
+
return val[0];
|
|
105
|
+
return val;
|
|
106
|
+
}
|
|
107
|
+
/** Returns true if the event was claimed (caller should process it). Returns false if already seen or in-flight. */
|
|
108
|
+
claim(eventIdStr) {
|
|
109
|
+
if (this.dedupWindowSize <= 0 || !eventIdStr)
|
|
110
|
+
return true;
|
|
111
|
+
if (this.dedupSeen.has(eventIdStr) || this.dedupPending.has(eventIdStr))
|
|
112
|
+
return false;
|
|
113
|
+
this.dedupPending.add(eventIdStr);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
/** Promote from pending to seen after successful handling. */
|
|
117
|
+
commitSeen(eventIdStr) {
|
|
118
|
+
if (this.dedupWindowSize <= 0 || !eventIdStr)
|
|
119
|
+
return;
|
|
120
|
+
this.dedupPending.delete(eventIdStr);
|
|
121
|
+
// Evict oldest if at capacity
|
|
122
|
+
if (this.dedupOrder.length >= this.dedupWindowSize) {
|
|
123
|
+
const oldest = this.dedupOrder.shift();
|
|
124
|
+
this.dedupSeen.delete(oldest);
|
|
125
|
+
}
|
|
126
|
+
this.dedupSeen.add(eventIdStr);
|
|
127
|
+
this.dedupOrder.push(eventIdStr);
|
|
128
|
+
}
|
|
129
|
+
/** Release claim on handler error so retries can re-attempt. */
|
|
130
|
+
releaseClaim(eventIdStr) {
|
|
131
|
+
if (eventIdStr)
|
|
132
|
+
this.dedupPending.delete(eventIdStr);
|
|
133
|
+
}
|
|
134
|
+
async dispatchHandlers(event) {
|
|
135
|
+
const matched = [];
|
|
136
|
+
for (const [pattern, handlers] of this.handlers) {
|
|
137
|
+
if (matchPattern(pattern, event.kind ?? "")) {
|
|
138
|
+
matched.push(...handlers);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
matched.push(...this.anyHandlers);
|
|
142
|
+
for (const handler of matched) {
|
|
143
|
+
await handler(event);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Extract the top-level "id" field as a raw string from JSON, avoiding Number precision loss on int64.
|
|
148
|
+
* Only matches "id" at brace depth 1 (top-level object), ignoring nested "id" fields.
|
|
149
|
+
* Uses a full string-aware state machine so braces inside JSON strings don't corrupt depth tracking. */
|
|
150
|
+
function extractIdString(json) {
|
|
151
|
+
let depth = 0;
|
|
152
|
+
let inString = false;
|
|
153
|
+
for (let i = 0; i < json.length; i++) {
|
|
154
|
+
const ch = json[i];
|
|
155
|
+
// String state machine — must be checked before anything else so braces
|
|
156
|
+
// inside strings never affect depth tracking.
|
|
157
|
+
if (inString) {
|
|
158
|
+
if (ch === "\\") {
|
|
159
|
+
i++;
|
|
160
|
+
continue;
|
|
161
|
+
} // skip escaped char
|
|
162
|
+
if (ch === '"') {
|
|
163
|
+
inString = false;
|
|
164
|
+
}
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// Outside any string
|
|
168
|
+
if (ch === '"') {
|
|
169
|
+
// At depth 1, check if this starts the key "id"
|
|
170
|
+
if (depth === 1 && json[i + 1] === "i" && json[i + 2] === "d" && json[i + 3] === '"') {
|
|
171
|
+
// Skip past "id" and any whitespace/colon
|
|
172
|
+
let j = i + 4;
|
|
173
|
+
while (j < json.length && (json[j] === " " || json[j] === "\t" || json[j] === "\n" || json[j] === "\r" || json[j] === ":"))
|
|
174
|
+
j++;
|
|
175
|
+
// Extract digits
|
|
176
|
+
const start = j;
|
|
177
|
+
while (j < json.length && json[j] >= "0" && json[j] <= "9")
|
|
178
|
+
j++;
|
|
179
|
+
if (j > start)
|
|
180
|
+
return json.slice(start, j);
|
|
181
|
+
}
|
|
182
|
+
inString = true;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (ch === "{") {
|
|
186
|
+
depth++;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (ch === "}") {
|
|
190
|
+
depth--;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Match a webhook event kind against a glob pattern.
|
|
198
|
+
* "*" matches any sequence of characters.
|
|
199
|
+
*/
|
|
200
|
+
function matchPattern(pattern, value) {
|
|
201
|
+
if (pattern === value)
|
|
202
|
+
return true;
|
|
203
|
+
const parts = pattern.split("*");
|
|
204
|
+
if (parts.length === 1)
|
|
205
|
+
return false; // No wildcards, exact match already checked
|
|
206
|
+
let remaining = value;
|
|
207
|
+
for (let i = 0; i < parts.length; i++) {
|
|
208
|
+
const part = parts[i];
|
|
209
|
+
if (part === "")
|
|
210
|
+
continue;
|
|
211
|
+
const idx = remaining.indexOf(part);
|
|
212
|
+
if (idx === -1)
|
|
213
|
+
return false;
|
|
214
|
+
// First part must be a prefix
|
|
215
|
+
if (i === 0 && idx !== 0)
|
|
216
|
+
return false;
|
|
217
|
+
remaining = remaining.slice(idx + part.length);
|
|
218
|
+
}
|
|
219
|
+
// Last part must be a suffix (if non-empty)
|
|
220
|
+
const lastPart = parts.at(-1);
|
|
221
|
+
if (lastPart !== "") {
|
|
222
|
+
return value.endsWith(lastPart);
|
|
223
|
+
}
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/webhooks/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { parseEventKind, WebhookEventKind, type WebhookEvent, type WebhookDelivery, type WebhookDeliveryRequest, type WebhookDeliveryResponse, type WebhookCopy, } from "./events.js";
|
|
2
|
+
export { verifyWebhookSignature, signWebhookPayload, } from "./verify.js";
|
|
3
|
+
export { WebhookReceiver, WebhookVerificationError, type WebhookEventHandler, type WebhookMiddleware, type WebhookReceiverOptions, type HeaderAccessor, } from "./handler.js";
|
|
4
|
+
export { createNodeHandler, type NodeHandlerOptions } from "./adapters/node-http.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { parseEventKind, WebhookEventKind, } from "./events.js";
|
|
2
|
+
export { verifyWebhookSignature, signWebhookPayload, } from "./verify.js";
|
|
3
|
+
export { WebhookReceiver, WebhookVerificationError, } from "./handler.js";
|
|
4
|
+
export { createNodeHandler } from "./adapters/node-http.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,GAMjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,wBAAwB,GAKzB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAA2B,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify an HMAC-SHA256 webhook signature.
|
|
3
|
+
* Returns false if secret or signature is empty.
|
|
4
|
+
*/
|
|
5
|
+
export declare function verifyWebhookSignature(payload: string | Buffer, signature: string, secret: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Compute the HMAC-SHA256 signature for a webhook payload.
|
|
8
|
+
* Useful for testing webhook handlers.
|
|
9
|
+
*/
|
|
10
|
+
export declare function signWebhookPayload(payload: string | Buffer, secret: string): string;
|
|
11
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/webhooks/verify.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAUT;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,MAAM,EAAE,MAAM,GACb,MAAM,CAER"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Verify an HMAC-SHA256 webhook signature.
|
|
4
|
+
* Returns false if secret or signature is empty.
|
|
5
|
+
*/
|
|
6
|
+
export function verifyWebhookSignature(payload, signature, secret) {
|
|
7
|
+
if (!secret || !signature)
|
|
8
|
+
return false;
|
|
9
|
+
const expected = signWebhookPayload(payload, secret);
|
|
10
|
+
try {
|
|
11
|
+
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// Lengths differ
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Compute the HMAC-SHA256 signature for a webhook payload.
|
|
20
|
+
* Useful for testing webhook handlers.
|
|
21
|
+
*/
|
|
22
|
+
export function signWebhookPayload(payload, secret) {
|
|
23
|
+
return createHmac("sha256", secret).update(payload).digest("hex");
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/webhooks/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAwB,EACxB,SAAiB,EACjB,MAAc;IAEd,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAExC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;QACjB,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAwB,EACxB,MAAc;IAEd,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@37signals/basecamp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "TypeScript SDK for the Basecamp 3 API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./oauth": {
|
|
14
|
+
"import": "./dist/oauth/index.js",
|
|
15
|
+
"types": "./dist/oauth/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src/generated"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"generate": "tsx scripts/strip-account-id.ts ../spec/build/smithy/openapi/openapi/Basecamp.openapi.json src/generated/openapi-stripped.json && openapi-typescript src/generated/openapi-stripped.json -o src/generated/schema.d.ts && tsx scripts/extract-metadata.ts src/generated/openapi-stripped.json > src/generated/metadata.json && tsx scripts/generate-path-mapping.ts",
|
|
24
|
+
"build": "tsc && npm run postbuild",
|
|
25
|
+
"postbuild": "node -e \"fs=require('fs');fs.cpSync('src/generated','dist/generated',{recursive:true});\"",
|
|
26
|
+
"prepublishOnly": "npm run build",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"test:coverage": "vitest run --coverage",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"lint": "oxlint src --ignore-pattern 'src/generated/**'"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"basecamp",
|
|
35
|
+
"api",
|
|
36
|
+
"sdk",
|
|
37
|
+
"typescript"
|
|
38
|
+
],
|
|
39
|
+
"author": "Basecamp",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/basecamp/basecamp-sdk.git",
|
|
47
|
+
"directory": "typescript"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"openapi-fetch": "^0.17.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^25.3.0",
|
|
57
|
+
"msw": "^2.12.10",
|
|
58
|
+
"openapi-typescript": "^7.13.0",
|
|
59
|
+
"oxlint": "^1.50.0",
|
|
60
|
+
"tsx": "^4.19.0",
|
|
61
|
+
"typescript": "^5.7.0",
|
|
62
|
+
"vitest": "^4.0.18"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"typescript": ">=5.0.0"
|
|
66
|
+
},
|
|
67
|
+
"overrides": {
|
|
68
|
+
"minimatch": ">=10.2.1"
|
|
69
|
+
}
|
|
70
|
+
}
|