Skip to content

Commit add6b5a

Browse files
chore: formatted
1 parent a10202f commit add6b5a

2 files changed

Lines changed: 29 additions & 47 deletions

File tree

examples/nextjs/lib/api/api.config.ts

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import "server-only";
1+
import 'server-only';
22
/**
33
* The single (server-only) API client for the whole app, plus the SSR RPC bridge
44
* handler. Backed by https://dummyjson.com.
@@ -18,36 +18,33 @@ import "server-only";
1818
* npx @developerehsan/api-client generate \
1919
* --input ./lib/api/openapi.json --output ./lib/api/types/generated
2020
*/
21-
import { createTypedClient } from "@developerehsan/api-client";
22-
import {
23-
createRateLimiter,
24-
createRpcHandler,
25-
} from "@developerehsan/api-client/server";
26-
import { generatedModules } from "./types/generated/api.modules";
27-
import type { OperationsMap } from "./types/generated/api.types";
21+
import { createTypedClient } from '@developerehsan/api-client';
22+
import { createRateLimiter, createRpcHandler } from '@developerehsan/api-client/server';
23+
import { generatedModules } from './types/generated/api.modules';
24+
import type { OperationsMap } from './types/generated/api.types';
2825

2926
export const api = createTypedClient<OperationsMap>()(
3027
{
3128
// DummyJSON — the base URL, paths, and OpenAPI doc live ONLY here on the
3229
// server; the browser (via the RPC bridge) never sees them.
33-
baseURL: "https://dummyjson.com",
30+
baseURL: 'https://dummyjson.com',
3431
dev: { logging: true },
35-
openapi: { mode: "runtime", validation: { enabled: true, mode: "loose" } },
32+
openapi: { mode: 'runtime', validation: { enabled: true, mode: 'loose' } },
3633
http: {
37-
adapter: "fetch",
34+
adapter: 'fetch',
3835
timeout: 12_000,
39-
retry: { attempts: 3, backoff: "exponential", baseDelay: 400 },
36+
retry: { attempts: 3, backoff: 'exponential', baseDelay: 400 },
4037
queue: { concurrency: 6 },
4138
},
4239
hooks: {
4340
onCacheHit(key) {
44-
console.log("CACHE HIT", key);
41+
console.log('CACHE HIT', key);
4542
},
4643
onRetry(attempt, error) {
47-
console.log("RETRYING", error, { attempt });
44+
console.log('RETRYING', error, { attempt });
4845
},
4946
},
50-
cache: { strategy: "stale-while-revalidate", ttl: 30_000 },
47+
cache: { strategy: 'stale-while-revalidate', ttl: 30_000 },
5148
modules: {
5249
auto: true,
5350
products: {
@@ -56,18 +53,18 @@ export const api = createTypedClient<OperationsMap>()(
5653
getWithSiblings: async (ctx, id: number) => {
5754
const product = (
5855
await ctx.request({
59-
method: "GET",
60-
path: "/products/{id}",
56+
method: 'GET',
57+
path: '/products/{id}',
6158
pathParams: { id },
6259
})
63-
).data as OperationsMap["getProductById"]["response"];
60+
).data as OperationsMap['getProductById']['response'];
6461
const siblings = (
6562
await ctx.request({
66-
method: "GET",
67-
path: "/products/search",
68-
query: { q: product.category ?? "", limit: 5 },
63+
method: 'GET',
64+
path: '/products/search',
65+
query: { q: product.category ?? '', limit: 5 },
6966
})
70-
).data as OperationsMap["searchProducts"]["response"];
67+
).data as OperationsMap['searchProducts']['response'];
7168
return { product, siblings: siblings.products };
7269
},
7370
},
@@ -88,11 +85,11 @@ export type Api = typeof api;
8885
const limiter = createRateLimiter({
8986
windowMs: 10_000,
9087
max: 30,
91-
keyFor: async (ctx) => (await ctx.getCookie?.("demo_session")) ?? "anon",
88+
keyFor: async (ctx) => (await ctx.getCookie?.('demo_session')) ?? 'anon',
9289
});
9390

9491
/** Methods that mutate — gated behind an editor cookie by `authorize`. */
95-
const WRITE_METHODS = new Set(["addProduct", "updateProduct", "deleteProduct"]);
92+
const WRITE_METHODS = new Set(['addProduct', 'updateProduct', 'deleteProduct']);
9693

9794
/**
9895
* SSR RPC bridge — server side. `rpcHandler` is the single trust boundary: it
@@ -111,33 +108,23 @@ const WRITE_METHODS = new Set(["addProduct", "updateProduct", "deleteProduct"]);
111108
*/
112109
export const rpcHandler = createRpcHandler(api, {
113110
expose: {
114-
products: [
115-
"getProductById",
116-
"listProducts",
117-
"searchProducts",
118-
"addProduct",
119-
"getWithSiblings",
120-
],
121-
auth: ["login", "getCurrentUser"],
122-
users: ["getUserById"],
111+
products: ['getProductById', 'listProducts', 'searchProducts', 'addProduct', 'getWithSiblings'],
112+
auth: ['login', 'getCurrentUser'],
113+
users: ['getUserById'],
123114
},
124115
maxBatchSize: 10,
125116

126117
onRequest: limiter.onRequest,
127118

128119
authorize: async (ctx, call) => {
129120
if (!WRITE_METHODS.has(call.method)) return true; // reads: always allowed
130-
const editor = await ctx.getCookie?.("demo_editor");
131-
return editor === "1"; // deny → same error as "unknown method" (no enumeration)
121+
const editor = await ctx.getCookie?.('demo_editor');
122+
return editor === '1'; // deny → same error as "unknown method" (no enumeration)
132123
},
133124

134125
// Least-privilege: strip a product's bulky `images` array before it ships.
135126
transformResult: (result, call) => {
136-
if (
137-
call.method === "getProductById" &&
138-
result &&
139-
typeof result === "object"
140-
) {
127+
if (call.method === 'getProductById' && result && typeof result === 'object') {
141128
const safe = { ...(result as Record<string, unknown>) };
142129
delete safe.images;
143130
return safe;

package.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@
2929
"prepublishOnly": "pnpm build"
3030
},
3131
"pnpm": {
32-
"onlyBuiltDependencies": [
33-
"@biomejs/biome",
34-
"esbuild"
35-
]
32+
"onlyBuiltDependencies": ["@biomejs/biome", "esbuild"]
3633
},
3734
"devDependencies": {
3835
"@biomejs/biome": "^1.9.4",
@@ -47,7 +44,5 @@
4744
"directories": {
4845
"example": "examples"
4946
},
50-
"keywords": [
51-
"api-manager"
52-
]
47+
"keywords": ["api-manager"]
5348
}

0 commit comments

Comments
 (0)