Skip to content

Commit 064cc49

Browse files
SDK Binding Support GA (#379)
1 parent 8d7c4af commit 064cc49

File tree

9 files changed

+911
-12
lines changed

9 files changed

+911
-12
lines changed

package-lock.json

Lines changed: 91 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"README.md"
2929
],
3030
"engines": {
31-
"node": ">=18.0"
31+
"node": ">=20.0"
3232
},
3333
"scripts": {
3434
"build": "webpack --mode development",
@@ -41,6 +41,7 @@
4141
"watch": "webpack --watch --mode development"
4242
},
4343
"dependencies": {
44+
"@azure/functions-extensions-base": "0.2.0",
4445
"cookie": "^0.7.0",
4546
"long": "^4.0.0",
4647
"undici": "^5.29.0"
@@ -55,6 +56,7 @@
5556
"@types/mocha": "^9.1.1",
5657
"@types/node": "^18.0.0",
5758
"@types/semver": "^7.3.9",
59+
"@types/sinon": "^17.0.4",
5860
"@typescript-eslint/eslint-plugin": "^5.12.1",
5961
"@typescript-eslint/parser": "^5.12.1",
6062
"chai": "^4.2.0",
@@ -65,8 +67,8 @@
6567
"eslint-plugin-header": "^3.1.1",
6668
"eslint-plugin-import": "^2.29.0",
6769
"eslint-plugin-prettier": "^4.0.0",
68-
"eslint-webpack-plugin": "^3.2.0",
6970
"eslint-plugin-simple-import-sort": "^10.0.0",
71+
"eslint-webpack-plugin": "^3.2.0",
7072
"fork-ts-checker-webpack-plugin": "^7.2.13",
7173
"fs-extra": "^10.0.1",
7274
"globby": "^11.0.0",
@@ -76,9 +78,10 @@
7678
"mocha-multi-reporters": "^1.5.1",
7779
"prettier": "^2.4.1",
7880
"semver": "^7.3.5",
81+
"sinon": "^20.0.0",
7982
"ts-loader": "^9.3.1",
8083
"ts-node": "^3.3.0",
81-
"typescript": "^4.5.5",
84+
"typescript": "^4.9.5",
8285
"typescript4": "npm:typescript@~4.0.0",
8386
"webpack": "^5.74.0",
8487
"webpack-cli": "^4.10.0"

src/converters/fromRpcTypedData.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
import { RpcTypedData } from '@azure/functions-core';
5+
import { ResourceFactoryResolver } from '@azure/functions-extensions-base';
56
import { HttpRequest } from '../http/HttpRequest';
67
import { isDefined } from '../utils/nonNull';
78

@@ -30,8 +31,35 @@ export function fromRpcTypedData(data: RpcTypedData | null | undefined): unknown
3031
return data.collectionDouble.double;
3132
} else if (data.collectionSint64 && isDefined(data.collectionSint64.sint64)) {
3233
return data.collectionSint64.sint64;
33-
} else {
34-
return undefined;
34+
} else if (data.modelBindingData && isDefined(data.modelBindingData.content)) {
35+
try {
36+
const resourceFactoryResolver: ResourceFactoryResolver = ResourceFactoryResolver.getInstance();
37+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
38+
return resourceFactoryResolver.createClient(data.modelBindingData.source, data.modelBindingData);
39+
} catch (exception) {
40+
throw new Error(
41+
'Unable to create client. Please register the extensions library with your function app. ' +
42+
`Error: ${exception instanceof Error ? exception.message : String(exception)}`
43+
);
44+
}
45+
} else if (
46+
data.collectionModelBindingData &&
47+
isDefined(data.collectionModelBindingData.modelBindingData) &&
48+
data.collectionModelBindingData.modelBindingData.length > 0
49+
) {
50+
try {
51+
const resourceFactoryResolver: ResourceFactoryResolver = ResourceFactoryResolver.getInstance();
52+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
53+
return resourceFactoryResolver.createClient(
54+
data.collectionModelBindingData.modelBindingData[0]?.source,
55+
data.collectionModelBindingData.modelBindingData
56+
);
57+
} catch (exception) {
58+
throw new Error(
59+
'Unable to create client. Please register the extensions library with your function app. ' +
60+
`Error: ${exception instanceof Error ? exception.message : String(exception)}`
61+
);
62+
}
3563
}
3664
}
3765

