Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,136 changes: 91 additions & 1,045 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"README.md"
],
"engines": {
"node": ">=18.0"
"node": ">=20.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that only Node 20 apps will be able to download the latest library version, right? We could also look at bumping the undici major version now (or removing that dependency all together)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets discuss this in Scrum today, should we bump the version?

},
"scripts": {
"build": "webpack --mode development",
Expand All @@ -41,6 +41,7 @@
"watch": "webpack --watch --mode development"
},
"dependencies": {
"@azure/functions-extensions-base": "0.2.0-preview",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should release a non-preview version of the base extension for GA

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good Catch. I will create a PR there.

"cookie": "^0.7.0",
"long": "^4.0.0",
"undici": "^5.29.0"
Expand All @@ -55,6 +56,7 @@
"@types/mocha": "^9.1.1",
"@types/node": "^18.0.0",
"@types/semver": "^7.3.9",
"@types/sinon": "^17.0.4",
"@typescript-eslint/eslint-plugin": "^5.12.1",
"@typescript-eslint/parser": "^5.12.1",
"chai": "^4.2.0",
Expand All @@ -65,8 +67,8 @@
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-webpack-plugin": "^3.2.0",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-webpack-plugin": "^3.2.0",
"fork-ts-checker-webpack-plugin": "^7.2.13",
"fs-extra": "^10.0.1",
"globby": "^11.0.0",
Expand All @@ -76,9 +78,10 @@
"mocha-multi-reporters": "^1.5.1",
"prettier": "^2.4.1",
"semver": "^7.3.5",
"sinon": "^20.0.0",
"ts-loader": "^9.3.1",
"ts-node": "^3.3.0",
"typescript": "^4.5.5",
"typescript": "^4.9.5",
"typescript4": "npm:typescript@~4.0.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
Expand Down
32 changes: 30 additions & 2 deletions src/converters/fromRpcTypedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

import { RpcTypedData } from '@azure/functions-core';
import { ResourceFactoryResolver } from '@azure/functions-extensions-base';
import { HttpRequest } from '../http/HttpRequest';
import { isDefined } from '../utils/nonNull';

Expand Down Expand Up @@ -30,8 +31,35 @@ export function fromRpcTypedData(data: RpcTypedData | null | undefined): unknown
return data.collectionDouble.double;
} else if (data.collectionSint64 && isDefined(data.collectionSint64.sint64)) {
return data.collectionSint64.sint64;
} else {
return undefined;
} else if (data.modelBindingData && isDefined(data.modelBindingData.content)) {
try {
const resourceFactoryResolver: ResourceFactoryResolver = ResourceFactoryResolver.getInstance();
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
return resourceFactoryResolver.createClient(data.modelBindingData.source, data.modelBindingData);
} catch (exception) {
throw new Error(
'Unable to create client. Please register the extensions library with your function app. ' +
`Error: ${exception instanceof Error ? exception.message : String(exception)}`
);
}
} else if (
data.collectionModelBindingData &&
isDefined(data.collectionModelBindingData.modelBindingData) &&
data.collectionModelBindingData.modelBindingData.length > 0
) {
try {
const resourceFactoryResolver: ResourceFactoryResolver = ResourceFactoryResolver.getInstance();
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
return resourceFactoryResolver.createClient(
data.collectionModelBindingData.modelBindingData[0]?.source,
data.collectionModelBindingData.modelBindingData
);
} catch (exception) {
throw new Error(
'Unable to create client. Please register the extensions library with your function app. ' +
`Error: ${exception instanceof Error ? exception.message : String(exception)}`
);
}
}
}

Expand Down
47 changes: 46 additions & 1 deletion src/converters/toCoreFunctionMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import * as coreTypes from '@azure/functions-core';
import { returnBindingKey } from '../constants';
import { AzFuncSystemError } from '../errors';
import { isTrigger } from '../utils/isTrigger';
import { workerSystemLog } from '../utils/workerSystemLog';
import { toRpcDuration } from './toRpcDuration';

export function toCoreFunctionMetadata(name: string, options: GenericFunctionOptions): coreTypes.FunctionMetadata {
const bindings: Record<string, coreTypes.RpcBindingInfo> = {};
const bindingNames: string[] = [];

const trigger = options.trigger;

bindings[trigger.name] = {
...trigger,
direction: 'in',
type: isTrigger(trigger.type) ? trigger.type : trigger.type + 'Trigger',
properties: addSdkBindingsFlag(options.trigger?.sdkBinding, name, trigger.type, trigger.name, false),
};
bindingNames.push(trigger.name);

Expand All @@ -25,6 +27,7 @@ export function toCoreFunctionMetadata(name: string, options: GenericFunctionOpt
bindings[input.name] = {
...input,
direction: 'in',
properties: addSdkBindingsFlag(input?.sdkBinding, name, input.type, input.name, true),
};
bindingNames.push(input.name);
}
Expand Down Expand Up @@ -74,3 +77,45 @@ export function toCoreFunctionMetadata(name: string, options: GenericFunctionOpt

return { name, bindings, retryOptions };
}

/**
* Adds the deferred binding flags to function bindings based on the binding configuration
* @param sdkBindingType Boolean indicating if this is an SDK binding
* @param functionName The name of the function for logging purposes
* @param triggerType The type of the trigger or binding
* @param bindingOrTriggerName The name of the trigger or binding
* @param isBinding Boolean indicating if this is a binding (vs a trigger)
* @returns Object with supportsDeferredBinding property set to 'true' or 'false'
*/
export function addSdkBindingsFlag(
sdkBindingType?: boolean | unknown,
functionName?: string,
triggerType?: string,
bindingOrTriggerName?: string,
isBinding?: boolean
): { [key: string]: string } {
// Ensure that trigger type is valid and supported
if (sdkBindingType !== undefined && sdkBindingType === true) {
const entityType = isBinding ? 'binding' : 'trigger';

// Create structured JSON log entry
const logData = {
operation: 'EnableDeferredBinding',
properties: {
functionName: functionName || 'unknown',
entityType: entityType,
triggerType: triggerType || 'unknown',
bindingOrTriggerName: bindingOrTriggerName || 'unknown',
supportsDeferredBinding: true,
},
message: `Enabled Deferred Binding of type '${triggerType || 'unknown'}' for function '${
functionName || 'unknown'
}'`,
};
// Log both the structured data
workerSystemLog('information', JSON.stringify(logData));
return { supportsDeferredBinding: 'true' };
}

return { supportsDeferredBinding: 'false' };
}
Loading
Loading