@ranwhenparked/trustap-sdk 0.1.0 → 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.
Files changed (43) hide show
  1. package/README.md +139 -175
  2. package/dist/client.d.ts +24 -0
  3. package/dist/client.js +66 -0
  4. package/{src/schema.d.ts → dist/generated/types.d.ts} +971 -4157
  5. package/dist/generated/types.js +5 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.js +3 -0
  8. package/dist/webhooks/index.d.ts +2 -0
  9. package/dist/webhooks/index.js +2 -0
  10. package/dist/webhooks/schemas.d.ts +1067 -0
  11. package/dist/webhooks/schemas.js +243 -0
  12. package/dist/webhooks/state.d.ts +31 -0
  13. package/dist/webhooks/state.js +150 -0
  14. package/mod.ts +1 -0
  15. package/package.json +31 -32
  16. package/deno.json +0 -9
  17. package/eslint.config.js +0 -21
  18. package/scripts/build-node.mjs +0 -75
  19. package/scripts/generate-operations-map.mjs +0 -57
  20. package/scripts/generate-security-map.mjs +0 -92
  21. package/src/__tests__/auth-middleware.test.ts +0 -171
  22. package/src/__tests__/client-factory.test.ts +0 -105
  23. package/src/__tests__/error-handling.test.ts +0 -302
  24. package/src/__tests__/helpers/mock-http-client.ts +0 -193
  25. package/src/__tests__/helpers/run-guard.ts +0 -24
  26. package/src/__tests__/helpers/test-fixtures.ts +0 -82
  27. package/src/__tests__/node-client.test.ts +0 -244
  28. package/src/__tests__/operation-proxy.test.ts +0 -268
  29. package/src/__tests__/query-params.test.ts +0 -232
  30. package/src/__tests__/setup.ts +0 -44
  31. package/src/__tests__/types.test.ts +0 -169
  32. package/src/client-deno.ts +0 -219
  33. package/src/client-factory.ts +0 -45
  34. package/src/core.ts +0 -619
  35. package/src/index.deno.ts +0 -28
  36. package/src/index.ts +0 -36
  37. package/src/operations-map.ts +0 -667
  38. package/src/security-map.ts +0 -770
  39. package/src/state-machine.ts +0 -79
  40. package/src/webhook-schemas.ts +0 -400
  41. package/tsconfig.build.json +0 -27
  42. package/tsconfig.json +0 -22
  43. package/vitest.config.ts +0 -31
