@37signals/basecamp 0.7.3 → 0.9.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.
Files changed (162) hide show
  1. package/README.md +82 -2
  2. package/dist/client.d.ts +7 -4
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +32 -23
  5. package/dist/client.js.map +1 -1
  6. package/dist/download.d.ts.map +1 -1
  7. package/dist/errors.d.ts +10 -0
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/errors.js +7 -1
  10. package/dist/errors.js.map +1 -1
  11. package/dist/generated/metadata.d.ts +32 -0
  12. package/dist/generated/metadata.d.ts.map +1 -0
  13. package/dist/generated/metadata.js +2723 -0
  14. package/dist/generated/metadata.js.map +1 -0
  15. package/dist/generated/{metadata.json → metadata.ts} +141 -35
  16. package/dist/generated/openapi-stripped.json +1713 -478
  17. package/dist/generated/path-mapping.d.ts.map +1 -1
  18. package/dist/generated/path-mapping.js +10 -5
  19. package/dist/generated/path-mapping.js.map +1 -1
  20. package/dist/generated/path-mapping.ts +10 -5
  21. package/dist/generated/schema.d.ts +1027 -265
  22. package/dist/generated/services/campfires.d.ts +22 -1
  23. package/dist/generated/services/campfires.d.ts.map +1 -1
  24. package/dist/generated/services/campfires.js +33 -1
  25. package/dist/generated/services/campfires.js.map +1 -1
  26. package/dist/generated/services/campfires.ts +46 -1
  27. package/dist/generated/services/card-columns.d.ts +31 -28
  28. package/dist/generated/services/card-columns.d.ts.map +1 -1
  29. package/dist/generated/services/card-columns.js +57 -51
  30. package/dist/generated/services/card-columns.js.map +1 -1
  31. package/dist/generated/services/card-columns.ts +65 -59
  32. package/dist/generated/services/checkins.d.ts +3 -1
  33. package/dist/generated/services/checkins.d.ts.map +1 -1
  34. package/dist/generated/services/checkins.js +2 -1
  35. package/dist/generated/services/checkins.js.map +1 -1
  36. package/dist/generated/services/checkins.ts +4 -1
  37. package/dist/generated/services/documents.d.ts +2 -0
  38. package/dist/generated/services/documents.d.ts.map +1 -1
  39. package/dist/generated/services/documents.js +1 -0
  40. package/dist/generated/services/documents.js.map +1 -1
  41. package/dist/generated/services/documents.ts +3 -0
  42. package/dist/generated/services/gauges.d.ts +2 -2
  43. package/dist/generated/services/gauges.js +2 -2
  44. package/dist/generated/services/gauges.ts +2 -2
  45. package/dist/generated/services/index.d.ts +3 -2
  46. package/dist/generated/services/index.d.ts.map +1 -1
  47. package/dist/generated/services/index.js +3 -2
  48. package/dist/generated/services/index.js.map +1 -1
  49. package/dist/generated/services/index.ts +3 -2
  50. package/dist/generated/services/messages.d.ts +2 -0
  51. package/dist/generated/services/messages.d.ts.map +1 -1
  52. package/dist/generated/services/messages.js +1 -0
  53. package/dist/generated/services/messages.js.map +1 -1
  54. package/dist/generated/services/messages.ts +3 -0
  55. package/dist/generated/services/people.d.ts +2 -2
  56. package/dist/generated/services/people.js +2 -2
  57. package/dist/generated/services/people.ts +2 -2
  58. package/dist/generated/services/reports.d.ts +1 -1
  59. package/dist/generated/services/reports.js +1 -1
  60. package/dist/generated/services/reports.ts +1 -1
  61. package/dist/generated/services/schedules.d.ts +2 -0
  62. package/dist/generated/services/schedules.d.ts.map +1 -1
  63. package/dist/generated/services/schedules.js +1 -0
  64. package/dist/generated/services/schedules.js.map +1 -1
  65. package/dist/generated/services/schedules.ts +3 -0
  66. package/dist/generated/services/search.d.ts +30 -1
  67. package/dist/generated/services/search.d.ts.map +1 -1
  68. package/dist/generated/services/search.js +1 -1
  69. package/dist/generated/services/search.js.map +1 -1
  70. package/dist/generated/services/search.ts +31 -2
  71. package/dist/generated/services/templates.d.ts +3 -5
  72. package/dist/generated/services/templates.d.ts.map +1 -1
  73. package/dist/generated/services/templates.js +4 -5
  74. package/dist/generated/services/templates.js.map +1 -1
  75. package/dist/generated/services/templates.ts +6 -9
  76. package/dist/generated/services/todolists.d.ts +22 -0
  77. package/dist/generated/services/todolists.d.ts.map +1 -1
  78. package/dist/generated/services/todolists.js +31 -0
  79. package/dist/generated/services/todolists.js.map +1 -1
  80. package/dist/generated/services/todolists.ts +46 -0
  81. package/dist/generated/services/todos.d.ts +8 -8
  82. package/dist/generated/services/todos.d.ts.map +1 -1
  83. package/dist/generated/services/todos.js +9 -6
  84. package/dist/generated/services/todos.js.map +1 -1
  85. package/dist/generated/services/todos.ts +12 -9
  86. package/dist/generated/services/tools.d.ts +11 -10
  87. package/dist/generated/services/tools.d.ts.map +1 -1
  88. package/dist/generated/services/tools.js +16 -8
  89. package/dist/generated/services/tools.js.map +1 -1
  90. package/dist/generated/services/tools.ts +21 -13
  91. package/dist/generated/services/uploads.d.ts +2 -0
  92. package/dist/generated/services/uploads.d.ts.map +1 -1
  93. package/dist/generated/services/uploads.js +1 -0
  94. package/dist/generated/services/uploads.js.map +1 -1
  95. package/dist/generated/services/uploads.ts +3 -0
  96. package/dist/generated/services/webhooks.js +2 -2
  97. package/dist/generated/services/webhooks.js.map +1 -1
  98. package/dist/generated/services/webhooks.ts +2 -2
  99. package/dist/generated/services/wormholes.d.ts +70 -0
  100. package/dist/generated/services/wormholes.d.ts.map +1 -0
  101. package/dist/generated/services/wormholes.js +103 -0
  102. package/dist/generated/services/wormholes.js.map +1 -0
  103. package/dist/generated/services/wormholes.ts +145 -0
  104. package/dist/index.d.ts +8 -5
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +4 -3
  107. package/dist/index.js.map +1 -1
  108. package/dist/oauth/discovery.d.ts +105 -23
  109. package/dist/oauth/discovery.d.ts.map +1 -1
  110. package/dist/oauth/discovery.js +453 -61
  111. package/dist/oauth/discovery.js.map +1 -1
  112. package/dist/oauth/index.d.ts +2 -2
  113. package/dist/oauth/index.d.ts.map +1 -1
  114. package/dist/oauth/index.js +1 -1
  115. package/dist/oauth/index.js.map +1 -1
  116. package/dist/oauth/interactive-login.d.ts +20 -2
  117. package/dist/oauth/interactive-login.d.ts.map +1 -1
  118. package/dist/oauth/interactive-login.js +58 -4
  119. package/dist/oauth/interactive-login.js.map +1 -1
  120. package/dist/oauth/types.d.ts +54 -2
  121. package/dist/oauth/types.d.ts.map +1 -1
  122. package/dist/security.d.ts +22 -0
  123. package/dist/security.d.ts.map +1 -1
  124. package/dist/security.js +56 -1
  125. package/dist/security.js.map +1 -1
  126. package/dist/services/authorization.d.ts.map +1 -1
  127. package/dist/services/authorization.js +3 -0
  128. package/dist/services/authorization.js.map +1 -1
  129. package/dist/services/base.d.ts.map +1 -1
  130. package/dist/services/base.js +1 -3
  131. package/dist/services/base.js.map +1 -1
  132. package/dist/services/todos-extensions.d.ts +118 -0
  133. package/dist/services/todos-extensions.d.ts.map +1 -0
  134. package/dist/services/todos-extensions.js +113 -0
  135. package/dist/services/todos-extensions.js.map +1 -0
  136. package/dist/services/uploads-extensions.d.ts +33 -0
  137. package/dist/services/uploads-extensions.d.ts.map +1 -0
  138. package/dist/services/uploads-extensions.js +48 -0
  139. package/dist/services/uploads-extensions.js.map +1 -0
  140. package/package.json +7 -4
  141. package/src/generated/{metadata.json → metadata.ts} +141 -35
  142. package/src/generated/openapi-stripped.json +1713 -478
  143. package/src/generated/path-mapping.ts +10 -5
  144. package/src/generated/schema.d.ts +1027 -265
  145. package/src/generated/services/campfires.ts +46 -1
  146. package/src/generated/services/card-columns.ts +65 -59
  147. package/src/generated/services/checkins.ts +4 -1
  148. package/src/generated/services/documents.ts +3 -0
  149. package/src/generated/services/gauges.ts +2 -2
  150. package/src/generated/services/index.ts +3 -2
  151. package/src/generated/services/messages.ts +3 -0
  152. package/src/generated/services/people.ts +2 -2
  153. package/src/generated/services/reports.ts +1 -1
  154. package/src/generated/services/schedules.ts +3 -0
  155. package/src/generated/services/search.ts +31 -2
  156. package/src/generated/services/templates.ts +6 -9
  157. package/src/generated/services/todolists.ts +46 -0
  158. package/src/generated/services/todos.ts +12 -9
  159. package/src/generated/services/tools.ts +21 -13
  160. package/src/generated/services/uploads.ts +3 -0
  161. package/src/generated/services/webhooks.ts +2 -2
  162. package/src/generated/services/wormholes.ts +145 -0
