Skip to content

Commit 991ac01

Browse files
committed
refactor(callapi/hooks): make hook registries use lazy instantiation instead of having to deep copy with structured clone🧩
chore(deps): update workspace package.json files and sync pnpm-lock.yaml 📦🔒
1 parent ea4bfb1 commit 991ac01

13 files changed

Lines changed: 739 additions & 621 deletions

File tree

.changeset/soft-windows-throw.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@zayne-labs/callapi": patch
3+
---
4+
5+
refactor(callapi/hooks): make hook registries use lazy instantiation instead of having to deep copy with structured clone🧩
6+
7+
chore(deps): update workspace package.json files and sync pnpm-lock.yaml 📦🔒

apps/dev/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
"dependencies": {
1414
"@zayne-labs/callapi": "workspace:*",
1515
"@zayne-labs/callapi-plugins": "workspace:*",
16-
"zod": "^4.0.14"
16+
"zod": "^4.0.17"
1717
},
1818
"devDependencies": {
19-
"@types/node": "^24.1.0",
19+
"@types/node": "^24.2.1",
2020
"@zayne-labs/tsconfig": "0.9.9",
2121
"tsx": "^4.20.3",
2222
"typescript": "5.9.2",
23-
"vite": "^7.0.6"
23+
"vite": "^7.1.1"
2424
}
2525
}

apps/dev/src/client.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ const stream = new ReadableStream({
111111
},
112112
}).pipeThrough(new TextEncoderStream());
113113

