cushin-monorepo 3.0.1
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/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.claude/settings.local.json +44 -0
- package/CHANGELOG.md +93 -0
- package/LICENSE +0 -0
- package/README.md +482 -0
- package/biome.json +34 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1552 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +84 -0
- package/dist/config/index.js +69 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +43 -0
- package/dist/config/schema.js +14 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +1666 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/client.d.ts +40 -0
- package/dist/runtime/client.js +260 -0
- package/dist/runtime/client.js.map +1 -0
- package/package.json +41 -0
- package/packages/api-codegen/CHANGELOG.md +86 -0
- package/packages/api-codegen/biome.json +34 -0
- package/packages/api-codegen/dist/cli.js +1038 -0
- package/packages/api-codegen/dist/cli.js.map +1 -0
- package/packages/api-codegen/dist/index.d.ts +103 -0
- package/packages/api-codegen/dist/index.js +1026 -0
- package/packages/api-codegen/dist/index.js.map +1 -0
- package/packages/api-codegen/node_modules/.bin/acorn +21 -0
- package/packages/api-codegen/node_modules/.bin/conventional-changelog +21 -0
- package/packages/api-codegen/node_modules/.bin/conventional-commits-parser +21 -0
- package/packages/api-codegen/node_modules/.bin/esbuild +21 -0
- package/packages/api-codegen/node_modules/.bin/eslint +21 -0
- package/packages/api-codegen/node_modules/.bin/jiti +21 -0
- package/packages/api-codegen/node_modules/.bin/next +21 -0
- package/packages/api-codegen/node_modules/.bin/tsc +21 -0
- package/packages/api-codegen/node_modules/.bin/tsserver +21 -0
- package/packages/api-codegen/node_modules/.bin/tsup +21 -0
- package/packages/api-codegen/node_modules/.bin/tsup-node +21 -0
- package/packages/api-codegen/node_modules/.bin/vitest +21 -0
- package/packages/api-codegen/package.json +88 -0
- package/packages/api-runtime/CHANGELOG.md +46 -0
- package/packages/api-runtime/README.md +95 -0
- package/packages/api-runtime/dist/chunk-3FFXWCVP.js +17 -0
- package/packages/api-runtime/dist/chunk-3FFXWCVP.js.map +1 -0
- package/packages/api-runtime/dist/chunk-EZ5P7OPH.js +267 -0
- package/packages/api-runtime/dist/chunk-EZ5P7OPH.js.map +1 -0
- package/packages/api-runtime/dist/client.d.ts +40 -0
- package/packages/api-runtime/dist/client.js +13 -0
- package/packages/api-runtime/dist/client.js.map +1 -0
- package/packages/api-runtime/dist/index.d.ts +3 -0
- package/packages/api-runtime/dist/index.js +21 -0
- package/packages/api-runtime/dist/index.js.map +1 -0
- package/packages/api-runtime/dist/schema.d.ts +45 -0
- package/packages/api-runtime/dist/schema.js +11 -0
- package/packages/api-runtime/dist/schema.js.map +1 -0
- package/packages/api-runtime/node_modules/.bin/esbuild +21 -0
- package/packages/api-runtime/node_modules/.bin/jiti +21 -0
- package/packages/api-runtime/node_modules/.bin/tsc +21 -0
- package/packages/api-runtime/node_modules/.bin/tsserver +21 -0
- package/packages/api-runtime/node_modules/.bin/tsup +21 -0
- package/packages/api-runtime/node_modules/.bin/tsup-node +21 -0
- package/packages/api-runtime/package.json +54 -0
- package/packages/cli/CHANGELOG.md +34 -0
- package/packages/cli/biome.json +34 -0
- package/packages/cli/dist/index.d.ts +27 -0
- package/packages/cli/dist/index.js +183 -0
- package/packages/cli/dist/index.js.map +1 -0
- package/packages/cli/node_modules/.bin/esbuild +21 -0
- package/packages/cli/node_modules/.bin/jiti +21 -0
- package/packages/cli/node_modules/.bin/tsc +21 -0
- package/packages/cli/node_modules/.bin/tsserver +21 -0
- package/packages/cli/node_modules/.bin/tsup +21 -0
- package/packages/cli/node_modules/.bin/tsup-node +21 -0
- package/packages/cli/package.json +47 -0
- package/pnpm-workspace.yaml +2 -0
- package/test-config.js +9 -0
- package/test-content-type-handling.mjs +100 -0
- package/test-endpoints-config.mjs +144 -0
- package/test-formdata-content-type-protection.mjs +127 -0
- package/test-formdata-runtime.mjs +127 -0
- package/test-full-integration.mjs +90 -0
- package/test-headers-formdata.mjs +97 -0
- package/test-headers-runtime.mjs +106 -0
- package/test-headers.mjs +79 -0
- package/test-internal-calls.mjs +57 -0
- package/test-ky-formdata.mjs +81 -0
- package/test-output/actions.ts +134 -0
- package/test-output/client.ts +81 -0
- package/test-output/hooks.ts +182 -0
- package/test-output/index.ts +9 -0
- package/test-output/prefetchs.ts +25 -0
- package/test-output/queries.ts +78 -0
- package/test-output/query-keys.ts +16 -0
- package/test-output/query-options.ts +38 -0
- package/test-output/server-client.ts +32 -0
- package/test-output/types.ts +61 -0
- package/test-real-endpoints.mjs +132 -0
- package/test-runtime-params.mjs +160 -0
- package/test-simple-config.mjs +71 -0
- package/tsconfig.base.json +29 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineEndpoint,
|
|
3
|
+
defineConfig,
|
|
4
|
+
createAPIClient,
|
|
5
|
+
} from "./packages/api-runtime/dist/index.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
console.log("Testing runtime header filtering...\n");
|
|
9
|
+
|
|
10
|
+
// Create test endpoints
|
|
11
|
+
const config = defineConfig({
|
|
12
|
+
baseUrl: "https://httpbin.org",
|
|
13
|
+
endpoints: {
|
|
14
|
+
testWithHeaders: defineEndpoint({
|
|
15
|
+
path: "headers",
|
|
16
|
+
method: "GET",
|
|
17
|
+
response: z.any(),
|
|
18
|
+
headers: {
|
|
19
|
+
"X-Custom-Header": "custom-value",
|
|
20
|
+
"X-Keep-This": "keep",
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
testWithMixedHeaders: defineEndpoint({
|
|
24
|
+
path: "headers",
|
|
25
|
+
method: "GET",
|
|
26
|
+
response: z.any(),
|
|
27
|
+
headers: {
|
|
28
|
+
"X-Custom-Header": "custom-value",
|
|
29
|
+
"X-Remove-Undefined": undefined,
|
|
30
|
+
"X-Remove-Null": null,
|
|
31
|
+
"X-Keep-This": "keep",
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
testWithAllRemoved: defineEndpoint({
|
|
35
|
+
path: "headers",
|
|
36
|
+
method: "GET",
|
|
37
|
+
response: z.any(),
|
|
38
|
+
headers: {
|
|
39
|
+
"X-Remove-1": undefined,
|
|
40
|
+
"X-Remove-2": null,
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Create API client
|
|
47
|
+
const client = createAPIClient(config);
|
|
48
|
+
|
|
49
|
+
console.log("Test 1: Headers with only string values");
|
|
50
|
+
try {
|
|
51
|
+
const response1 = await client.testWithHeaders();
|
|
52
|
+
console.log("✓ Request succeeded");
|
|
53
|
+
console.log(" Headers sent:", response1.headers);
|
|
54
|
+
if (
|
|
55
|
+
response1.headers["X-Custom-Header"] === "custom-value" &&
|
|
56
|
+
response1.headers["X-Keep-This"] === "keep"
|
|
57
|
+
) {
|
|
58
|
+
console.log(" ✓ Both headers were sent correctly\n");
|
|
59
|
+
} else {
|
|
60
|
+
console.log(" ✗ Headers were not sent correctly\n");
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.log("✗ Request failed:", error.message, "\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log("Test 2: Headers with undefined and null values");
|
|
67
|
+
try {
|
|
68
|
+
const response2 = await client.testWithMixedHeaders();
|
|
69
|
+
console.log("✓ Request succeeded");
|
|
70
|
+
console.log(" Headers sent:", response2.headers);
|
|
71
|
+
if (
|
|
72
|
+
response2.headers["X-Custom-Header"] === "custom-value" &&
|
|
73
|
+
response2.headers["X-Keep-This"] === "keep" &&
|
|
74
|
+
!response2.headers["X-Remove-Undefined"] &&
|
|
75
|
+
!response2.headers["X-Remove-Null"]
|
|
76
|
+
) {
|
|
77
|
+
console.log(
|
|
78
|
+
" ✓ Only non-null/undefined headers were sent (undefined/null headers filtered out)\n",
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
console.log(" ✗ Headers were not filtered correctly\n");
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.log("✗ Request failed:", error.message, "\n");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log("Test 3: All headers are undefined/null");
|
|
88
|
+
try {
|
|
89
|
+
const response3 = await client.testWithAllRemoved();
|
|
90
|
+
console.log("✓ Request succeeded");
|
|
91
|
+
console.log(" Headers sent:", response3.headers);
|
|
92
|
+
if (
|
|
93
|
+
!response3.headers["X-Remove-1"] &&
|
|
94
|
+
!response3.headers["X-Remove-2"]
|
|
95
|
+
) {
|
|
96
|
+
console.log(
|
|
97
|
+
" ✓ All undefined/null headers were filtered out (no custom headers sent)\n",
|
|
98
|
+
);
|
|
99
|
+
} else {
|
|
100
|
+
console.log(" ✗ Headers were not filtered correctly\n");
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.log("✗ Request failed:", error.message, "\n");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log("Runtime tests completed! ✨");
|
package/test-headers.mjs
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { defineEndpoint, defineConfig } from "./packages/api-runtime/dist/index.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
console.log("Testing header unsetting functionality...\n");
|
|
5
|
+
|
|
6
|
+
// Test 1: Headers with string values
|
|
7
|
+
const endpoint1 = defineEndpoint({
|
|
8
|
+
path: "/test",
|
|
9
|
+
method: "GET",
|
|
10
|
+
response: z.object({ message: z.string() }),
|
|
11
|
+
headers: {
|
|
12
|
+
"X-Custom-Header": "value1",
|
|
13
|
+
"X-Another-Header": "value2",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
console.log("✓ Test 1: Headers with string values");
|
|
18
|
+
console.log(" Input:", endpoint1.headers);
|
|
19
|
+
console.log(" Expected: All headers should be set");
|
|
20
|
+
console.log("");
|
|
21
|
+
|
|
22
|
+
// Test 2: Headers with undefined values (should be filtered out)
|
|
23
|
+
const endpoint2 = defineEndpoint({
|
|
24
|
+
path: "/test",
|
|
25
|
+
method: "GET",
|
|
26
|
+
response: z.object({ message: z.string() }),
|
|
27
|
+
headers: {
|
|
28
|
+
"X-Custom-Header": "value1",
|
|
29
|
+
"X-Remove-This": undefined,
|
|
30
|
+
"X-Another-Header": "value2",
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
console.log("✓ Test 2: Headers with undefined values");
|
|
35
|
+
console.log(" Input:", endpoint2.headers);
|
|
36
|
+
console.log(" Expected: X-Remove-This should be undefined");
|
|
37
|
+
console.log("");
|
|
38
|
+
|
|
39
|
+
// Test 3: Headers with null values (should be filtered out)
|
|
40
|
+
const endpoint3 = defineEndpoint({
|
|
41
|
+
path: "/test",
|
|
42
|
+
method: "GET",
|
|
43
|
+
response: z.object({ message: z.string() }),
|
|
44
|
+
headers: {
|
|
45
|
+
"X-Custom-Header": "value1",
|
|
46
|
+
"X-Remove-This": null,
|
|
47
|
+
"X-Another-Header": "value2",
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
console.log("✓ Test 3: Headers with null values");
|
|
52
|
+
console.log(" Input:", endpoint3.headers);
|
|
53
|
+
console.log(" Expected: X-Remove-This should be null");
|
|
54
|
+
console.log("");
|
|
55
|
+
|
|
56
|
+
// Test 4: Mixed headers
|
|
57
|
+
const endpoint4 = defineEndpoint({
|
|
58
|
+
path: "/test",
|
|
59
|
+
method: "POST",
|
|
60
|
+
response: z.object({ success: z.boolean() }),
|
|
61
|
+
body: z.object({ data: z.string() }),
|
|
62
|
+
headers: {
|
|
63
|
+
"X-Keep-This": "keep",
|
|
64
|
+
"X-Remove-Undefined": undefined,
|
|
65
|
+
"X-Remove-Null": null,
|
|
66
|
+
"X-Also-Keep": "also-keep",
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
console.log("✓ Test 4: Mixed headers");
|
|
71
|
+
console.log(" Input:", endpoint4.headers);
|
|
72
|
+
console.log(" Expected: Only X-Keep-This and X-Also-Keep should have string values");
|
|
73
|
+
console.log("");
|
|
74
|
+
|
|
75
|
+
console.log("All type checks passed! ✨");
|
|
76
|
+
console.log("\nThe implementation allows:");
|
|
77
|
+
console.log(" - Setting headers to string values");
|
|
78
|
+
console.log(" - Setting headers to undefined to unset them");
|
|
79
|
+
console.log(" - Setting headers to null to unset them");
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createAPIClient } from "./packages/api-runtime/dist/client.js";
|
|
2
|
+
import simpleConfig from "./test-simple-config.mjs";
|
|
3
|
+
|
|
4
|
+
console.log("=== TESTING INTERNAL request() CALLS ===\n");
|
|
5
|
+
console.log("Analyzing what parameters are passed to this.request()\n");
|
|
6
|
+
|
|
7
|
+
const client = createAPIClient(simpleConfig);
|
|
8
|
+
|
|
9
|
+
// Inspect the actual generated function code
|
|
10
|
+
console.log("1. listUsers (no params, no query):");
|
|
11
|
+
console.log(client.listUsers.toString());
|
|
12
|
+
console.log(" → Calls: this.request(endpoint)");
|
|
13
|
+
console.log(" → params argument: NOT PASSED (undefined by default)\n");
|
|
14
|
+
|
|
15
|
+
console.log("2. searchUsers (query only):");
|
|
16
|
+
console.log(client.searchUsers.toString());
|
|
17
|
+
console.log(" → Calls: this.request(endpoint, undefined, query)");
|
|
18
|
+
console.log(" → params argument: EXPLICITLY undefined ⚠️\n");
|
|
19
|
+
|
|
20
|
+
console.log("3. getUser (params only):");
|
|
21
|
+
console.log(client.getUser.toString());
|
|
22
|
+
console.log(" → Calls: this.request(endpoint, params)");
|
|
23
|
+
console.log(" → params argument: passed\n");
|
|
24
|
+
|
|
25
|
+
console.log("4. getUserPosts (params + query):");
|
|
26
|
+
console.log(client.getUserPosts.toString());
|
|
27
|
+
console.log(" → Calls: this.request(endpoint, params, query)");
|
|
28
|
+
console.log(" → params argument: passed\n");
|
|
29
|
+
|
|
30
|
+
console.log("5. createSession (POST, no params, no body):");
|
|
31
|
+
console.log(client.createSession.toString());
|
|
32
|
+
console.log(" → Calls: this.request(endpoint)");
|
|
33
|
+
console.log(" → params argument: NOT PASSED (undefined by default)\n");
|
|
34
|
+
|
|
35
|
+
console.log("6. createUser (POST, body only):");
|
|
36
|
+
console.log(client.createUser.toString());
|
|
37
|
+
console.log(" → Calls: this.request(endpoint, undefined, undefined, body)");
|
|
38
|
+
console.log(" → params argument: EXPLICITLY undefined ⚠️\n");
|
|
39
|
+
|
|
40
|
+
console.log("7. updateUser (POST, params + body):");
|
|
41
|
+
console.log(client.updateUser.toString());
|
|
42
|
+
console.log(" → Calls: this.request(endpoint, params, undefined, body)");
|
|
43
|
+
console.log(" → params argument: passed\n");
|
|
44
|
+
|
|
45
|
+
console.log("\n=== ANALYSIS ===\n");
|
|
46
|
+
console.log("Situations where params is EXPLICITLY passed as undefined:");
|
|
47
|
+
console.log(" 1. GET với query only: this.request(endpoint, undefined, query)");
|
|
48
|
+
console.log(" 2. POST/etc với body only: this.request(endpoint, undefined, undefined, body)");
|
|
49
|
+
console.log("");
|
|
50
|
+
console.log("This is happening in generateMethods() at:");
|
|
51
|
+
console.log(" - Line 266-269 (GET with query only)");
|
|
52
|
+
console.log(" - Line 283-287 (POST with body only)");
|
|
53
|
+
console.log("");
|
|
54
|
+
console.log("✅ However, this.request() handles this correctly!");
|
|
55
|
+
console.log(" The buildPath() method checks 'if (!params) return path;'");
|
|
56
|
+
console.log(" So passing undefined explicitly is SAFE and has no issues.");
|
|
57
|
+
console.log("");
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct ky test to understand FormData behavior
|
|
3
|
+
*/
|
|
4
|
+
import ky from 'ky';
|
|
5
|
+
|
|
6
|
+
console.log('\n🧪 Testing KY FormData Behavior\n');
|
|
7
|
+
|
|
8
|
+
// Create FormData
|
|
9
|
+
const formData = new FormData();
|
|
10
|
+
const fileBlob = new Blob(['test content'], { type: 'text/plain' });
|
|
11
|
+
formData.append('file', fileBlob, 'test.txt');
|
|
12
|
+
formData.append('metadata', JSON.stringify({ name: 'Test File' }));
|
|
13
|
+
|
|
14
|
+
console.log('FormData created with entries:', Array.from(formData.entries()).map(([k]) => k));
|
|
15
|
+
|
|
16
|
+
// Mock fetch to intercept
|
|
17
|
+
const originalFetch = globalThis.fetch;
|
|
18
|
+
|
|
19
|
+
globalThis.fetch = async (input, init) => {
|
|
20
|
+
console.log('\n📦 Fetch intercepted:');
|
|
21
|
+
console.log(' Input type:', input instanceof Request ? 'Request' : typeof input);
|
|
22
|
+
|
|
23
|
+
// If input is a Request object, extract info from it
|
|
24
|
+
if (input instanceof Request) {
|
|
25
|
+
console.log(' URL:', input.url);
|
|
26
|
+
console.log(' Method:', input.method);
|
|
27
|
+
console.log(' Body type:', input.body?.constructor?.name || 'none');
|
|
28
|
+
console.log(' Headers:');
|
|
29
|
+
for (const [key, value] of input.headers.entries()) {
|
|
30
|
+
console.log(` ${key}: ${value}`);
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
console.log(' URL:', typeof input === 'string' ? input : input.url);
|
|
34
|
+
console.log(' Method:', init?.method || 'GET');
|
|
35
|
+
console.log(' Body type:', init?.body?.constructor?.name || 'none');
|
|
36
|
+
console.log(' Body is FormData:', init?.body instanceof FormData);
|
|
37
|
+
|
|
38
|
+
const headers = init?.headers;
|
|
39
|
+
if (headers instanceof Headers) {
|
|
40
|
+
console.log(' Headers:');
|
|
41
|
+
for (const [key, value] of headers.entries()) {
|
|
42
|
+
console.log(` ${key}: ${value}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Return proper Response object
|
|
48
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
49
|
+
status: 200,
|
|
50
|
+
headers: { 'content-type': 'application/json' },
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
// Test 1: Direct ky call with FormData using body option
|
|
56
|
+
console.log('\n✅ Test 1: ky with options.body (FormData)');
|
|
57
|
+
await ky('https://httpbin.org/post', {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
body: formData,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log('\n✅ Test 2: ky.post with FormData');
|
|
63
|
+
const formData2 = new FormData();
|
|
64
|
+
formData2.append('test', 'value');
|
|
65
|
+
|
|
66
|
+
await ky.post('https://httpbin.org/post', {
|
|
67
|
+
body: formData2,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
console.log('\n✅ Test 3: ky with json option');
|
|
71
|
+
await ky.post('https://httpbin.org/post', {
|
|
72
|
+
json: { test: 'value' },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('❌ Error:', error.message);
|
|
77
|
+
} finally {
|
|
78
|
+
globalThis.fetch = originalFetch;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log('\n🎉 Ky test complete!\n');
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import { revalidateTag, revalidatePath } from "next/cache";
|
|
4
|
+
import { serverClient } from "./server-client";
|
|
5
|
+
import type {
|
|
6
|
+
APIEndpoints,
|
|
7
|
+
ExtractBody,
|
|
8
|
+
ExtractParams,
|
|
9
|
+
ExtractResponse,
|
|
10
|
+
} from "./types";
|
|
11
|
+
|
|
12
|
+
export type ActionResult<T> =
|
|
13
|
+
| { success: true; data: T }
|
|
14
|
+
| { success: false; error: string };
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create new session
|
|
18
|
+
* @tags auth
|
|
19
|
+
*/
|
|
20
|
+
export async function createSessionAction(): Promise<
|
|
21
|
+
ActionResult<ExtractResponse<APIEndpoints["createSession"]>>
|
|
22
|
+
> {
|
|
23
|
+
try {
|
|
24
|
+
const result = await serverClient.createSession();
|
|
25
|
+
|
|
26
|
+
// Revalidate related data
|
|
27
|
+
revalidateTag("auth");
|
|
28
|
+
|
|
29
|
+
return { success: true, data: result };
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error("[Server Action Error]:", error);
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create new user
|
|
41
|
+
* @tags users
|
|
42
|
+
*/
|
|
43
|
+
export async function createUserAction(
|
|
44
|
+
body: ExtractBody<APIEndpoints["createUser"]>,
|
|
45
|
+
): Promise<ActionResult<ExtractResponse<APIEndpoints["createUser"]>>> {
|
|
46
|
+
try {
|
|
47
|
+
const result = await serverClient.createUser(body);
|
|
48
|
+
|
|
49
|
+
// Revalidate related data
|
|
50
|
+
revalidateTag("users");
|
|
51
|
+
|
|
52
|
+
return { success: true, data: result };
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error("[Server Action Error]:", error);
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Update user
|
|
64
|
+
* @tags users
|
|
65
|
+
*/
|
|
66
|
+
export async function updateUserAction(input: {
|
|
67
|
+
params: ExtractParams<APIEndpoints["updateUser"]>;
|
|
68
|
+
body: ExtractBody<APIEndpoints["updateUser"]>;
|
|
69
|
+
}): Promise<ActionResult<ExtractResponse<APIEndpoints["updateUser"]>>> {
|
|
70
|
+
try {
|
|
71
|
+
const result = await (serverClient as any).updateUser(
|
|
72
|
+
input.params,
|
|
73
|
+
input.body,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Revalidate related data
|
|
77
|
+
revalidateTag("users");
|
|
78
|
+
|
|
79
|
+
return { success: true, data: result };
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error("[Server Action Error]:", error);
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Delete user
|
|
91
|
+
* @tags users
|
|
92
|
+
*/
|
|
93
|
+
export async function deleteUserAction(
|
|
94
|
+
params: ExtractParams<APIEndpoints["deleteUser"]>,
|
|
95
|
+
): Promise<ActionResult<ExtractResponse<APIEndpoints["deleteUser"]>>> {
|
|
96
|
+
try {
|
|
97
|
+
const result = await serverClient.deleteUser(params);
|
|
98
|
+
|
|
99
|
+
// Revalidate related data
|
|
100
|
+
revalidateTag("users");
|
|
101
|
+
|
|
102
|
+
return { success: true, data: result };
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("[Server Action Error]:", error);
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Refresh access token
|
|
114
|
+
* @tags auth
|
|
115
|
+
*/
|
|
116
|
+
export async function refreshTokenAction(): Promise<
|
|
117
|
+
ActionResult<ExtractResponse<APIEndpoints["refreshToken"]>>
|
|
118
|
+
> {
|
|
119
|
+
try {
|
|
120
|
+
const result = await serverClient.refreshToken();
|
|
121
|
+
|
|
122
|
+
// Revalidate related data
|
|
123
|
+
revalidateTag("auth");
|
|
124
|
+
|
|
125
|
+
return { success: true, data: result };
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("[Server Action Error]:", error);
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createAPIClient } from '@cushin/api-runtime';
|
|
4
|
+
import type { AuthCallbacks } from '@cushin/api-runtime';
|
|
5
|
+
import { apiConfig } from '../test-real-endpoints.mjs';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
// Type the methods based on endpoints
|
|
9
|
+
type APIClientMethods = {
|
|
10
|
+
[K in keyof typeof apiConfig.endpoints]: (typeof apiConfig.endpoints)[K] extends infer E
|
|
11
|
+
? E extends { method: "GET"; params: infer P; query: infer Q; response: infer R }
|
|
12
|
+
? (params: P extends z.ZodType ? z.infer<P> : never, query?: Q extends z.ZodType ? z.infer<Q> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
13
|
+
: E extends { method: "GET"; params: infer P; response: infer R }
|
|
14
|
+
? (params: P extends z.ZodType ? z.infer<P> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
15
|
+
: E extends { method: "GET"; query: infer Q; response: infer R }
|
|
16
|
+
? (query?: Q extends z.ZodType ? z.infer<Q> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
17
|
+
: E extends { method: "GET"; response: infer R }
|
|
18
|
+
? () => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
19
|
+
: E extends { method: string; params: infer P; body: infer B; response: infer R }
|
|
20
|
+
? (params: P extends z.ZodType ? z.infer<P> : never, body: B extends z.ZodType ? z.infer<B> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
21
|
+
: E extends { method: string; params: infer P; response: infer R }
|
|
22
|
+
? (params: P extends z.ZodType ? z.infer<P> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
23
|
+
: E extends { method: string; body: infer B; response: infer R }
|
|
24
|
+
? (body: B extends z.ZodType ? z.infer<B> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
25
|
+
: E extends { method: string; response: infer R }
|
|
26
|
+
? () => Promise<R extends z.ZodType ? z.infer<R> : never>
|
|
27
|
+
: never
|
|
28
|
+
: never;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// Export singleton instance (will be initialized later)
|
|
33
|
+
export let baseClient: APIClientMethods & {
|
|
34
|
+
refreshAuth: () => Promise<void>;
|
|
35
|
+
updateAuthCallbacks: (callbacks: AuthCallbacks) => void;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const apiClient = {
|
|
39
|
+
listUsers: (): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.listUsers.response>>> =>
|
|
40
|
+
(baseClient as any).listUsers(),
|
|
41
|
+
getUser: (params: z.infer<NonNullable<typeof apiConfig.endpoints.getUser.params>>): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.getUser.response>>> =>
|
|
42
|
+
(baseClient as any).getUser(params),
|
|
43
|
+
searchUsers: (query?: z.infer<NonNullable<typeof apiConfig.endpoints.searchUsers.query>>): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.searchUsers.response>>> =>
|
|
44
|
+
(baseClient as any).searchUsers(query),
|
|
45
|
+
getUserPosts: (params: z.infer<NonNullable<typeof apiConfig.endpoints.getUserPosts.params>>, query?: z.infer<NonNullable<typeof apiConfig.endpoints.getUserPosts.query>>): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.getUserPosts.response>>> =>
|
|
46
|
+
(baseClient as any).getUserPosts(params, query),
|
|
47
|
+
createSession: (): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.createSession.response>>> =>
|
|
48
|
+
(baseClient as any).createSession(),
|
|
49
|
+
createUser: (body: z.infer<NonNullable<typeof apiConfig.endpoints.createUser.body>>): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.createUser.response>>> =>
|
|
50
|
+
(baseClient as any).createUser(body),
|
|
51
|
+
updateUser: (params: z.infer<NonNullable<typeof apiConfig.endpoints.updateUser.params>>, body: z.infer<NonNullable<typeof apiConfig.endpoints.updateUser.body>>): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.updateUser.response>>> =>
|
|
52
|
+
(baseClient as any).updateUser(params, body),
|
|
53
|
+
deleteUser: (params: z.infer<NonNullable<typeof apiConfig.endpoints.deleteUser.params>>): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.deleteUser.response>>> =>
|
|
54
|
+
(baseClient as any).deleteUser(params),
|
|
55
|
+
refreshToken: (): Promise<z.infer<NonNullable<typeof apiConfig.endpoints.refreshToken.response>>> =>
|
|
56
|
+
(baseClient as any).refreshToken(),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Initialize API client with auth callbacks
|
|
61
|
+
* Call this function in your auth provider setup
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const authCallbacks = {
|
|
65
|
+
* getTokens: () => getStoredTokens(),
|
|
66
|
+
* onAuthError: () => router.push('/login'),
|
|
67
|
+
* onRefreshToken: async () => {
|
|
68
|
+
* await refreshAccessToken();
|
|
69
|
+
* },
|
|
70
|
+
* };
|
|
71
|
+
*
|
|
72
|
+
* initializeAPIClient(authCallbacks);
|
|
73
|
+
*/
|
|
74
|
+
export const initializeAPIClient = (authCallbacks: AuthCallbacks) => {
|
|
75
|
+
baseClient = createAPIClient(apiConfig, authCallbacks) as any;
|
|
76
|
+
return baseClient;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Export for custom usage
|
|
80
|
+
export { createAPIClient };
|
|
81
|
+
export type { AuthCallbacks };
|