@@ -0,0 +1,113 @@
1
+ import { TodosService as GeneratedTodosService } from "../generated/services/todos.js";
2
+ /**
3
+ * TodosService with merge-safe `update` and read-modify-write `edit` on
4
+ * top of the generated surface (`get`, `replace`, ...).
5
+ *
6
+ * Both compose the public `get` and `replace` methods, so hooks observe
7
+ * the two wire operations (`GetTodo` then `ReplaceTodo`), not a synthetic
8
+ * composite.
9
+ */
10
+ export class TodosService extends GeneratedTodosService {
11
+ /**
12
+ * Sets the given fields on a todo and preserves everything else: GETs
13
+ * the current todo, overlays the explicitly-set request fields, and PUTs
14
+ * the full representation back. An omitted (`undefined`) field is
15
+ * untouched, guaranteed; an explicitly-passed empty array clears.
16
+ *
17
+ * Not atomic: there is no conditional-update signal on this endpoint, so
18
+ * a concurrent write between the GET and PUT is overwritten — last write
19
+ * wins for the whole representation. The window is one round-trip. Use
20
+ * `replace` to overwrite deliberately.
21
+ *
22
+ * @param todoId - The todo ID
23
+ * @param req - Fields to set; omitted fields are preserved
24
+ * @returns The updated Todo
25
+ * @throws {BasecampError} If the request fails
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * // Retitle without touching description, dates, or assignees.
30
+ * await client.todos.update(123, { content: "New title" });
31
+ * ```
32
+ */
33
+ async update(todoId, req) {
34
+ const fields = await this.currentFields(todoId);
35
+ if (req.content !== undefined)
36
+ fields.content = req.content;
37
+ if (req.description !== undefined)
38
+ fields.description = req.description;
39
+ if (req.assigneeIds !== undefined)
40
+ fields.assigneeIds = req.assigneeIds;
41
+ if (req.completionSubscriberIds !== undefined) {
42
+ fields.completionSubscriberIds = req.completionSubscriberIds;
43
+ }
44
+ if (req.dueOn !== undefined)
45
+ fields.dueOn = req.dueOn;
46
+ if (req.startsOn !== undefined)
47
+ fields.startsOn = req.startsOn;
48
+ if (req.notify !== undefined)
49
+ fields.notify = req.notify;
50
+ return this.putFields(todoId, fields);
51
+ }
52
+ /**
53
+ * Applies a read-modify-write callback to a todo: GETs the current todo,
54
+ * hands the callback the full writable representation, and PUTs the
55
+ * whole thing back. Clearing a field means setting it empty (`""` or
56
+ * `[]`) — an untouched field keeps its current value. If the callback
57
+ * throws (or rejects), the edit aborts and nothing is written.
58
+ *
59
+ * Not atomic: there is no conditional-update signal on this endpoint, so
60
+ * a concurrent write between the GET and PUT is overwritten — last write
61
+ * wins for the whole representation. The window is one round-trip. Use
62
+ * `replace` to overwrite deliberately.
63
+ *
64
+ * @param todoId - The todo ID
65
+ * @param fn - Callback that mutates the todo's writable fields in place
66
+ * @returns The updated Todo
67
+ * @throws {BasecampError} If the request fails
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * await client.todos.edit(123, (t) => {
72
+ * t.content = `🚨 ${t.content}`;
73
+ * t.dueOn = ""; // clearing = setting empty on a full object
74
+ * });
75
+ * ```
76
+ */
77
+ async edit(todoId, fn) {
78
+ const fields = await this.currentFields(todoId);
79
+ await fn(fields);
80
+ return this.putFields(todoId, fields);
81
+ }
82
+ /** Fetches the todo and derives its full writable state. */
83
+ async currentFields(todoId) {
84
+ const current = await this.get(todoId);
85
+ return {
86
+ content: current.content ?? "",
87
+ description: current.description ?? "",
88
+ assigneeIds: (current.assignees ?? []).map((p) => p.id),
89
+ completionSubscriberIds: (current.completion_subscribers ?? []).map((p) => p.id),
90
+ dueOn: current.due_on ?? "",
91
+ startsOn: current.starts_on ?? "",
92
+ notify: false,
93
+ };
94
+ }
95
+ /**
96
+ * PUTs the full writable state via `replace`: content, description, and
97
+ * both ID lists are always sent (empties included, so clears survive);
98
+ * dates are sent only when non-empty (the server clears an omitted date,
99
+ * and `""` is a format error); notify is sent only when true.
100
+ */
101
+ putFields(todoId, f) {
102
+ return this.replace(todoId, {
103
+ content: f.content,
104
+ description: f.description,
105
+ assigneeIds: f.assigneeIds,
106
+ completionSubscriberIds: f.completionSubscriberIds,
107
+ dueOn: f.dueOn === "" ? undefined : f.dueOn,
108
+ startsOn: f.startsOn === "" ? undefined : f.startsOn,
109
+ notify: f.notify ? true : undefined,
110
+ });
111
+ }
112
+ }
113
+ //# sourceMappingURL=todos-extensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todos-extensions.js","sourceRoot":"","sources":["../../src/services/todos-extensions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { BasecampHooks } from "../hooks.js";
2
+ import type { DownloadResult } from "../download.js";
3
+ import { UploadsService as GeneratedUploadsService } from "../generated/services/uploads.js";
4
+ import type { RawClient } from "./base.js";
5
+ /** Function signature for the client-level `downloadURL` primitive. */
6
+ type DownloadURLFn = (rawURL: string) => Promise<DownloadResult>;
7
+ /**
8
+ * UploadsService with a hand-written `download(uploadId)` convenience.
9
+ *
10
+ * The subclass injects the client-level `downloadURL` function so the
11
+ * convenience method can delegate to it — the authenticated-hop + 302-follow
12
+ * flow stays in one place (`createDownloadURL` in `download.ts`).
13
+ */
14
+ export declare class UploadsService extends GeneratedUploadsService {
15
+ private readonly downloadURLFn?;
16
+ constructor(client: RawClient, hooks?: BasecampHooks, fetchPage?: (url: string) => Promise<Response>, maxPages?: number, authenticatedFetch?: (url: string, init: RequestInit) => Promise<Response>, baseUrl?: string, downloadURLFn?: DownloadURLFn);
17
+ /**
18
+ * Downloads an upload's file content in one call.
19
+ *
20
+ * Fetches the upload metadata to retrieve `download_url`, then delegates to
21
+ * the client-level `downloadURL` primitive (authenticated-hop + 302-follow).
22
+ *
23
+ * @param uploadId - The upload's numeric id.
24
+ * @returns A `DownloadResult` whose `filename` prefers `upload.filename`
25
+ * from metadata, falling back to the URL-derived filename.
26
+ * @throws {BasecampError} `usage` if the upload has no `download_url`,
27
+ * or if the service was constructed without the injected download
28
+ * primitive (obtain the service through `createBasecampClient().uploads`).
29
+ */
30
+ download(uploadId: number): Promise<DownloadResult>;
31
+ }
32
+ export {};
33
+ //# sourceMappingURL=uploads-extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploads-extensions.d.ts","sourceRoot":"","sources":["../../src/services/uploads-extensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,cAAc,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC7F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,uEAAuE;AACvE,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,uBAAuB;IACzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAgB;gBAS7C,MAAM,EAAE,SAAS,EACjB,KAAK,CAAC,EAAE,aAAa,EACrB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,EAC9C,QAAQ,CAAC,EAAE,MAAM,EACjB,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,EAC1E,OAAO,CAAC,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,aAAa;IAM/B;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAc1D"}
@@ -0,0 +1,48 @@
1
+ import { Errors } from "../errors.js";
2
+ import { UploadsService as GeneratedUploadsService } from "../generated/services/uploads.js";
3
+ /**
4
+ * UploadsService with a hand-written `download(uploadId)` convenience.
5
+ *
6
+ * The subclass injects the client-level `downloadURL` function so the
7
+ * convenience method can delegate to it — the authenticated-hop + 302-follow
8
+ * flow stays in one place (`createDownloadURL` in `download.ts`).
9
+ */
10
+ export class UploadsService extends GeneratedUploadsService {
11
+ downloadURLFn;
12
+ // Preserve BaseService's full positional signature (authenticatedFetch, baseUrl),
13
+ // then append downloadURLFn — otherwise existing `new UploadsService(client, hooks,
14
+ // fetchPage, maxPages, authenticatedFetch, baseUrl)` callers would silently miswire
15
+ // authenticatedFetch into the 5th slot. All params optional for direct-construction
16
+ // back-compat; `download()` throws a clear usage error if the primitive wasn't
17
+ // injected (i.e. the service was constructed outside createBasecampClient).
18
+ constructor(client, hooks, fetchPage, maxPages, authenticatedFetch, baseUrl, downloadURLFn) {
19
+ super(client, hooks, fetchPage, maxPages, authenticatedFetch, baseUrl);
20
+ this.downloadURLFn = downloadURLFn;
21
+ }
22
+ /**
23
+ * Downloads an upload's file content in one call.
24
+ *
25
+ * Fetches the upload metadata to retrieve `download_url`, then delegates to
26
+ * the client-level `downloadURL` primitive (authenticated-hop + 302-follow).
27
+ *
28
+ * @param uploadId - The upload's numeric id.
29
+ * @returns A `DownloadResult` whose `filename` prefers `upload.filename`
30
+ * from metadata, falling back to the URL-derived filename.
31
+ * @throws {BasecampError} `usage` if the upload has no `download_url`,
32
+ * or if the service was constructed without the injected download
33
+ * primitive (obtain the service through `createBasecampClient().uploads`).
34
+ */
35
+ async download(uploadId) {
36
+ if (!this.downloadURLFn) {
37
+ throw Errors.usage("uploads.download requires the download primitive — obtain UploadsService via createBasecampClient(...).uploads rather than instantiating it directly");
38
+ }
39
+ const upload = await this.get(uploadId);
40
+ const url = upload.download_url;
41
+ if (!url) {
42
+ throw Errors.usage(`upload ${uploadId} has no download_url`);
43
+ }
44
+ const result = await this.downloadURLFn(url);
45
+ return upload.filename ? { ...result, filename: upload.filename } : result;
46
+ }
47
+ }
48
+ //# sourceMappingURL=uploads-extensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploads-extensions.js","sourceRoot":"","sources":["../../src/services/uploads-extensions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,cAAc,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAM7F;;;;;;GAMG;AACH,MAAM,OAAO,cAAe,SAAQ,uBAAuB;IACxC,aAAa,CAAiB;IAE/C,kFAAkF;IAClF,oFAAoF;IACpF,oFAAoF;IACpF,oFAAoF;IACpF,+EAA+E;IAC/E,4EAA4E;IAC5E,YACE,MAAiB,EACjB,KAAqB,EACrB,SAA8C,EAC9C,QAAiB,EACjB,kBAA0E,EAC1E,OAAgB,EAChB,aAA6B;QAE7B,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;QACvE,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,CAAC,QAAgB;QAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,MAAM,CAAC,KAAK,CAChB,sJAAsJ,CACvJ,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC;QAChC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,QAAQ,sBAAsB,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7E,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@37signals/basecamp",
3
- "version": "0.7.3",
3
+ "version": "0.9.0",
4
4
  "description": "TypeScript SDK for the Basecamp API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "src/generated"