114-
const [result1, result2, result3, result4, result5, result6] = await Promise.all([
114+
const [result1, result2, result3, result4, result5, result6, result7, result8] = await Promise.all([
115115
callMainApi<{ price: number }>("/products/:id", {
116116
onRequest: () => console.info("OnRequest - INSTANCE"),
117117
params: [1],
@@ -149,7 +149,9 @@ const [result1, result2, result3, result4, result5, result6] = await Promise.all
149149
callMainApi("https://api.github.com/repos/zayne-labs/ui/commits?per_page=50", {
150150
onRequestStream: (ctx) => console.info("OnRequestStream", { event: ctx.event }),
151151
onResponseStream: (ctx) => console.info("OnResponseStream", { event: ctx.event }),
152-
responseParser: (responseString) => JSON.parse(responseString) as { foo: string },
152+
schema: {
153+
data: () => ({}) as { foo: string },
154+
},
153155
// schemaConfig: (ctx) => ({
154156
// strict: false,
155157
// }),

apps/docs/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,23 @@
1212
"dependencies": {
1313
"@bprogress/next": "^3.2.12",
1414
"@iconify/react": "^6.0.0",
15-
"@shikijs/twoslash": "3.9.1",
15+
"@shikijs/twoslash": "3.9.2",
1616
"@zayne-labs/callapi": "workspace:*",
1717
"@zayne-labs/toolkit-core": "^0.10.6",
1818
"@zayne-labs/toolkit-react": "^0.10.6",
1919
"@zayne-labs/toolkit-type-helpers": "^0.10.6",
2020
"@zayne-labs/ui-react": "^0.9.21",
2121
"clsx": "^2.1.1",
22-
"fumadocs-core": "15.6.8",
22+
"fumadocs-core": "15.6.9",
2323
"fumadocs-docgen": "2.1.0",
24-
"fumadocs-mdx": "11.7.3",
24+
"fumadocs-mdx": "11.7.4",
2525
"fumadocs-twoslash": "3.1.4",
2626
"fumadocs-typescript": "4.0.6",
27-
"fumadocs-ui": "15.6.8",
27+
"fumadocs-ui": "15.6.9",
2828
"geist": "^1.4.2",
29-
"lucide-react": "^0.536.0",
29+
"lucide-react": "^0.539.0",
3030
"motion": "^12.23.12",
31-
"next": "15.4.5",
31+
"next": "15.4.6",
3232
"react": "19.1.1",
3333
"react-dom": "19.1.1",
3434
"remark": "^15.0.1",
@@ -37,13 +37,13 @@
3737
"schema-dts": "^1.1.5",
3838
"tailwind-merge": "^3.3.1",
3939
"tailwind-variants": "^2.1.0",
40-
"zod": "^4.0.14",
40+
"zod": "^4.0.17",
4141
"zustand": "^5.0.7"
4242
},
4343
"devDependencies": {
4444
"@tailwindcss/postcss": "^4.1.11",
4545
"@types/mdx": "^2.0.13",
46-
"@types/node": "24.1.0",
46+
"@types/node": "24.2.1",
4747
"@types/react": "19.1.9",
4848
"@types/react-dom": "19.1.7",
4949
"@zayne-labs/prettier-config": "0.9.9",

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@
3838
"devDependencies": {
3939
"@changesets/cli": "2.29.5",
4040
"@eslint-react/eslint-plugin": "^1.52.3",
41-
"@next/eslint-plugin-next": "^15.4.5",
42-
"@types/node": "^24.1.0",
41+
"@next/eslint-plugin-next": "^15.4.6",
42+
"@types/node": "^24.2.1",
4343
"@zayne-labs/eslint-config": "0.9.9",
4444
"@zayne-labs/prettier-config": "0.9.9",
45-
"eslint": "9.32.0",
46-
"eslint-plugin-better-tailwindcss": "^3.7.3",
45+
"eslint": "9.33.0",
46+
"eslint-plugin-better-tailwindcss": "^3.7.4",
4747
"eslint-plugin-react-hooks": "^5.2.0",
4848
"eslint-plugin-react-refresh": "^0.4.20",
4949
"husky": "9.1.7",
50-
"lint-staged": "16.1.2",
50+
"lint-staged": "16.1.5",
5151
"prettier": "3.6.2",
5252
"tailwindcss": "^4.1.11",
5353
"turbo": "^2.5.5",

packages/callapi-plugins/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"cross-env": "^10.0.0",
5353
"publint": "^0.3.12",
5454
"size-limit": "11.2.0",
55-
"tsdown": "^0.13.2",
55+
"tsdown": "^0.14.0",
5656
"typescript": "5.9.2",
5757
"vitest": "^3.2.4"
5858
},

packages/callapi/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"cross-env": "^10.0.0",
6262
"publint": "^0.3.12",
6363
"size-limit": "11.2.0",
64-
"tsdown": "^0.13.2",
64+
"tsdown": "^0.14.0",
6565
"typescript": "5.9.2",
6666
"vitest": "^3.2.4"
6767
},

packages/callapi/src/hooks.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -415,35 +415,43 @@ type HookRegistries = Required<{
415415
[Key in keyof Hooks]: Set<Hooks[Key]>;
416416
}>;
417417

418-
export const hookRegistries = {
419-
onError: new Set(),
420-
onRequest: new Set(),
421-
onRequestError: new Set(),
422-
onRequestStream: new Set(),
423-
onResponse: new Set(),
424-
onResponseError: new Set(),
425-
onResponseStream: new Set(),
426-
onRetry: new Set(),
427-
onSuccess: new Set(),
428-
onValidationError: new Set(),
429-
} satisfies HookRegistries;
418+
export const getHookRegistries = (): HookRegistries => {
419+
return {
420+
onError: new Set(),
421+
onRequest: new Set(),
422+
onRequestError: new Set(),
423+
onRequestStream: new Set(),
424+
onResponse: new Set(),
425+
onResponseError: new Set(),
426+
onResponseStream: new Set(),
427+
onRetry: new Set(),
428+
onSuccess: new Set(),
429+
onValidationError: new Set(),
430+
};
431+
};
430432

431433
export const composeAllHooks = (
432434
hooksArray: Array<AnyFunction | undefined>,
433435
hooksExecutionMode: CallApiExtraOptionsForHooks["hooksExecutionMode"]
434436
) => {
435437
const mergedHook = async (ctx: unknown) => {
436-
if (hooksExecutionMode === "sequential") {
437-
for (const hook of hooksArray) {
438-
// eslint-disable-next-line no-await-in-loop -- This is necessary in this case
439-
await hook?.(ctx);
438+
switch (hooksExecutionMode) {
439+
case "parallel": {
440+
await Promise.all(hooksArray.map((uniqueHook) => uniqueHook?.(ctx)));
441+
break;
440442
}
441443

442-
return;
443-
}
444+
case "sequential": {
445+
for (const hook of hooksArray) {
446+
// eslint-disable-next-line no-await-in-loop -- This is necessary in this case
447+
await hook?.(ctx);
448+
}
449+
break;
450+
}
444451

445-
if (hooksExecutionMode === "parallel") {
446-
await Promise.all(hooksArray.map((uniqueHook) => uniqueHook?.(ctx)));
452+
default: {
453+
hooksExecutionMode satisfies undefined;
454+
}
447455
}
448456
};
449457

packages/callapi/src/plugins.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { extraOptionDefaults } from "./constants/default-options";
22
import {
33
composeAllHooks,
4+
getHookRegistries,
45
type Hooks,
56
type HooksOrHooksArray,
6-
hookRegistries,
77
type PluginExtraOptions,
88
type RequestContext,
99
} from "./hooks";
@@ -91,10 +91,10 @@ export const getResolvedPlugins = (context: Pick<RequestContext, "baseConfig" |
9191
export const initializePlugins = async (context: PluginSetupContext) => {
9292
const { baseConfig, config, initURL, options, request } = context;
9393

94-
const clonedHookRegistries = structuredClone(hookRegistries);
94+
const hookRegistries = getHookRegistries();
9595

9696
const addMainHooks = () => {
97-
for (const key of Object.keys(clonedHookRegistries) as Array<keyof Hooks>) {
97+
for (const key of Object.keys(hookRegistries) as Array<keyof Hooks>) {
9898
const overriddenHook = options[key];
9999
const baseHook = baseConfig[key];
100100
const instanceHook = config[key];
@@ -105,17 +105,17 @@ export const initializePlugins = async (context: PluginSetupContext) => {
105105

106106
if (!mainHook) continue;
107107

108-
clonedHookRegistries[key].add(mainHook as never);
108+
hookRegistries[key].add(mainHook as never);
109109
}
110110
};
111111

112112
const addPluginHooks = (pluginHooks: Required<CallApiPlugin>["hooks"]) => {
113-
for (const key of Object.keys(clonedHookRegistries) as Array<keyof Hooks>) {
113+
for (const key of Object.keys(hookRegistries) as Array<keyof Hooks>) {
114114
const pluginHook = pluginHooks[key];
115115

116116
if (!pluginHook) continue;
117117

118-
clonedHookRegistries[key].add(pluginHook as never);
118+
hookRegistries[key].add(pluginHook as never);
119119
}
120120
};
121121

@@ -189,7 +189,7 @@ export const initializePlugins = async (context: PluginSetupContext) => {
189189

190190
const resolvedHooks: Hooks = {};
191191

192-
for (const [key, hookRegistry] of Object.entries(clonedHookRegistries)) {
192+
for (const [key, hookRegistry] of Object.entries(hookRegistries)) {
193193
if (hookRegistry.size === 0) continue;
194194

195195
// == Flatten the hook registry to remove any nested arrays, incase an array of hooks is passed to any of the hooks

packages/callapi/src/types/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ type SharedExtraOptions<
275275
meta?: GlobalMeta;
276276

277277
/**
278-
* Custom function to parse response strings into objects instead of the default response.json().
278+
* Custom function to parse response strings into actual value instead of the default response.json().
279279
*
280280
* Useful when you need custom parsing logic for specific response formats.
281281
*

0 commit comments

Comments
 (0)