src/converters/toCoreFunctionMetadata.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ import * as coreTypes from '@azure/functions-core';
66
import { returnBindingKey } from '../constants';
77
import { AzFuncSystemError } from '../errors';
88
import { isTrigger } from '../utils/isTrigger';
9+
import { workerSystemLog } from '../utils/workerSystemLog';
910
import { toRpcDuration } from './toRpcDuration';
1011

1112
export function toCoreFunctionMetadata(name: string, options: GenericFunctionOptions): coreTypes.FunctionMetadata {
1213
const bindings: Record<string, coreTypes.RpcBindingInfo> = {};
1314
const bindingNames: string[] = [];
14-
1515
const trigger = options.trigger;
16+
1617
bindings[trigger.name] = {
1718
...trigger,
1819
direction: 'in',
1920
type: isTrigger(trigger.type) ? trigger.type : trigger.type + 'Trigger',
21+
properties: addSdkBindingsFlag(options.trigger?.sdkBinding, name, trigger.type, trigger.name, false),
2022
};
2123
bindingNames.push(trigger.name);
2224

@@ -25,6 +27,7 @@ export function toCoreFunctionMetadata(name: string, options: GenericFunctionOpt
2527
bindings[input.name] = {
2628
...input,
2729
direction: 'in',
30+
properties: addSdkBindingsFlag(input?.sdkBinding, name, input.type, input.name, true),
2831
};
2932
bindingNames.push(input.name);
3033
}
@@ -74,3 +77,45 @@ export function toCoreFunctionMetadata(name: string, options: GenericFunctionOpt
7477

7578
return { name, bindings, retryOptions };
7679
}
80+
81+
/**
82+
* Adds the deferred binding flags to function bindings based on the binding configuration
83+
* @param sdkBindingType Boolean indicating if this is an SDK binding
84+
* @param functionName The name of the function for logging purposes
85+
* @param triggerType The type of the trigger or binding
86+
* @param bindingOrTriggerName The name of the trigger or binding
87+
* @param isBinding Boolean indicating if this is a binding (vs a trigger)
88+
* @returns Object with supportsDeferredBinding property set to 'true' or 'false'
89+
*/
90+
export function addSdkBindingsFlag(
91+
sdkBindingType?: boolean | unknown,
92+
functionName?: string,
93+
triggerType?: string,
94+
bindingOrTriggerName?: string,
95+
isBinding?: boolean
96+
): { [key: string]: string } {
97+
// Ensure that trigger type is valid and supported
98+
if (sdkBindingType !== undefined && sdkBindingType === true) {
99+
const entityType = isBinding ? 'binding' : 'trigger';
100+
101+
// Create structured JSON log entry
102+
const logData = {
103+
operation: 'EnableDeferredBinding',
104+
properties: {
105+
functionName: functionName || 'unknown',
106+
entityType: entityType,
107+
triggerType: triggerType || 'unknown',
108+
bindingOrTriggerName: bindingOrTriggerName || 'unknown',
109+
supportsDeferredBinding: true,
110+
},
111+
message: `Enabled Deferred Binding of type '${triggerType || 'unknown'}' for function '${
112+
functionName || 'unknown'
113+
}'`,
114+
};
115+
// Log both the structured data
116+
workerSystemLog('information', JSON.stringify(logData));
117+
return { supportsDeferredBinding: 'true' };
118+
}
119+
120+
return { supportsDeferredBinding: 'false' };
121+
}

0 commit comments

Comments
 (0)