21
21
  ],
22
22
  "scripts": {
23
- "generate": "tsx scripts/strip-account-id.ts ../openapi.json src/generated/openapi-stripped.json && openapi-typescript src/generated/openapi-stripped.json -o src/generated/schema.d.ts && tsx scripts/patch-flexible-ids.ts && tsx scripts/extract-metadata.ts src/generated/openapi-stripped.json > src/generated/metadata.json && tsx scripts/generate-path-mapping.ts",
23
+ "generate": "tsx scripts/strip-account-id.ts ../openapi.json src/generated/openapi-stripped.json && openapi-typescript src/generated/openapi-stripped.json -o src/generated/schema.d.ts && tsx scripts/patch-flexible-ids.ts && tsx scripts/extract-metadata.ts src/generated/openapi-stripped.json > src/generated/metadata.ts && tsx scripts/generate-path-mapping.ts",
24
24
  "build": "tsc",
25
25
  "postbuild": "node -e \"fs=require('fs');fs.cpSync('src/generated','dist/generated',{recursive:true});\"",
26
26
  "prepublishOnly": "npm run build",
@@ -53,7 +53,7 @@
53
53
  "openapi-fetch": "^0.17.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@types/node": "^25.3.2",
56
+ "@types/node": "^26.1.0",
57
57
  "@vitest/coverage-v8": "^4.0.18",
58
58
  "msw": "^2.12.10",
59
59
  "openapi-typescript": "^7.13.0",
@@ -66,6 +66,9 @@
66
66
  "typescript": ">=5.0.0"
67
67
  },