@@ -1,92 +0,0 @@
1
- #!/usr/bin/env node
2
- // Generate a minimal security map from an OpenAPI document (JSON or YAML)
3
- // Usage: node scripts/generate-security-map.mjs [/absolute/or/relative/path/or/url]
4
-
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import process from 'node:process';
8
- import { fileURLToPath } from 'node:url';
9
- import { createRequire } from 'node:module';
10
-
11
- const require = createRequire(import.meta.url);
12
- let YAML;
13
- try {
14
- YAML = require('yaml');
15
- } catch {}
16
-
17
- const inputArg = process.argv[2] || 'https://docs.trustap.com/_spec/apis/openapi.yaml';
18
-
19
- async function readOpenApi(source) {
20
- if (/^https?:\/\//.test(source)) {
21
- const res = await fetch(source);
22
- if (!res.ok) throw new Error(`Failed to fetch ${source}: ${res.status}`);
23
- const text = await res.text();
24
- if (source.endsWith('.yaml') || source.endsWith('.yml')) {
25
- if (!YAML) throw new Error('yaml package not available');
26
- return YAML.parse(text);
27
- }
28
- return JSON.parse(text);
29
- }
30
- const content = fs.readFileSync(source, 'utf8');
31
- if (source.endsWith('.yaml') || source.endsWith('.yml')) {
32
- if (!YAML) throw new Error('yaml package not available');
33
- return YAML.parse(content);
34
- }
35
- return JSON.parse(content);
36
- }
37
-
38
- function normalizeSecurityArray(secArr) {
39
- // Convert OpenAPI security array to a set of scheme names
40
- // e.g., [{ OAuth2: [] }, { APIKey: [] }] -> Set(['OAuth2','APIKey'])
41
- const set = new Set();
42
- if (Array.isArray(secArr)) {
43
- for (const entry of secArr) {
44
- if (entry && typeof entry === 'object') {
45
- for (const key of Object.keys(entry)) set.add(key);
46
- }
47
- }
48
- }
49
- return set;
50
- }
51
-
52
- function buildSecurityMap(doc) {
53
- const out = {}; // { path: { METHOD: ['APIKey','OAuth2'] } }
54
- const globalSec = normalizeSecurityArray(doc.security);
55
- const paths = doc.paths || {};
56
- for (const p of Object.keys(paths)) {
57
- const item = paths[p] || {};
58
- for (const method of Object.keys(item)) {
59
- const op = item[method];
60
- if (!op || typeof op !== 'object') continue;
61
- if (!['get','post','put','patch','delete','head','options','trace'].includes(method)) continue;
62
- const opSec = normalizeSecurityArray(op.security);
63
- const effective = opSec.size > 0 ? opSec : globalSec;
64
- if (!out[p]) out[p] = {};
65
- out[p][method.toUpperCase()] = Array.from(effective);
66
- }
67
- }
68
- return out;
69
- }
70
-
71
- function emitTs(securityMap) {
72
- const header = `// generated by scripts/generate-security-map.mjs\n`;
73
- const body = `export const securityMap = ${JSON.stringify(securityMap, null, 2)} as const;\n`;
74
- return header + body;
75
- }
76
-
77
- async function main() {
78
- const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
79
- const outFile = path.join(rootDir, 'src', 'security-map.ts');
80
- const api = await readOpenApi(inputArg);
81
- const map = buildSecurityMap(api);
82
- const ts = emitTs(map);
83
- fs.writeFileSync(outFile, ts, 'utf8');
84
- console.log(`Wrote ${outFile}`);
85
- }
86
-
87
- main().catch((err) => {
88
- console.error(err);
89
- process.exit(1);
90
- });
91
-
92
-
@@ -1,171 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
-
3
- import { createTrustapClientWithDeps } from "../client-factory.ts";
4
- import type { TrustapClientDependencies } from "../client-factory.ts";
5
- import { MockHttpClient } from "./helpers/mock-http-client.ts";
6
- import type { MockMiddleware } from "./helpers/mock-http-client.ts";
7
- import {
8
- createTestOptions,
9
- encodeBasicAuth,
10
- mockBasicAuth,
11
- mockOAuthToken,
12
- sampleCarrierFacilityRequest,
13
- sampleChargeQuery,
14
- sampleTransactionBody,
15
- } from "./helpers/test-fixtures.ts";
16
- import { runTrustapSuite } from "./helpers/run-guard.ts";
17
-
18
- runTrustapSuite(import.meta.url, "Auth Middleware", () => {
19
- describe("Auth Middleware", () => {
20
- let mockClient: MockHttpClient;
21
-
22
- const createDeps = (): TrustapClientDependencies<
23
- MockMiddleware,
24
- MockHttpClient,
25
- Record<string, unknown>
26
- > => ({
27
- createClient: () => mockClient,
28
- wrapAsPathBasedClient: () => ({}),
29
- });
30
-
31
- const createClient = (
32
- overrides?: Parameters<typeof createTestOptions>[0],
33
- ) =>
34
- createTrustapClientWithDeps(
35
- createDeps(),
36
- createTestOptions(overrides ?? {}),
37
- );
38
-
39
- beforeEach(() => {
40
- mockClient = new MockHttpClient();
41
- });
42
-
43
- it("adds a Basic Authorization header when APIKey security is declared", async () => {
44
- const client = createClient({ getAccessToken: undefined });
45
-
46
- await client["basic.getCharge"]({
47
- params: { query: sampleChargeQuery },
48
- });
49
-
50
- const header = mockClient.requests[0]?.request.headers.get(
51
- "Authorization",
52
- );
53
- expect(header).toBe(
54
- `Basic ${encodeBasicAuth(
55
- mockBasicAuth.username,
56
- mockBasicAuth.password,
57
- )}`,
58
- );
59
- });
60
-
61
- it("reuses the encoded Basic credentials for repeated calls", async () => {
62
- const client = createClient({ getAccessToken: undefined });
63
-
64
- await client["basic.getCharge"]({
65
- params: { query: sampleChargeQuery },
66
- });
67
- await client["basic.getCharge"]({
68
- params: { query: sampleChargeQuery },
69
- });
70
-
71
- const first = mockClient.requests[0]?.request.headers.get(
72
- "Authorization",
73
- );
74
- const second = mockClient.requests[1]?.request.headers.get(
75
- "Authorization",
76
- );
77
- expect(first).toBe(second);
78
- });
79
-
80
- it("requests bearer tokens for OAuth-protected endpoints", async () => {
81
- const getAccessToken = vi.fn(() => Promise.resolve(mockOAuthToken));
82
- const client = createClient({
83
- basicAuth: undefined,
84
- getAccessToken,
85
- });
86
-
87
- await client["oauth.getUser"]({
88
- params: {
89
- path: { userId: "user_123" },
90
- },
91
- });
92
-
93
- const header = mockClient.requests[0]?.request.headers.get(
94
- "Authorization",
95
- );
96
- expect(header).toBe(`Bearer ${mockOAuthToken}`);
97
- expect(getAccessToken).toHaveBeenCalledTimes(1);
98
- });
99
-
100
- it("honors authOverrides using exact path matches", async () => {
101
- const client = createClient({
102
- authOverrides: {
103
- "/transactions": "basic",
104
- },
105
- });
106
-
107
- await client["basic.createTransaction"]({
108
- body: sampleTransactionBody,
109
- });
110
-
111
- const header = mockClient.requests[0]?.request.headers.get(
112
- "Authorization",
113
- );
114
- expect(header).toBe(
115
- `Basic ${encodeBasicAuth(
116
- mockBasicAuth.username,
117
- mockBasicAuth.password,
118
- )}`,
119
- );
120
- });
121
-
122
- it("uses explicit OAuth overrides when provided", async () => {
123
- const client = createClient({
124
- authOverrides: {
125
- "/transactions": "oauth2",
126
- },
127
- getAccessToken: () => Promise.resolve(mockOAuthToken),
128
- });
129
-
130
- await client["basic.createTransaction"]({
131
- body: sampleTransactionBody,
132
- });
133
-
134
- const header = mockClient.requests[0]?.request.headers.get(
135
- "Authorization",
136
- );
137
- expect(header).toBe(`Bearer ${mockOAuthToken}`);
138
- });
139
-
140
- it("does not override an Authorization header that is already present", async () => {
141
- const client = createClient({ getAccessToken: undefined });
142
-
143
- await client["basic.getCharge"]({
144
- headers: { Authorization: "Custom token" },
145
- params: { query: sampleChargeQuery },
146
- });
147
-
148
- const header = mockClient.requests[0]?.request.headers.get(
149
- "Authorization",
150
- );
151
- expect(header).toBe("Custom token");
152
- });
153
-
154
- it("skips auth headers when no credentials are configured", async () => {
155
- const client = createClient({
156
- basicAuth: undefined,
157
- getAccessToken: undefined,
158
- });
159
-
160
- await client["basic.getCarrierFacilityOptions"]({
161
- params: { path: { carrier_id: "carrier_1" } },
162
- body: sampleCarrierFacilityRequest,
163
- });
164
-
165
- const header = mockClient.requests[0]?.request.headers.get(
166
- "Authorization",
167
- );
168
- expect(header).toBeNull();
169
- });
170
- });
171
- });
@@ -1,105 +0,0 @@
1
- import { beforeEach, describe, expect, it } from "vitest";
2
-
3
- import { createTrustapClientWithDeps } from "../client-factory.ts";
4
- import type { TrustapClientDependencies } from "../client-factory.ts";
5
- import { MockHttpClient } from "./helpers/mock-http-client.ts";
6
- import type { MockMiddleware } from "./helpers/mock-http-client.ts";
7
- import {
8
- createTestOptions,
9
- encodeBasicAuth,
10
- mockBasicAuth,
11
- sampleChargeQuery,
12
- } from "./helpers/test-fixtures.ts";
13
- import { runTrustapSuite } from "./helpers/run-guard.ts";
14
-
15
- runTrustapSuite(import.meta.url, "Client Factory", () => {
16
- describe("Client Factory", () => {
17
- let mockClient: MockHttpClient;
18
-
19
- const createDeps = (): TrustapClientDependencies<
20
- MockMiddleware,
21
- MockHttpClient,
22
- { pathBased: MockHttpClient }
23
- > => ({
24
- createClient: () => mockClient,
25
- wrapAsPathBasedClient: (client) => ({ pathBased: client }),
26
- });
27
-
28
- beforeEach(() => {
29
- mockClient = new MockHttpClient();
30
- });
31
-
32
- it("creates a client that exposes operation-id functions", () => {
33
- const client = createTrustapClientWithDeps(
34
- createDeps(),
35
- createTestOptions({ getAccessToken: undefined }),
36
- );
37
-
38
- expect(client).toBeDefined();
39
- expect(typeof client["basic.getCharge"]).toBe("function");
40
- });
41
-
42
- it("routes requests using the generated operations map", async () => {
43
- const client = createTrustapClientWithDeps(
44
- createDeps(),
45
- createTestOptions({ getAccessToken: undefined }),
46
- );
47
-
48
- await client["basic.getCharge"]({
49
- params: { query: sampleChargeQuery },
50
- });
51
-
52
- expect(mockClient.requests).toHaveLength(1);
53
- expect(mockClient.requests[0]?.path).toBe("/api/v4/charge");
54
- expect(mockClient.requests[0]?.method).toBe("GET");
55
- });
56
-
57
- it("applies auth middleware sourced from the security map", async () => {
58
- const client = createTrustapClientWithDeps(
59
- createDeps(),
60
- createTestOptions({ getAccessToken: undefined }),
61
- );
62
-
63
- await client["basic.getCharge"]({
64
- params: { query: sampleChargeQuery },
65
- });
66
-
67
- const header = mockClient.requests[0]?.request.headers.get(
68
- "Authorization",
69
- );
70
- expect(header).toBe(
71
- `Basic ${encodeBasicAuth(
72
- mockBasicAuth.username,
73
- mockBasicAuth.password,
74
- )}`,
75
- );
76
- });
77
-
78
- it("exposes the underlying HTTP client via the raw property", () => {
79
- const client = createTrustapClientWithDeps(
80
- createDeps(),
81
- createTestOptions({ getAccessToken: undefined }),
82
- ) as { raw: MockHttpClient };
83
-
84
- expect(client.raw).toBe(mockClient);
85
- });
86
-
87
- it("merges the path-based wrapper onto the returned client", () => {
88
- const deps: TrustapClientDependencies<
89
- MockMiddleware,
90
- MockHttpClient,
91
- { byPath: MockHttpClient }
92
- > = {
93
- createClient: () => mockClient,
94
- wrapAsPathBasedClient: (client) => ({ byPath: client }),
95
- };
96
-
97
- const client = createTrustapClientWithDeps(
98
- deps,
99
- createTestOptions({ getAccessToken: undefined }),
100
- ) as { byPath: MockHttpClient };
101
-
102
- expect(client.byPath).toBe(mockClient);
103
- });
104
- });
105
- });
@@ -1,302 +0,0 @@
1
- import { beforeEach, describe, expect, it } from "vitest";
2
-
3
- import { createTrustapClientWithDeps } from "../client-factory.ts";
4
- import type { TrustapClientDependencies } from "../client-factory.ts";
5
- import { MockHttpClient } from "./helpers/mock-http-client.ts";
6
- import type { MockMiddleware } from "./helpers/mock-http-client.ts";
7
- import { createTestOptions } from "./helpers/test-fixtures.ts";
8
- import { runTrustapSuite } from "./helpers/run-guard.ts";
9
-
10
- const CHARGE_ENDPOINT = "/api/v4/charge";
11
-
12
- runTrustapSuite(import.meta.url, "Error Handling", () => {
13
- describe("Error Handling", () => {
14
- let mockClient: MockHttpClient;
15
-
16
- const createDeps = (): TrustapClientDependencies<
17
- MockMiddleware,
18
- MockHttpClient,
19
- Record<string, unknown>
20
- > => ({
21
- createClient: () => mockClient,
22
- wrapAsPathBasedClient: () => ({}),
23
- });
24
-
25
- const createClient = (
26
- overrides?: Parameters<typeof createTestOptions>[0],
27
- ) =>
28
- createTrustapClientWithDeps(
29
- createDeps(),
30
- createTestOptions(overrides ?? {}),
31
- );
32
-
33
- beforeEach(() => {
34
- mockClient = new MockHttpClient();
35
- });
36
-
37
- describe("Network Failures", () => {
38
- it("handles network errors when middleware throws", async () => {
39
- const client = createClient({ getAccessToken: undefined });
40
-
41
- // Simulate network failure by adding middleware that throws
42
- mockClient.use({
43
- onRequest: () => {
44
- throw new Error("Network connection failed");
45
- },
46
- });
47
-
48
- await expect(client["basic.getCharge"]()).rejects.toThrow(
49
- "Network connection failed",
50
- );
51
- });
52
-
53
- it("handles errors in response middleware", async () => {
54
- const client = createClient({ getAccessToken: undefined });
55
-
56
- mockClient.use({
57
- onResponse: () => {
58
- throw new Error("Response processing failed");
59
- },
60
- });
61
-
62
- await expect(client["basic.getCharge"]()).rejects.toThrow(
63
- "Response processing failed",
64
- );
65
- });
66
- });
67
-
68
- describe("HTTP Error Responses", () => {
69
- it("returns error for 400 Bad Request", async () => {
70
- const client = createClient({ getAccessToken: undefined });
71
-
72
- mockClient.setResponse(CHARGE_ENDPOINT, "GET", {
73
- error: { message: "Invalid parameters" },
74
- status: 400,
75
- });
76
-
77
- const result = await client["basic.getCharge"]();
78
-
79
- expect(result.error).toEqual({ message: "Invalid parameters" });
80
- expect(result.data).toBeUndefined();
81
- expect(result.response.status).toBe(400);
82
- });
83
-
84
- it("returns error for 401 Unauthorized", async () => {
85
- const client = createClient({ getAccessToken: undefined });
86
-
87
- mockClient.setResponse(CHARGE_ENDPOINT, "GET", {
88
- error: { message: "Unauthorized" },
89
- status: 401,
90
- });
91
-
92
- const result = await client["basic.getCharge"]();
93
-
94
- expect(result.error).toEqual({ message: "Unauthorized" });
95
- expect(result.data).toBeUndefined();
96
- expect(result.response.status).toBe(401);
97
- });
98
-
99
- it("returns error for 403 Forbidden", async () => {
100
- const client = createClient({ getAccessToken: undefined });
101
-
102
- mockClient.setResponse(CHARGE_ENDPOINT, "GET", {
103
- error: { message: "Forbidden" },
104
- status: 403,
105
- });
106
-
107
- const result = await client["basic.getCharge"]();
108
-
109
- expect(result.error).toEqual({ message: "Forbidden" });
110
- expect(result.data).toBeUndefined();
111
- expect(result.response.status).toBe(403);
112
- });
113
-
114
- it("returns error for 404 Not Found", async () => {
115
- const client = createClient({ getAccessToken: undefined });
116
-
117
- mockClient.setResponse(CHARGE_ENDPOINT, "GET", {
118
- error: { message: "Not found" },
119
- status: 404,
120
- });
121
-
122
- const result = await client["basic.getCharge"]();
123
-
124
- expect(result.error).toEqual({ message: "Not found" });
125
- expect(result.data).toBeUndefined();
126
- expect(result.response.status).toBe(404);
127
- });
128
-
129
- it("returns error for 500 Internal Server Error", async () => {
130
- const client = createClient({ getAccessToken: undefined });
131
-
132
- mockClient.setResponse(CHARGE_ENDPOINT, "GET", {
133
- error: { message: "Internal server error" },
134
- status: 500,
135
- });
136
-
137
- const result = await client["basic.getCharge"]();
138
-
139
- expect(result.error).toEqual({ message: "Internal server error" });
140
- expect(result.data).toBeUndefined();
141
- expect(result.response.status).toBe(500);
142
- });
143
-
144
- it("returns error for 503 Service Unavailable", async () => {
145
- const client = createClient({ getAccessToken: undefined });
146
-
147
- mockClient.setResponse(CHARGE_ENDPOINT, "GET", {
148
- error: { message: "Service unavailable" },
149
- status: 503,
150
- });
151
-
152
- const result = await client["basic.getCharge"]();
153
-
154
- expect(result.error).toEqual({ message: "Service unavailable" });
155
- expect(result.data).toBeUndefined();
156
- expect(result.response.status).toBe(503);
157
- });
158
- });
159
-
160
- describe("Malformed Responses", () => {
161
- it("handles responses with invalid JSON", async () => {
162
- const client = createClient({ getAccessToken: undefined });
163
-
164
- // Mock a response that will fail JSON parsing
165
- mockClient.use({
166
- onResponse: () => {
167
- return new Response("Invalid JSON {{{", {
168
- status: 200,
169
- headers: { "content-type": "application/json" },
170
- });
171
- },
172
- });
173
-
174
- const result = await client["basic.getCharge"]();
175
-
176
- // Response should still be returned even if body parsing might fail later
177
- expect(result.response).toBeInstanceOf(Response);
178
- expect(result.response.status).toBe(200);
179
- });
180
-
181
- it("handles responses with missing content-type", async () => {
182
- const client = createClient({ getAccessToken: undefined });
183
-
184
- mockClient.use({
185
- onResponse: () => {
186
- return Response.json({ data: "test" }, {
187
- status: 200,
188
- // No content-type header
189
- });
190
- },
191
- });
192
-
193
- const result = await client["basic.getCharge"]();
194
-
195
- expect(result.response).toBeInstanceOf(Response);
196
- expect(result.response.status).toBe(200);
197
- });
198
-
199
- it("handles empty response bodies", async () => {
200
- const client = createClient({ getAccessToken: undefined });
201
-
202
- mockClient.use({
203
- onResponse: () => {
204
- return new Response(null, {
205
- status: 204,
206
- headers: { "content-type": "application/json" },
207
- });
208
- },
209
- });
210
-
211
- const result = await client["basic.getCharge"]();
212
-
213
- expect(result.response).toBeInstanceOf(Response);
214
- expect(result.response.status).toBe(204);
215
- });
216
- });
217
-
218
- describe("Authentication Errors", () => {
219
- it("handles OAuth token retrieval failures", async () => {
220
- const client = createClient({
221
- basicAuth: undefined,
222
- getAccessToken: () =>
223
- Promise.reject(new Error("Failed to get access token")),
224
- });
225
-
226
- await expect(
227
- client["oauth.getUser"]({
228
- params: { path: { userId: "user_123" } },
229
- }),
230
- ).rejects.toThrow("Failed to get access token");
231
- });
232
-
233
- it("continues when OAuth token is null or empty", async () => {
234
- const client = createClient({
235
- basicAuth: undefined,
236
- getAccessToken: () => Promise.resolve(""),
237
- });
238
-
239
- // Should not throw, just proceed without auth header
240
- const result = await client["oauth.getUser"]({
241
- params: { path: { userId: "user_123" } },
242
- });
243
-
244
- expect(result.response).toBeInstanceOf(Response);
245
-
246
- // Verify no Authorization header was set
247
- const authHeader = mockClient.requests[0]?.request.headers.get(
248
- "Authorization",
249
- );
250
- expect(authHeader).toBeNull();
251
- });
252
- });
253
-
254
- describe("Path Parameter Errors", () => {
255
- it("handles missing required path parameters", async () => {
256
- const client = createClient({
257
- basicAuth: undefined,
258
- getAccessToken: () => Promise.resolve("token"),
259
- });
260
-
261
- // Call with missing userId parameter
262
- await client["oauth.getUser"]({
263
- params: { path: {} },
264
- });
265
-
266
- // Path should contain the unreplaced placeholder
267
- const requestPath = mockClient.requests[0]?.path;
268
- expect(requestPath).toContain("{userId}");
269
- });
270
-
271
- it("handles null path parameters", async () => {
272
- const client = createClient({
273
- basicAuth: undefined,
274
- getAccessToken: () => Promise.resolve("token"),
275
- });
276
-
277
- await client["oauth.getUser"]({
278
- params: { path: { userId: null } },
279
- });
280
-
281
- // Path should contain the unreplaced placeholder
282
- const requestPath = mockClient.requests[0]?.path;
283
- expect(requestPath).toContain("{userId}");
284
- });
285
-
286
- it("handles undefined path parameters", async () => {
287
- const client = createClient({
288
- basicAuth: undefined,
289
- getAccessToken: () => Promise.resolve("token"),
290
- });
291
-
292
- await client["oauth.getUser"]({
293
- params: { path: { userId: undefined } },
294
- });
295
-
296
- // Path should contain the unreplaced placeholder
297
- const requestPath = mockClient.requests[0]?.path;
298
- expect(requestPath).toContain("{userId}");
299
- });
300
- });
301
- });
302
- });