Skip to content

Commit eb6c17f

Browse files
committed
refactor: MethodDecoratorManager
1 parent d56c6b1 commit eb6c17f

File tree

8 files changed

+398
-123
lines changed

8 files changed

+398
-123
lines changed

packages/middleware/src/apiClientFactory/applyContextToApi.ts

Lines changed: 26 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
// @ts-check
2-
import { isExtensionEndpointHandler } from "../helpers";
3-
import { createExtendQuery } from "./createExtendQuery";
42
import {
53
AfterCallParams,
64
ApiMethods,
75
ApplyingContextHooks,
86
BeforeCallParams,
97
MiddlewareContext,
108
} from "../types";
11-
import { getLogger } from "../logger";
9+
import {
10+
ExtensionEndpointMethodDecorator,
11+
PurgeHookNameMethodDecorator,
12+
MethodDecoratorManager,
13+
MissingScopeMethodDecorator,
14+
OrchiestratedMethodDecorator,
15+
ScopeTypeMethodDecorator,
16+
} from "./methodDecorator";
1217

1318
const nopBefore = <ARGS>({ args }: BeforeCallParams<any, ARGS>): ARGS => args;
1419
const nopAfter = <RESPONSE>({
@@ -39,87 +44,27 @@ const applyContextToApi = <
3944
(prev, [callName, fn]) => ({
4045
...prev,
4146
[callName]: async (...args: Parameters<typeof fn>) => {
42-
const hasMetadataScope = checkMetadataScope(context);
43-
if (!hasMetadataScope) {
44-
const logger = getLogger(context.res);
45-
logger.warning(
46-
`Alokai's metadata object is missing in the context under 'res.locals.alokai'.
47-
This could indicate that the extension's scope or metadata has not been properly initialized.
48-
Without this metadata, certain custom API client functionalities may not work as expected,
49-
including tracking of extension-specific actions or data.
50-
Please ensure that the Alokai metadata object is correctly set up in 'res.locals.alokai' before proceeding with the request.
51-
52-
Steps to troubleshoot:
53-
1. Verify if content of res.locals hasn't been overwritten, instead of extended.
54-
2. If you're unsure, please consult Alokai's team for further assistance or review the source code implementation.
55-
56-
Call Name: ${callName}
57-
Function Name: ${fn.name || "Unnamed function"}`
58-
);
59-
}
60-
const extendQuery = createExtendQuery(context);
61-
let tmpIntegrationName = "";
62-
let tmpFnName = "";
63-
if (hasMetadataScope) {
64-
context.res.locals.alokai.metadata.scope.type = "requestHook";
65-
tmpIntegrationName =
66-
context.res.locals.alokai.metadata.scope.integrationName;
67-
context.res.locals.alokai.metadata.scope.integrationName =
68-
context.integrationKey;
69-
70-
tmpFnName = context.res.locals.alokai.metadata.scope.functionName;
71-
context.res.locals.alokai.metadata.scope.functionName = callName;
72-
}
73-
const transformedArgs = await hooks.before({ callName, args });
74-
const apiClientContext = { ...context, extendQuery };
75-
if (isExtensionEndpointHandler(fn)) {
76-
context.res.locals.alokai.metadata.scope.extensionName =
77-
fn._extensionName;
78-
}
79-
let tmp = {
80-
extensionName: null,
81-
functionName: null,
82-
};
83-
const isTmpSet = (tmp) => !!tmp.functionName; // as we never set fn name to nullish
84-
if (hasMetadataScope) {
85-
context.res.locals.alokai.metadata.scope.type = "endpoint";
86-
context.res.locals.alokai.metadata.scope.hookName = undefined;
87-
if (!(fn as any)._extensionName) {
88-
tmp = {
89-
extensionName:
90-
context.res.locals.alokai.metadata.scope.extensionName,
91-
functionName:
92-
context.res.locals.alokai.metadata.scope.functionName,
93-
};
94-
context.res.locals.alokai.metadata.scope.extensionName = undefined;
95-
context.res.locals.alokai.metadata.scope.functionName = callName;
96-
// console.log(`wywolam ${fn.name} lub ${callName}`, { ...tmp });
97-
}
98-
}
99-
const response = await fn(apiClientContext, ...transformedArgs);
100-
if (hasMetadataScope) {
101-
if (isTmpSet(tmp)) {
102-
context.res.locals.alokai.metadata.scope.extensionName =
103-
tmp.extensionName;
104-
context.res.locals.alokai.metadata.scope.functionName =
105-
tmp.functionName;
106-
}
107-
// console.log("co ustawiam?: ", { ...tmp });
108-
context.res.locals.alokai.metadata.scope.type = "requestHook";
109-
}
110-
const transformedResponse = await hooks.after({
47+
const methodDecoratorManager = new MethodDecoratorManager(
48+
context,
49+
hooks,
11150
callName,
112-
args,
113-
response,
114-
});
51+
fn
52+
);
53+
54+
const hasMetadataScope = checkMetadataScope(context);
55+
const decoratorsToAdd = hasMetadataScope
56+
? [
57+
new ScopeTypeMethodDecorator(context),
58+
new PurgeHookNameMethodDecorator(context),
59+
new ExtensionEndpointMethodDecorator(context, fn),
60+
new OrchiestratedMethodDecorator(context, callName, fn),
61+
]
62+
: [new MissingScopeMethodDecorator(context, callName, fn.name)];
63+
methodDecoratorManager.addDecorator(...decoratorsToAdd);
11564

116-
if (hasMetadataScope) {
117-
context.res.locals.alokai.metadata.scope.integrationName =
118-
tmpIntegrationName;
119-
context.res.locals.alokai.metadata.scope.functionName = tmpFnName;
120-
}
65+
const method = methodDecoratorManager.prepare<typeof args>();
12166

122-
return transformedResponse;
67+
return await method(args);
12368
},
12469
}),
12570
{} as any

packages/middleware/src/apiClientFactory/index.ts

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,9 @@ import {
1111
CreateApiClientFn,
1212
ExtensionHookWith,
1313
ExtensionWith,
14-
ExtensionEndpointHandler,
1514
} from "../types";
1615
import { applyContextToApi } from "./applyContextToApi";
17-
18-
/**
19-
* Function marking endpoint added or overwritten by extension's extendApiMethod hook
20-
* with information about source extension's name
21-
*/
22-
function markWithExtensionName(
23-
apiMethod: ExtensionEndpointHandler,
24-
extensionName: string
25-
) {
26-
apiMethod._extensionName = extensionName;
27-
return apiMethod;
28-
}
16+
import { markExtensionNameHelpers } from "./markExtensionNameHelpers";
2917

3018
const apiClientFactory = <
3119
ALL_SETTINGS extends ApiClientConfig,
@@ -92,7 +80,7 @@ const apiClientFactory = <
9280

9381
const loggerWithMetadata = injectMetadata(logger, () => ({
9482
scope: {
95-
integrationName: this.middleware?.integrationKey,
83+
integrationName: this.middleware?.integrationTag,
9684
type: "requestHook",
9785
hookName: "onCreate",
9886
},
@@ -150,10 +138,7 @@ const apiClientFactory = <
150138
},
151139
};
152140

153-
const context = {
154-
...settings,
155-
...(this?.middleware || {}),
156-
};
141+
const context = { ...settings, ...(this?.middleware || {}) };
157142

158143
const api = await resolveApi(factoryParams.api, settings);
159144

@@ -166,28 +151,20 @@ const apiClientFactory = <
166151
settings
167152
);
168153
if (extension.isNamespaced) {
169-
const markedExtendedApiMethods = Object.entries(
170-
extendedApiMethods
171-
).reduce((total, [name, fn]: [string, ExtensionEndpointHandler]) => {
172-
return {
173-
...total,
174-
[name]: markWithExtensionName(fn, extension.name),
175-
};
176-
}, {});
154+
const markedExtendedApiMethods = markExtensionNameHelpers.markApi(
155+
extendedApiMethods,
156+
extension.name
157+
);
177158

178159
namespacedExtensions[extension.name] = {
179160
...(namespacedExtensions?.[extension.name] ?? {}),
180161
...markedExtendedApiMethods,
181162
};
182163
} else {
183-
const markedExtendedApiMethods = Object.entries(
184-
extendedApiMethods
185-
).reduce((total, [name, fn]: [string, ExtensionEndpointHandler]) => {
186-
return {
187-
...total,
188-
[name]: markWithExtensionName(fn, extension.name),
189-
};
190-
}, {});
164+
const markedExtendedApiMethods = markExtensionNameHelpers.markApi(
165+
extendedApiMethods,
166+
extension.name
167+
);
191168
sharedExtensions = {
192169
...sharedExtensions,
193170
...markedExtendedApiMethods,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ExtensionEndpointHandler } from "../types";
2+
3+
/**
4+
* Set of helpers to faciliate working with _extensionName property
5+
* added on handlers added by extension's extendApiMethod hook.
6+
*/
7+
export const markExtensionNameHelpers = {
8+
/**
9+
* Function marking endpoint added or overwritten by extension's extendApiMethod hook
10+
* with information about source extension's name
11+
*/
12+
mark(apiMethod: ExtensionEndpointHandler, extensionName: string) {
13+
apiMethod._extensionName = extensionName;
14+
return apiMethod;
15+
},
16+
17+
markApi(
18+
api: Record<string, ExtensionEndpointHandler>,
19+
extensionName: string
20+
) {
21+
return Object.entries(api).reduce(
22+
(total, [name, fn]: [string, ExtensionEndpointHandler]) => {
23+
return {
24+
...total,
25+
[name]: markExtensionNameHelpers.mark(fn, extensionName),
26+
};
27+
},
28+
{}
29+
);
30+
},
31+
32+
has(obj: object): obj is ExtensionEndpointHandler {
33+
return "_extensionName" in obj;
34+
},
35+
36+
get(obj: object) {
37+
return (obj as ExtensionEndpointHandler)?._extensionName;
38+
},
39+
};

0 commit comments

Comments
 (0)