@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,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry hooks for the Basecamp SDK.
|
|
3
|
+
*
|
|
4
|
+
* Provides distributed tracing and metrics for API operations.
|
|
5
|
+
* Requires @opentelemetry/api as an optional peer dependency.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createBasecampClient, otelHooks } from "@37signals/basecamp";
|
|
10
|
+
* import { trace, metrics } from "@opentelemetry/api";
|
|
11
|
+
*
|
|
12
|
+
* const tracer = trace.getTracer("my-app");
|
|
13
|
+
* const meter = metrics.getMeter("my-app");
|
|
14
|
+
*
|
|
15
|
+
* const client = createBasecampClient({
|
|
16
|
+
* accountId: "12345",
|
|
17
|
+
* accessToken: "token",
|
|
18
|
+
* hooks: otelHooks({ tracer, meter }),
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // All SDK operations will now create spans and record metrics
|
|
22
|
+
* const projects = await client.projects.list();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { BasecampHooks } from "../hooks.js";
|
|
26
|
+
interface OtelSpan {
|
|
27
|
+
setAttribute(key: string, value: string | number | boolean): this;
|
|
28
|
+
setStatus(status: {
|
|
29
|
+
code: number;
|
|
30
|
+
message?: string;
|
|
31
|
+
}): this;
|
|
32
|
+
recordException(exception: Error): this;
|
|
33
|
+
end(): void;
|
|
34
|
+
}
|
|
35
|
+
interface OtelTracer {
|
|
36
|
+
startSpan(name: string, options?: {
|
|
37
|
+
attributes?: Record<string, string | number | boolean>;
|
|
38
|
+
}): OtelSpan;
|
|
39
|
+
}
|
|
40
|
+
interface OtelMeter {
|
|
41
|
+
createHistogram(name: string, options?: {
|
|
42
|
+
description?: string;
|
|
43
|
+
unit?: string;
|
|
44
|
+
}): OtelHistogram;
|
|
45
|
+
createCounter(name: string, options?: {
|
|
46
|
+
description?: string;
|
|
47
|
+
}): OtelCounter;
|
|
48
|
+
}
|
|
49
|
+
interface OtelHistogram {
|
|
50
|
+
record(value: number, attributes?: Record<string, string | number | boolean>): void;
|
|
51
|
+
}
|
|
52
|
+
interface OtelCounter {
|
|
53
|
+
add(value: number, attributes?: Record<string, string | number | boolean>): void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Options for OpenTelemetry hooks.
|
|
57
|
+
*/
|
|
58
|
+
export interface OtelHooksOptions {
|
|
59
|
+
/**
|
|
60
|
+
* OpenTelemetry tracer instance.
|
|
61
|
+
* Create with: `trace.getTracer("your-app-name")`
|
|
62
|
+
*/
|
|
63
|
+
tracer?: OtelTracer;
|
|
64
|
+
/**
|
|
65
|
+
* OpenTelemetry meter instance for metrics.
|
|
66
|
+
* Create with: `metrics.getMeter("your-app-name")`
|
|
67
|
+
*/
|
|
68
|
+
meter?: OtelMeter;
|
|
69
|
+
/**
|
|
70
|
+
* Whether to record request-level spans (in addition to operation spans).
|
|
71
|
+
* Defaults to false for reduced noise.
|
|
72
|
+
*/
|
|
73
|
+
recordRequestSpans?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Prefix for span names.
|
|
76
|
+
* Defaults to "basecamp"
|
|
77
|
+
*/
|
|
78
|
+
spanPrefix?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Prefix for metric names.
|
|
81
|
+
* Defaults to "basecamp"
|
|
82
|
+
*/
|
|
83
|
+
metricPrefix?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Creates OpenTelemetry hooks for distributed tracing and metrics.
|
|
87
|
+
*
|
|
88
|
+
* This function creates hooks that integrate with OpenTelemetry for:
|
|
89
|
+
* - **Tracing**: Creates spans for SDK operations with relevant attributes
|
|
90
|
+
* - **Metrics**: Records histograms for latency and counters for operations/errors
|
|
91
|
+
*
|
|
92
|
+
* Span attributes include:
|
|
93
|
+
* - `basecamp.service`: Service name (e.g., "Todos", "Projects")
|
|
94
|
+
* - `basecamp.operation`: Operation name (e.g., "List", "Create")
|
|
95
|
+
* - `basecamp.resource_type`: Type of resource being accessed
|
|
96
|
+
* - `basecamp.is_mutation`: Whether the operation modifies data
|
|
97
|
+
* - `basecamp.project_id`: Project ID if applicable
|
|
98
|
+
* - `basecamp.resource_id`: Resource ID if applicable
|
|
99
|
+
*
|
|
100
|
+
* Metrics recorded:
|
|
101
|
+
* - `basecamp.operation.duration`: Histogram of operation durations (ms)
|
|
102
|
+
* - `basecamp.request.duration`: Histogram of HTTP request durations (ms)
|
|
103
|
+
* - `basecamp.operations.total`: Counter of total operations
|
|
104
|
+
* - `basecamp.errors.total`: Counter of errors
|
|
105
|
+
* - `basecamp.retries.total`: Counter of retry attempts
|
|
106
|
+
*
|
|
107
|
+
* @param options - Configuration options
|
|
108
|
+
* @returns Hooks object for use with createBasecampClient
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* import { createBasecampClient, otelHooks } from "@37signals/basecamp";
|
|
113
|
+
* import { trace, metrics } from "@opentelemetry/api";
|
|
114
|
+
*
|
|
115
|
+
* // Set up OpenTelemetry first (SDK configuration not shown)
|
|
116
|
+
* const tracer = trace.getTracer("my-app", "1.0.0");
|
|
117
|
+
* const meter = metrics.getMeter("my-app", "1.0.0");
|
|
118
|
+
*
|
|
119
|
+
* const client = createBasecampClient({
|
|
120
|
+
* accountId: "12345",
|
|
121
|
+
* accessToken: "token",
|
|
122
|
+
* hooks: otelHooks({
|
|
123
|
+
* tracer,
|
|
124
|
+
* meter,
|
|
125
|
+
* spanPrefix: "basecamp",
|
|
126
|
+
* recordRequestSpans: true,
|
|
127
|
+
* }),
|
|
128
|
+
* });
|
|
129
|
+
*
|
|
130
|
+
* // Operations will create spans and record metrics
|
|
131
|
+
* const todos = await client.todos.list(projectId, todolistId);
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function otelHooks(options?: OtelHooksOptions): BasecampHooks;
|
|
135
|
+
export {};
|
|
136
|
+
//# sourceMappingURL=otel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../../src/hooks/otel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA8D,MAAM,aAAa,CAAC;AAI7G,UAAU,QAAQ;IAChB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAClE,SAAS,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5D,eAAe,CAAC,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxC,GAAG,IAAI,IAAI,CAAC;CACb;AAED,UAAU,UAAU;IAClB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;KAAE,GAAG,QAAQ,CAAC;CACzG;AAED,UAAU,SAAS;IACjB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,CAAC;IAChG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW,CAAC;CAC9E;AAED,UAAU,aAAa;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;CACrF;AAED,UAAU,WAAW;IACnB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;CAClF;AASD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAuCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,aAAa,CAyKvE"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry hooks for the Basecamp SDK.
|
|
3
|
+
*
|
|
4
|
+
* Provides distributed tracing and metrics for API operations.
|
|
5
|
+
* Requires @opentelemetry/api as an optional peer dependency.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createBasecampClient, otelHooks } from "@37signals/basecamp";
|
|
10
|
+
* import { trace, metrics } from "@opentelemetry/api";
|
|
11
|
+
*
|
|
12
|
+
* const tracer = trace.getTracer("my-app");
|
|
13
|
+
* const meter = metrics.getMeter("my-app");
|
|
14
|
+
*
|
|
15
|
+
* const client = createBasecampClient({
|
|
16
|
+
* accountId: "12345",
|
|
17
|
+
* accessToken: "token",
|
|
18
|
+
* hooks: otelHooks({ tracer, meter }),
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // All SDK operations will now create spans and record metrics
|
|
22
|
+
* const projects = await client.projects.list();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
// Span status codes from OpenTelemetry
|
|
26
|
+
const SpanStatusCode = {
|
|
27
|
+
UNSET: 0,
|
|
28
|
+
OK: 1,
|
|
29
|
+
ERROR: 2,
|
|
30
|
+
};
|
|
31
|
+
/** Counter for generating unique keys */
|
|
32
|
+
let keyCounter = 0;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a unique key for an operation.
|
|
35
|
+
*/
|
|
36
|
+
function operationKey(info) {
|
|
37
|
+
return `${info.service}.${info.operation}:${info.resourceId ?? ""}:${++keyCounter}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a unique key for a request.
|
|
41
|
+
*/
|
|
42
|
+
function requestKey(info) {
|
|
43
|
+
return `${info.method}:${info.url}:${info.attempt}:${++keyCounter}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates OpenTelemetry hooks for distributed tracing and metrics.
|
|
47
|
+
*
|
|
48
|
+
* This function creates hooks that integrate with OpenTelemetry for:
|
|
49
|
+
* - **Tracing**: Creates spans for SDK operations with relevant attributes
|
|
50
|
+
* - **Metrics**: Records histograms for latency and counters for operations/errors
|
|
51
|
+
*
|
|
52
|
+
* Span attributes include:
|
|
53
|
+
* - `basecamp.service`: Service name (e.g., "Todos", "Projects")
|
|
54
|
+
* - `basecamp.operation`: Operation name (e.g., "List", "Create")
|
|
55
|
+
* - `basecamp.resource_type`: Type of resource being accessed
|
|
56
|
+
* - `basecamp.is_mutation`: Whether the operation modifies data
|
|
57
|
+
* - `basecamp.project_id`: Project ID if applicable
|
|
58
|
+
* - `basecamp.resource_id`: Resource ID if applicable
|
|
59
|
+
*
|
|
60
|
+
* Metrics recorded:
|
|
61
|
+
* - `basecamp.operation.duration`: Histogram of operation durations (ms)
|
|
62
|
+
* - `basecamp.request.duration`: Histogram of HTTP request durations (ms)
|
|
63
|
+
* - `basecamp.operations.total`: Counter of total operations
|
|
64
|
+
* - `basecamp.errors.total`: Counter of errors
|
|
65
|
+
* - `basecamp.retries.total`: Counter of retry attempts
|
|
66
|
+
*
|
|
67
|
+
* @param options - Configuration options
|
|
68
|
+
* @returns Hooks object for use with createBasecampClient
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* import { createBasecampClient, otelHooks } from "@37signals/basecamp";
|
|
73
|
+
* import { trace, metrics } from "@opentelemetry/api";
|
|
74
|
+
*
|
|
75
|
+
* // Set up OpenTelemetry first (SDK configuration not shown)
|
|
76
|
+
* const tracer = trace.getTracer("my-app", "1.0.0");
|
|
77
|
+
* const meter = metrics.getMeter("my-app", "1.0.0");
|
|
78
|
+
*
|
|
79
|
+
* const client = createBasecampClient({
|
|
80
|
+
* accountId: "12345",
|
|
81
|
+
* accessToken: "token",
|
|
82
|
+
* hooks: otelHooks({
|
|
83
|
+
* tracer,
|
|
84
|
+
* meter,
|
|
85
|
+
* spanPrefix: "basecamp",
|
|
86
|
+
* recordRequestSpans: true,
|
|
87
|
+
* }),
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Operations will create spans and record metrics
|
|
91
|
+
* const todos = await client.todos.list(projectId, todolistId);
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export function otelHooks(options = {}) {
|
|
95
|
+
const { tracer, meter, recordRequestSpans = false, spanPrefix = "basecamp", metricPrefix = "basecamp", } = options;
|
|
96
|
+
// Initialize state
|
|
97
|
+
const state = {
|
|
98
|
+
operationSpans: new Map(),
|
|
99
|
+
requestSpans: new Map(),
|
|
100
|
+
};
|
|
101
|
+
// Initialize metrics if meter is provided
|
|
102
|
+
if (meter) {
|
|
103
|
+
state.operationDuration = meter.createHistogram(`${metricPrefix}.operation.duration`, {
|
|
104
|
+
description: "Duration of Basecamp SDK operations",
|
|
105
|
+
unit: "ms",
|
|
106
|
+
});
|
|
107
|
+
state.requestDuration = meter.createHistogram(`${metricPrefix}.request.duration`, {
|
|
108
|
+
description: "Duration of HTTP requests",
|
|
109
|
+
unit: "ms",
|
|
110
|
+
});
|
|
111
|
+
state.operationCounter = meter.createCounter(`${metricPrefix}.operations.total`, {
|
|
112
|
+
description: "Total number of Basecamp SDK operations",
|
|
113
|
+
});
|
|
114
|
+
state.errorCounter = meter.createCounter(`${metricPrefix}.errors.total`, {
|
|
115
|
+
description: "Total number of errors",
|
|
116
|
+
});
|
|
117
|
+
state.retryCounter = meter.createCounter(`${metricPrefix}.retries.total`, {
|
|
118
|
+
description: "Total number of retry attempts",
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
onOperationStart(info) {
|
|
123
|
+
// Record operation count (even without tracer)
|
|
124
|
+
state.operationCounter?.add(1, {
|
|
125
|
+
service: info.service,
|
|
126
|
+
operation: info.operation,
|
|
127
|
+
is_mutation: info.isMutation,
|
|
128
|
+
});
|
|
129
|
+
if (!tracer)
|
|
130
|
+
return;
|
|
131
|
+
const spanName = `${spanPrefix}.${info.service}.${info.operation}`;
|
|
132
|
+
const attributes = {
|
|
133
|
+
[`${spanPrefix}.service`]: info.service,
|
|
134
|
+
[`${spanPrefix}.operation`]: info.operation,
|
|
135
|
+
[`${spanPrefix}.resource_type`]: info.resourceType,
|
|
136
|
+
[`${spanPrefix}.is_mutation`]: info.isMutation,
|
|
137
|
+
};
|
|
138
|
+
if (info.projectId) {
|
|
139
|
+
attributes[`${spanPrefix}.project_id`] = info.projectId;
|
|
140
|
+
}
|
|
141
|
+
if (info.resourceId) {
|
|
142
|
+
attributes[`${spanPrefix}.resource_id`] = info.resourceId;
|
|
143
|
+
}
|
|
144
|
+
const span = tracer.startSpan(spanName, { attributes });
|
|
145
|
+
const key = operationKey(info);
|
|
146
|
+
state.operationSpans.set(key, span);
|
|
147
|
+
},
|
|
148
|
+
onOperationEnd(info, result) {
|
|
149
|
+
// Find and end the span
|
|
150
|
+
if (tracer) {
|
|
151
|
+
// Find the most recent span for this operation
|
|
152
|
+
for (const [key, span] of state.operationSpans) {
|
|
153
|
+
if (key.startsWith(`${info.service}.${info.operation}:`)) {
|
|
154
|
+
if (result.error) {
|
|
155
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: result.error.message });
|
|
156
|
+
span.recordException(result.error);
|
|
157
|
+
span.setAttribute("error", true);
|
|
158
|
+
span.setAttribute("error.message", result.error.message);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
162
|
+
}
|
|
163
|
+
span.setAttribute("duration_ms", result.durationMs);
|
|
164
|
+
span.end();
|
|
165
|
+
state.operationSpans.delete(key);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Record metrics
|
|
171
|
+
const labels = {
|
|
172
|
+
service: info.service,
|
|
173
|
+
operation: info.operation,
|
|
174
|
+
is_mutation: info.isMutation,
|
|
175
|
+
success: !result.error,
|
|
176
|
+
};
|
|
177
|
+
state.operationDuration?.record(result.durationMs, labels);
|
|
178
|
+
if (result.error) {
|
|
179
|
+
state.errorCounter?.add(1, {
|
|
180
|
+
service: info.service,
|
|
181
|
+
operation: info.operation,
|
|
182
|
+
error_type: result.error.name,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
onRequestStart(info) {
|
|
187
|
+
if (!tracer || !recordRequestSpans)
|
|
188
|
+
return;
|
|
189
|
+
const spanName = `${spanPrefix}.http.${info.method}`;
|
|
190
|
+
const span = tracer.startSpan(spanName, {
|
|
191
|
+
attributes: {
|
|
192
|
+
"http.method": info.method,
|
|
193
|
+
"http.url": info.url,
|
|
194
|
+
"http.attempt": info.attempt,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
const key = requestKey(info);
|
|
198
|
+
state.requestSpans.set(key, span);
|
|
199
|
+
},
|
|
200
|
+
onRequestEnd(info, result) {
|
|
201
|
+
// Find and end the span
|
|
202
|
+
if (tracer && recordRequestSpans) {
|
|
203
|
+
for (const [key, span] of state.requestSpans) {
|
|
204
|
+
if (key.startsWith(`${info.method}:${info.url}:${info.attempt}:`)) {
|
|
205
|
+
span.setAttribute("http.status_code", result.statusCode);
|
|
206
|
+
span.setAttribute("http.from_cache", result.fromCache);
|
|
207
|
+
span.setAttribute("duration_ms", result.durationMs);
|
|
208
|
+
if (result.error) {
|
|
209
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: result.error.message });
|
|
210
|
+
span.recordException(result.error);
|
|
211
|
+
}
|
|
212
|
+
else if (result.statusCode >= 400) {
|
|
213
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: `HTTP ${result.statusCode}` });
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
217
|
+
}
|
|
218
|
+
span.end();
|
|
219
|
+
state.requestSpans.delete(key);
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Record request metrics
|
|
225
|
+
state.requestDuration?.record(result.durationMs, {
|
|
226
|
+
method: info.method,
|
|
227
|
+
status_code: result.statusCode,
|
|
228
|
+
from_cache: result.fromCache,
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
onRetry(info, attempt, error, _delayMs) {
|
|
232
|
+
state.retryCounter?.add(1, {
|
|
233
|
+
method: info.method,
|
|
234
|
+
attempt,
|
|
235
|
+
error_type: error.name,
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=otel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../../src/hooks/otel.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability hooks system for the Basecamp SDK.
|
|
3
|
+
*
|
|
4
|
+
* Provides a way to observe API operations and HTTP requests
|
|
5
|
+
* without modifying the core client logic. Hooks compile away
|
|
6
|
+
* when unused (no overhead).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createBasecampClient, consoleHooks } from "@37signals/basecamp";
|
|
11
|
+
*
|
|
12
|
+
* // Simple console logging
|
|
13
|
+
* const client = createBasecampClient({
|
|
14
|
+
* accountId: "12345",
|
|
15
|
+
* accessToken: "token",
|
|
16
|
+
* hooks: consoleHooks(),
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Custom metrics
|
|
20
|
+
* const client = createBasecampClient({
|
|
21
|
+
* accountId: "12345",
|
|
22
|
+
* accessToken: "token",
|
|
23
|
+
* hooks: {
|
|
24
|
+
* onOperationEnd: (info, result) => {
|
|
25
|
+
* metrics.recordLatency(info.service, info.operation, result.durationMs);
|
|
26
|
+
* if (result.error) {
|
|
27
|
+
* metrics.recordError(info.service, info.operation);
|
|
28
|
+
* }
|
|
29
|
+
* },
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Information about a high-level service operation.
|
|
36
|
+
*/
|
|
37
|
+
export interface OperationInfo {
|
|
38
|
+
/** Service name (e.g., "Todos", "Projects") */
|
|
39
|
+
service: string;
|
|
40
|
+
/** Operation name (e.g., "List", "Get", "Create") */
|
|
41
|
+
operation: string;
|
|
42
|
+
/** Type of resource being accessed */
|
|
43
|
+
resourceType: string;
|
|
44
|
+
/** Whether this operation modifies data */
|
|
45
|
+
isMutation: boolean;
|
|
46
|
+
/** Project ID if the operation is scoped to a project */
|
|
47
|
+
projectId?: number;
|
|
48
|
+
/** Resource ID if the operation targets a specific resource */
|
|
49
|
+
resourceId?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Information about an HTTP request.
|
|
53
|
+
*/
|
|
54
|
+
export interface RequestInfo {
|
|
55
|
+
/** HTTP method */
|
|
56
|
+
method: string;
|
|
57
|
+
/** Full request URL */
|
|
58
|
+
url: string;
|
|
59
|
+
/** Current attempt number (1-based) */
|
|
60
|
+
attempt: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Result of an HTTP request.
|
|
64
|
+
*/
|
|
65
|
+
export interface RequestResult {
|
|
66
|
+
/** HTTP status code */
|
|
67
|
+
statusCode: number;
|
|
68
|
+
/** Request duration in milliseconds */
|
|
69
|
+
durationMs: number;
|
|
70
|
+
/** Whether the response was served from cache */
|
|
71
|
+
fromCache: boolean;
|
|
72
|
+
/** Error if the request failed */
|
|
73
|
+
error?: Error;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Result of an operation.
|
|
77
|
+
*/
|
|
78
|
+
export interface OperationResult {
|
|
79
|
+
/** Error if the operation failed */
|
|
80
|
+
error?: Error;
|
|
81
|
+
/** Operation duration in milliseconds */
|
|
82
|
+
durationMs: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Hooks interface for observing SDK operations.
|
|
86
|
+
* All hooks are optional - implement only what you need.
|
|
87
|
+
*/
|
|
88
|
+
export interface BasecampHooks {
|
|
89
|
+
/**
|
|
90
|
+
* Called when a service operation starts.
|
|
91
|
+
* Use for logging, tracing, or metrics.
|
|
92
|
+
*/
|
|
93
|
+
onOperationStart?(info: OperationInfo): void;
|
|
94
|
+
/**
|
|
95
|
+
* Called when a service operation completes (success or failure).
|
|
96
|
+
* Always called, even if onOperationStart threw.
|
|
97
|
+
*/
|
|
98
|
+
onOperationEnd?(info: OperationInfo, result: OperationResult): void;
|
|
99
|
+
/**
|
|
100
|
+
* Called when an HTTP request starts.
|
|
101
|
+
* Called for each attempt (including retries).
|
|
102
|
+
*/
|
|
103
|
+
onRequestStart?(info: RequestInfo): void;
|
|
104
|
+
/**
|
|
105
|
+
* Called when an HTTP request completes.
|
|
106
|
+
* Called for each attempt (including retries).
|
|
107
|
+
*/
|
|
108
|
+
onRequestEnd?(info: RequestInfo, result: RequestResult): void;
|
|
109
|
+
/**
|
|
110
|
+
* Called before a retry attempt.
|
|
111
|
+
* Use for logging retry behavior or implementing custom backoff.
|
|
112
|
+
*/
|
|
113
|
+
onRetry?(info: RequestInfo, attempt: number, error: Error, delayMs: number): void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Combines multiple hooks into a single hooks object.
|
|
117
|
+
* All hooks are called in order. Errors in hooks are caught and logged.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* const hooks = chainHooks(
|
|
122
|
+
* consoleHooks(),
|
|
123
|
+
* metricsHooks(),
|
|
124
|
+
* sentryHooks(),
|
|
125
|
+
* );
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function chainHooks(...hooks: BasecampHooks[]): BasecampHooks;
|
|
129
|
+
/**
|
|
130
|
+
* Options for console logging hooks.
|
|
131
|
+
*/
|
|
132
|
+
export interface ConsoleHooksOptions {
|
|
133
|
+
/** Whether to log operation events (default: true) */
|
|
134
|
+
logOperations?: boolean;
|
|
135
|
+
/** Whether to log request events (default: false) */
|
|
136
|
+
logRequests?: boolean;
|
|
137
|
+
/** Whether to log retry events (default: true) */
|
|
138
|
+
logRetries?: boolean;
|
|
139
|
+
/** Minimum duration in ms to log (default: 0) */
|
|
140
|
+
minDurationMs?: number;
|
|
141
|
+
/** Custom logger (default: console) */
|
|
142
|
+
logger?: Pick<Console, "log" | "warn" | "error">;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Creates hooks that log to the console.
|
|
146
|
+
* Useful for debugging and development.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* // Basic usage
|
|
151
|
+
* const hooks = consoleHooks();
|
|
152
|
+
*
|
|
153
|
+
* // With custom options
|
|
154
|
+
* const hooks = consoleHooks({
|
|
155
|
+
* logRequests: true,
|
|
156
|
+
* minDurationMs: 100,
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
export declare function consoleHooks(options?: ConsoleHooksOptions): BasecampHooks;
|
|
161
|
+
/**
|
|
162
|
+
* Creates a no-op hooks object.
|
|
163
|
+
* Useful as a default when hooks are optional.
|
|
164
|
+
*/
|
|
165
|
+
export declare function noopHooks(): BasecampHooks;
|
|
166
|
+
/**
|
|
167
|
+
* Internal helper to safely invoke a hook.
|
|
168
|
+
* Returns silently if the hook throws.
|
|
169
|
+
*/
|
|
170
|
+
export declare function safeInvoke<K extends keyof BasecampHooks>(hooks: BasecampHooks | undefined, hookName: K, ...args: Parameters<NonNullable<BasecampHooks[K]>>): void;
|
|
171
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,SAAS,EAAE,OAAO,CAAC;IACnB,kCAAkC;IAClC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAE7C;;;OAGG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAEpE;;;OAGG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IAEzC;;;OAGG;IACH,YAAY,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAE9D;;;OAGG;IACH,OAAO,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACnF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,GAAG,KAAK,EAAE,aAAa,EAAE,GAAG,aAAa,CA+DnE;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa,CA4D7E;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,aAAa,CAEzC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,aAAa,EACtD,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,QAAQ,EAAE,CAAC,EACX,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACjD,IAAI,CAYN"}
|