68
68
  "overrides": {
69
- "minimatch": ">=10.2.1"
69
+ "minimatch": ">=10.2.1",
70
+ "brace-expansion": ">=5.0.7",
71
+ "fast-uri": ">=3.1.3",
72
+ "js-yaml": "^4.3.0"
70
73
  }
71
74
  }
@@ -1,7 +1,43 @@
1
- {
1
+ // Generated from OpenAPI x-basecamp-* extensions. Do not edit by hand.
2
+
3
+ export interface RetryConfig {
4
+ maxAttempts: number;
5
+ baseDelayMs: number;
6
+ backoff: "exponential" | "linear" | "constant";
7
+ retryOn: number[];
8
+ }
9
+
10
+ export interface PaginationConfig {
11
+ style: "link" | "cursor" | "page";
12
+ pageParam?: string;
13
+ totalCountHeader?: string;
14
+ maxPageSize?: number;
15
+ key?: string;
16
+ }
17
+
18
+ export interface IdempotentConfig {
19
+ keySupported?: boolean;
20
+ keyHeader?: string;
21
+ natural?: boolean;
22
+ }
23
+
24
+ export interface OperationMetadata {
25
+ retry?: RetryConfig;
26
+ pagination?: PaginationConfig;
27
+ idempotent?: IdempotentConfig;
28
+ }
29
+
30
+ export interface MetadataOutput {
31
+ $schema: string;
32
+ version: string;
33
+ generated: string;
34
+ operations: Record<string, OperationMetadata>;
35
+ }
36
+
37
+ const metadata: MetadataOutput = {
2
38
  "$schema": "https://basecamp.com/schemas/sdk-metadata.json",
3
39
  "version": "1.0.0",
4
- "generated": "2026-03-30T13:40:08.204Z",
40
+ "generated": "2026-07-23T19:34:22.062Z",
5
41
  "operations": {
6
42
  "GetAccount": {
7
43
  "retry": {
@@ -92,7 +128,7 @@
92
128
  "natural": true
93
129
  }
94
130
  },
95
- "ListWebhooks": {
131
+ "SetCardColumnColor": {
96
132
  "retry": {
97
133
  "maxAttempts": 3,
98
134
  "baseDelayMs": 1000,
@@ -102,13 +138,11 @@
102
138
  503
103
139
  ]
104
140
  },
105
- "pagination": {
106
- "style": "link",
107
- "totalCountHeader": "X-Total-Count",
108
- "maxPageSize": 50
141
+ "idempotent": {
142
+ "natural": true
109
143
  }
110
144
  },
111
- "CreateWebhook": {
145
+ "EnableCardColumnOnHold": {
112
146
  "retry": {
113
147
  "maxAttempts": 2,
114
148
  "baseDelayMs": 1000,
@@ -119,7 +153,7 @@
119
153
  ]
120
154
  }
121
155
  },
122
- "GetCard": {
156
+ "DisableCardColumnOnHold": {
123
157
  "retry": {
124
158
  "maxAttempts": 3,
125
159
  "baseDelayMs": 1000,
@@ -128,9 +162,12 @@
128
162
  429,
129
163
  503
130
164
  ]
165
+ },
166
+ "idempotent": {
167
+ "natural": true
131
168
  }
132
169
  },
133
- "UpdateCard": {
170
+ "UpdateWormhole": {
134
171
  "retry": {
135
172
  "maxAttempts": 3,
136
173
  "baseDelayMs": 1000,
@@ -144,18 +181,21 @@
144
181
  "natural": true
145
182
  }
146
183
  },
147
- "MoveCard": {
184
+ "DeleteWormhole": {
148
185
  "retry": {
149
- "maxAttempts": 2,
186
+ "maxAttempts": 3,
150
187
  "baseDelayMs": 1000,
151
188
  "backoff": "exponential",
152
189
  "retryOn": [
153
190
  429,
154
191
  503
155
192
  ]
193
+ },
194
+ "idempotent": {
195
+ "natural": true
156
196
  }
157
197
  },
158
- "RepositionCardStep": {
198
+ "CreateWormhole": {
159
199
  "retry": {
160
200
  "maxAttempts": 2,
161
201
  "baseDelayMs": 1000,
@@ -166,7 +206,7 @@
166
206
  ]
167
207
  }
168
208
  },
169
- "CreateCardStep": {
209
+ "CreateTool": {
170
210
  "retry": {
171
211
  "maxAttempts": 2,
172
212
  "baseDelayMs": 1000,
@@ -177,7 +217,7 @@
177
217
  ]
178
218
  }
179
219
  },
180
- "GetCardColumn": {
220
+ "ListWebhooks": {
181
221
  "retry": {
182
222
  "maxAttempts": 3,
183
223
  "baseDelayMs": 1000,
@@ -186,9 +226,25 @@
186
226
  429,
187
227
  503
188
228
  ]
229
+ },
230
+ "pagination": {
231
+ "style": "link",
232
+ "totalCountHeader": "X-Total-Count",
233
+ "maxPageSize": 50
234
+ }
235
+ },
236
+ "CreateWebhook": {
237
+ "retry": {
238
+ "maxAttempts": 2,
239
+ "baseDelayMs": 1000,
240
+ "backoff": "exponential",
241
+ "retryOn": [
242
+ 429,
243
+ 503
244
+ ]
189
245
  }
190
246
  },
191
- "UpdateCardColumn": {
247
+ "GetCard": {
192
248
  "retry": {
193
249
  "maxAttempts": 3,
194
250
  "baseDelayMs": 1000,
@@ -197,12 +253,9 @@
197
253
  429,
198
254
  503
199
255
  ]
200
- },
201
- "idempotent": {
202
- "natural": true
203
256
  }
204
257
  },
205
- "SetCardColumnColor": {
258
+ "UpdateCard": {
206
259
  "retry": {
207
260
  "maxAttempts": 3,
208
261
  "baseDelayMs": 1000,
@@ -216,7 +269,7 @@
216
269
  "natural": true
217
270
  }
218
271
  },
219
- "EnableCardColumnOnHold": {
272
+ "MoveCard": {
220
273
  "retry": {
221
274
  "maxAttempts": 2,
222
275
  "baseDelayMs": 1000,
@@ -227,7 +280,40 @@
227
280
  ]
228
281
  }
229
282
  },
230
- "DisableCardColumnOnHold": {
283
+ "RepositionCardStep": {
284
+ "retry": {
285
+ "maxAttempts": 2,
286
+ "baseDelayMs": 1000,
287
+ "backoff": "exponential",
288
+ "retryOn": [
289
+ 429,
290
+ 503
291
+ ]
292
+ }
293
+ },
294
+ "CreateCardStep": {
295
+ "retry": {
296
+ "maxAttempts": 2,
297
+ "baseDelayMs": 1000,
298
+ "backoff": "exponential",
299
+ "retryOn": [
300
+ 429,
301
+ 503
302
+ ]
303
+ }
304
+ },
305
+ "GetCardColumn": {
306
+ "retry": {
307
+ "maxAttempts": 3,
308
+ "baseDelayMs": 1000,
309
+ "backoff": "exponential",
310
+ "retryOn": [
311
+ 429,
312
+ 503
313
+ ]
314
+ }
315
+ },
316
+ "UpdateCardColumn": {
231
317
  "retry": {
232
318
  "maxAttempts": 3,
233
319
  "baseDelayMs": 1000,
@@ -565,6 +651,20 @@
565
651
  ]
566
652
  }
567
653
  },
654
+ "UpdateCampfireLine": {
655
+ "retry": {
656
+ "maxAttempts": 3,
657
+ "baseDelayMs": 1000,
658
+ "backoff": "exponential",
659
+ "retryOn": [
660
+ 429,
661
+ 503
662
+ ]
663
+ },
664
+ "idempotent": {
665
+ "natural": true
666
+ }
667
+ },
568
668
  "DeleteCampfireLine": {
569
669
  "retry": {
570
670
  "maxAttempts": 3,
@@ -728,17 +828,6 @@
728
828
  "natural": true
729
829
  }
730
830
  },
731
- "CloneTool": {
732
- "retry": {
733
- "maxAttempts": 2,
734
- "baseDelayMs": 1000,
735
- "backoff": "exponential",
736
- "retryOn": [
737
- 429,
738
- 503
739
- ]
740
- }
741
- },
742
831
  "GetTool": {
743
832
  "retry": {
744
833
  "maxAttempts": 3,
@@ -2330,7 +2419,7 @@
2330
2419
  ]
2331
2420
  }
2332
2421
  },
2333
- "UpdateTodo": {
2422
+ "ReplaceTodo": {
2334
2423
  "retry": {
2335
2424
  "maxAttempts": 3,
2336
2425
  "baseDelayMs": 1000,
@@ -2400,6 +2489,20 @@
2400
2489
  "natural": true
2401
2490
  }
2402
2491
  },
2492
+ "RepositionTodolist": {
2493
+ "retry": {
2494
+ "maxAttempts": 3,
2495
+ "baseDelayMs": 1000,
2496
+ "backoff": "exponential",
2497
+ "retryOn": [
2498
+ 429,
2499
+ 503
2500
+ ]
2501
+ },
2502
+ "idempotent": {
2503
+ "natural": true
2504
+ }
2505
+ },
2403
2506
  "GetTodoset": {
2404
2507
  "retry": {
2405
2508
  "maxAttempts": 3,
@@ -2650,4 +2753,7 @@
2650
2753
  }
2651
2754
  }
2652
2755
  }
2653
- }
2756
+ };
2757
+
2758
+ export default metadata;
2759
+