From bc099a48c22a2c7815808c88b08ed347283d65a4 Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Fri, 27 Mar 2026 10:56:33 +0800 Subject: [PATCH 1/9] nodejs sdk onboarding --- src/app.ts | 6 ++ src/input.ts | 9 ++ src/output.ts | 9 ++ src/trigger.ts | 9 ++ test/cosmosDBMongo.test.ts | 193 +++++++++++++++++++++++++++++++++++++ types/app.d.ts | 8 ++ types/cosmosDBMongo.d.ts | 187 +++++++++++++++++++++++++++++++++++ types/index.d.ts | 1 + types/input.d.ts | 6 ++ types/output.d.ts | 6 ++ types/trigger.d.ts | 6 ++ 11 files changed, 440 insertions(+) create mode 100644 test/cosmosDBMongo.test.ts create mode 100644 types/cosmosDBMongo.d.ts diff --git a/src/app.ts b/src/app.ts index 9659545..54b2995 100644 --- a/src/app.ts +++ b/src/app.ts @@ -3,6 +3,7 @@ import { CosmosDBFunctionOptions, + CosmosDBMongoFunctionOptions, EventGridFunctionOptions, EventHubFunctionOptions, FunctionTrigger, @@ -131,6 +132,11 @@ export function cosmosDB(name: string, options: CosmosDBFunctionOptions): void { generic(name, convertToGenericOptions(options, trigger.cosmosDB)); } +export function cosmosDBMongo(name: string, options: CosmosDBMongoFunctionOptions): void { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + generic(name, convertToGenericOptions(options, trigger.cosmosDBMongo)); +} + export function warmup(name: string, options: WarmupFunctionOptions): void { generic(name, convertToGenericOptions(options, trigger.warmup)); } diff --git a/src/input.ts b/src/input.ts index 60e3713..ad19a90 100644 --- a/src/input.ts +++ b/src/input.ts @@ -4,6 +4,8 @@ import { CosmosDBInput, CosmosDBInputOptions, + CosmosDBMongoInput, + CosmosDBMongoInputOptions, FunctionInput, GenericInputOptions, MySqlInput, @@ -42,6 +44,13 @@ export function cosmosDB(options: CosmosDBInputOptions): CosmosDBInput { }); } +export function cosmosDBMongo(options: CosmosDBMongoInputOptions): CosmosDBMongoInput { + return addInputBindingName({ + ...options, + type: 'cosmosDBMongo', + }); +} + export function sql(options: SqlInputOptions): SqlInput { return addInputBindingName({ ...options, diff --git a/src/output.ts b/src/output.ts index 0f0a781..50c926a 100644 --- a/src/output.ts +++ b/src/output.ts @@ -2,6 +2,8 @@ // Licensed under the MIT License. import { + CosmosDBMongoOutput, + CosmosDBMongoOutputOptions, CosmosDBOutput, CosmosDBOutputOptions, EventGridOutput, @@ -94,6 +96,13 @@ export function cosmosDB(options: CosmosDBOutputOptions): CosmosDBOutput { }); } +export function cosmosDBMongo(options: CosmosDBMongoOutputOptions): CosmosDBMongoOutput { + return addOutputBindingName({ + ...options, + type: 'cosmosDBMongo', + }); +} + export function sql(options: SqlOutputOptions): SqlOutput { return addOutputBindingName({ ...options, diff --git a/src/trigger.ts b/src/trigger.ts index 90103e5..80137d6 100644 --- a/src/trigger.ts +++ b/src/trigger.ts @@ -2,6 +2,8 @@ // Licensed under the MIT License. import { + CosmosDBMongoTrigger, + CosmosDBMongoTriggerOptions, CosmosDBTrigger, CosmosDBTriggerOptions, EventGridTrigger, @@ -104,6 +106,13 @@ export function cosmosDB(options: CosmosDBTriggerOptions): CosmosDBTrigger { }); } +export function cosmosDBMongo(options: CosmosDBMongoTriggerOptions): CosmosDBMongoTrigger { + return addTriggerBindingName({ + ...options, + type: 'cosmosDBMongoTrigger', + }); +} + export function warmup(options: WarmupTriggerOptions): WarmupTrigger { return addTriggerBindingName({ ...options, diff --git a/test/cosmosDBMongo.test.ts b/test/cosmosDBMongo.test.ts new file mode 100644 index 0000000..5fca9d4 --- /dev/null +++ b/test/cosmosDBMongo.test.ts @@ -0,0 +1,193 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import 'mocha'; +import { expect } from 'chai'; +import { input, output, trigger } from '../src'; +import { toCoreFunctionMetadata } from '../src/converters/toCoreFunctionMetadata'; +import { InvocationContext } from '../types'; + +describe('cosmosDBMongo bindings', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const handler = (_doc: unknown, _context: InvocationContext) => {}; + + const minimalTriggerOptions = { + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'MyDatabase', + collectionName: 'MyCollection', + }; + + // ------------------------------------------------------------------------- + // trigger + // ------------------------------------------------------------------------- + + describe('trigger.cosmosDBMongo', () => { + it('produces correct type string', () => { + const trig = trigger.cosmosDBMongo(minimalTriggerOptions); + expect(trig.type).to.equal('cosmosDBMongoTrigger'); + }); + + it('copies all trigger options onto the binding object', () => { + const trig = trigger.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + createIfNotExists: true, + triggerLevel: 'Database', + leaseDatabaseName: 'leaseDb', + leaseCollectionName: 'leases', + leaseConnectionStringSetting: 'LeaseConn', + tenantId: 'tenant-abc', + managedIdentityClientId: 'mi-abc', + leaseTenantId: 'lease-tenant', + leaseManagedIdentityClientId: 'lease-mi', + }); + expect(trig.connectionStringSetting).to.equal('CosmosDBMongo'); + expect(trig.databaseName).to.equal('db'); + expect(trig.collectionName).to.equal('coll'); + expect(trig.createIfNotExists).to.equal(true); + expect(trig.triggerLevel).to.equal('Database'); + expect(trig.leaseDatabaseName).to.equal('leaseDb'); + expect(trig.leaseCollectionName).to.equal('leases'); + expect(trig.leaseConnectionStringSetting).to.equal('LeaseConn'); + expect(trig.tenantId).to.equal('tenant-abc'); + expect(trig.managedIdentityClientId).to.equal('mi-abc'); + expect(trig.leaseTenantId).to.equal('lease-tenant'); + expect(trig.leaseManagedIdentityClientId).to.equal('lease-mi'); + }); + + it('generates a deterministic binding name with Trigger suffix', () => { + const trig1 = trigger.cosmosDBMongo(minimalTriggerOptions); + const trig2 = trigger.cosmosDBMongo(minimalTriggerOptions); + expect(trig1.name).to.equal(trig2.name); + expect(trig1.name).to.include('cosmosDBMongoTrigger'); + }); + + it('sets direction = in via toCoreFunctionMetadata', () => { + const result = toCoreFunctionMetadata('mongoTrigFunc', { + handler, + trigger: trigger.cosmosDBMongo(minimalTriggerOptions), + }); + const bindingValues = Object.values(result.bindings) as Record[]; + const trig = bindingValues.find((b) => b['type'] === 'cosmosDBMongoTrigger'); + expect(trig).to.exist; + expect(trig!['direction']).to.equal('in'); + }); + }); + + // ------------------------------------------------------------------------- + // input + // ------------------------------------------------------------------------- + + describe('input.cosmosDBMongo', () => { + it('produces correct type string', () => { + const inp = input.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + }); + expect(inp.type).to.equal('cosmosDBMongo'); + }); + + it('copies all input options onto the binding object', () => { + const inp = input.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + queryString: '{"status": "active"}', + createIfNotExists: false, + tenantId: 'tenant-xyz', + managedIdentityClientId: 'mi-xyz', + }); + expect(inp.connectionStringSetting).to.equal('CosmosDBMongo'); + expect(inp.databaseName).to.equal('db'); + expect(inp.collectionName).to.equal('coll'); + expect(inp.queryString).to.equal('{"status": "active"}'); + expect(inp.createIfNotExists).to.equal(false); + expect(inp.tenantId).to.equal('tenant-xyz'); + expect(inp.managedIdentityClientId).to.equal('mi-xyz'); + }); + + it('generates a deterministic binding name with Input suffix', () => { + const inp = input.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + }); + expect(inp.name).to.include('Input'); + }); + + it('sets direction = in via toCoreFunctionMetadata extra input', () => { + const inp = input.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + }); + const result = toCoreFunctionMetadata('mongoInputFunc', { + handler: () => {}, + trigger: trigger.cosmosDBMongo(minimalTriggerOptions), + extraInputs: [inp], + }); + const bindingValues = Object.values(result.bindings) as Record[]; + const inputBinding = bindingValues.find((b) => b['type'] === 'cosmosDBMongo' && b['direction'] === 'in'); + expect(inputBinding).to.exist; + }); + }); + + // ------------------------------------------------------------------------- + // output + // ------------------------------------------------------------------------- + + describe('output.cosmosDBMongo', () => { + it('produces correct type string', () => { + const out = output.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + }); + expect(out.type).to.equal('cosmosDBMongo'); + }); + + it('copies all output options onto the binding object', () => { + const out = output.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + createIfNotExists: true, + tenantId: 'tenant-out', + managedIdentityClientId: 'mi-out', + }); + expect(out.connectionStringSetting).to.equal('CosmosDBMongo'); + expect(out.databaseName).to.equal('db'); + expect(out.collectionName).to.equal('coll'); + expect(out.createIfNotExists).to.equal(true); + expect(out.tenantId).to.equal('tenant-out'); + expect(out.managedIdentityClientId).to.equal('mi-out'); + }); + + it('generates a deterministic binding name with Output suffix', () => { + const out = output.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + }); + expect(out.name).to.include('Output'); + }); + + it('sets direction = out via toCoreFunctionMetadata extra output', () => { + const out = output.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'db', + collectionName: 'coll', + }); + const result = toCoreFunctionMetadata('mongoOutputFunc', { + handler: () => {}, + trigger: trigger.cosmosDBMongo(minimalTriggerOptions), + extraOutputs: [out], + }); + const bindingValues = Object.values(result.bindings) as Record[]; + const outputBinding = bindingValues.find((b) => b['type'] === 'cosmosDBMongo' && b['direction'] === 'out'); + expect(outputBinding).to.exist; + }); + }); +}); diff --git a/types/app.d.ts b/types/app.d.ts index a736187..461a0f2 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { CosmosDBFunctionOptions } from './cosmosDB'; +import { CosmosDBMongoFunctionOptions } from './cosmosDBMongo'; import { EventGridEvent, EventGridFunctionOptions } from './eventGrid'; import { EventHubFunctionOptions } from './eventHub'; import { GenericFunctionOptions } from './generic'; @@ -157,6 +158,13 @@ export function eventGrid(name: string, options: EventGridFu */ export function cosmosDB(name: string, options: CosmosDBFunctionOptions): void; +/** + * Registers an Azure Cosmos DB for MongoDB function in your app that will be triggered whenever change stream events occur + * @param name The name of the function. The name must be unique within your app and will mostly be used for your own tracking purposes + * @param options Configuration options describing the inputs, outputs, and handler for this function + */ +export function cosmosDBMongo(name: string, options: CosmosDBMongoFunctionOptions): void; + /** * Registers a function in your app that will be triggered when an instance is added to scale a running function app. * The warmup trigger is only called during scale-out operations, not during restarts or other non-scale startups. diff --git a/types/cosmosDBMongo.d.ts b/types/cosmosDBMongo.d.ts new file mode 100644 index 0000000..917833a --- /dev/null +++ b/types/cosmosDBMongo.d.ts @@ -0,0 +1,187 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { FunctionInput, FunctionOptions, FunctionOutput, FunctionResult, FunctionTrigger, RetryOptions } from './index'; +import { InvocationContext } from './InvocationContext'; + +/** + * Handler type for CosmosDB Mongo trigger functions. + * The trigger delivers the change stream document serialized as JSON. + */ +export type CosmosDBMongoHandler = (documents: T, context: InvocationContext) => FunctionResult; + +/** + * Options for registering a CosmosDB Mongo-triggered function via `app.cosmosDBMongo()`. + */ +export interface CosmosDBMongoFunctionOptions extends CosmosDBMongoTriggerOptions, Partial { + handler: CosmosDBMongoHandler; + + trigger?: CosmosDBMongoTrigger; + + /** + * An optional retry policy to rerun a failed execution until either successful completion occurs + * or the maximum number of retries is reached. + * Learn more [here](https://learn.microsoft.com/azure/azure-functions/functions-bindings-error-pages) + */ + retry?: RetryOptions; +} + +/** + * Options for configuring a CosmosDB Mongo trigger binding. + */ +export interface CosmosDBMongoTriggerOptions { + /** + * An app setting (or environment variable) with the MongoDB connection string. + * Defaults to "CosmosDBMongo" if not specified. + */ + connectionStringSetting: string; + + /** + * The name of the database being monitored. + */ + databaseName: string; + + /** + * The name of the collection being monitored. + * Optional when triggerLevel is "Database" or "Cluster". + */ + collectionName?: string; + + /** + * Whether to create the collection and lease collection if they do not exist. + * Default is false. + */ + createIfNotExists?: boolean; + + /** + * The level at which the trigger monitors for changes. + * Accepted values: "Collection" | "Database" | "Cluster". + * Default is "Collection". + */ + triggerLevel?: 'Collection' | 'Database' | 'Cluster'; + + /** + * The name of the database that holds the lease collection. + * Defaults to the monitored database name. + */ + leaseDatabaseName?: string; + + /** + * The name of the collection used to store leases. + * Defaults to "leases". + */ + leaseCollectionName?: string; + + /** + * An app setting name for the connection string of the lease account. + * If not set, uses the monitored account connection string. + */ + leaseConnectionStringSetting?: string; + + /** + * The Azure AD tenant ID used for managed identity authentication on the monitored account. + */ + tenantId?: string; + + /** + * The managed identity client ID for the monitored account. + * Used for user-assigned managed identity authentication. + */ + managedIdentityClientId?: string; + + /** + * The Azure AD tenant ID used for managed identity authentication on the lease account. + */ + leaseTenantId?: string; + + /** + * The managed identity client ID for the lease account. + */ + leaseManagedIdentityClientId?: string; +} + +export type CosmosDBMongoTrigger = FunctionTrigger & CosmosDBMongoTriggerOptions; + +/** + * Options for configuring a CosmosDB Mongo input binding. + */ +export interface CosmosDBMongoInputOptions { + /** + * An app setting (or environment variable) with the MongoDB connection string. + * Defaults to "CosmosDBMongo" if not specified. + */ + connectionStringSetting: string; + + /** + * The name of the database to read from. + */ + databaseName: string; + + /** + * The name of the collection to read from. + */ + collectionName: string; + + /** + * An optional MongoDB filter document as a JSON string. + * Supports binding expressions, e.g. {"id": "{Query.id}"}. + */ + queryString?: string; + + /** + * Whether to create the collection if it does not exist. + * Default is false. + */ + createIfNotExists?: boolean; + + /** + * The Azure AD tenant ID used for managed identity authentication. + */ + tenantId?: string; + + /** + * The managed identity client ID for user-assigned managed identity authentication. + */ + managedIdentityClientId?: string; +} + +export type CosmosDBMongoInput = FunctionInput & CosmosDBMongoInputOptions; + +/** + * Options for configuring a CosmosDB Mongo output binding. + */ +export interface CosmosDBMongoOutputOptions { + /** + * An app setting (or environment variable) with the MongoDB connection string. + * Defaults to "CosmosDBMongo" if not specified. + */ + connectionStringSetting: string; + + /** + * The name of the database to write to. + */ + databaseName: string; + + /** + * The name of the collection to write to. + */ + collectionName: string; + + /** + * Whether to create the collection if it does not exist. + * Default is false. + */ + createIfNotExists?: boolean; + + /** + * The Azure AD tenant ID used for managed identity authentication. + */ + tenantId?: string; + + /** + * The managed identity client ID for user-assigned managed identity authentication. + */ + managedIdentityClientId?: string; +} + +export type CosmosDBMongoOutput = FunctionOutput & CosmosDBMongoOutputOptions; diff --git a/types/index.d.ts b/types/index.d.ts index b45bb76..7897c25 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -7,6 +7,7 @@ export * as app from './app'; export * from './cosmosDB'; export * from './cosmosDB.v3'; export * from './cosmosDB.v4'; +export * from './cosmosDBMongo'; export * from './eventGrid'; export * from './eventHub'; export * from './generic'; diff --git a/types/input.d.ts b/types/input.d.ts index b264405..53a4be7 100644 --- a/types/input.d.ts +++ b/types/input.d.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { CosmosDBInput, CosmosDBInputOptions } from './cosmosDB'; +import { CosmosDBMongoInput, CosmosDBMongoInputOptions } from './cosmosDBMongo'; import { GenericInputOptions } from './generic'; import { FunctionInput } from './index'; import { MySqlInput, MySqlInputOptions } from './mySql'; @@ -30,6 +31,11 @@ export function table(options: TableInputOptions): TableInput; */ export function cosmosDB(options: CosmosDBInputOptions): CosmosDBInput; +/** + * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-azure-cosmosdb-mongo-input?pivots=programming-language-javascript) + */ +export function cosmosDBMongo(options: CosmosDBMongoInputOptions): CosmosDBMongoInput; + /** * [Link to docs and examples](https://docs.microsoft.com/azure/azure-functions/functions-bindings-azure-sql-input?pivots=programming-language-javascript) */ diff --git a/types/output.d.ts b/types/output.d.ts index e9e08d9..2084c11 100644 --- a/types/output.d.ts +++ b/types/output.d.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { CosmosDBOutput, CosmosDBOutputOptions } from './cosmosDB'; +import { CosmosDBMongoOutput, CosmosDBMongoOutputOptions } from './cosmosDBMongo'; import { EventGridOutput, EventGridOutputOptions } from './eventGrid'; import { EventHubOutput, EventHubOutputOptions } from './eventHub'; import { GenericOutputOptions } from './generic'; @@ -64,6 +65,11 @@ export function eventGrid(options: EventGridOutputOptions): EventGridOutput; */ export function cosmosDB(options: CosmosDBOutputOptions): CosmosDBOutput; +/** + * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-azure-cosmosdb-mongo-output?pivots=programming-language-javascript) + */ +export function cosmosDBMongo(options: CosmosDBMongoOutputOptions): CosmosDBMongoOutput; + /** * [Link to docs and examples](https://docs.microsoft.com/azure/azure-functions/functions-bindings-azure-sql-output?pivots=programming-language-javascript) */ diff --git a/types/trigger.d.ts b/types/trigger.d.ts index c91a958..a6dee6f 100644 --- a/types/trigger.d.ts +++ b/types/trigger.d.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { CosmosDBTrigger, CosmosDBTriggerOptions } from './cosmosDB'; +import { CosmosDBMongoTrigger, CosmosDBMongoTriggerOptions } from './cosmosDBMongo'; import { EventGridTrigger, EventGridTriggerOptions } from './eventGrid'; import { EventHubTrigger, EventHubTriggerOptions } from './eventHub'; import { GenericTriggerOptions } from './generic'; @@ -72,6 +73,11 @@ export function eventGrid(options: EventGridTriggerOptions): EventGridTrigger; */ export function cosmosDB(options: CosmosDBTriggerOptions): CosmosDBTrigger; +/** + * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-azure-cosmosdb-mongo-trigger?pivots=programming-language-javascript) + */ +export function cosmosDBMongo(options: CosmosDBMongoTriggerOptions): CosmosDBMongoTrigger; + /** * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-warmup?tabs=isolated-process&pivots=programming-language-javascript) */ From 7d03741b2945d651c4366238f9148060615aaf12 Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Fri, 27 Mar 2026 11:14:29 +0800 Subject: [PATCH 2/9] document link place holder --- types/input.d.ts | 2 +- types/output.d.ts | 2 +- types/trigger.d.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/types/input.d.ts b/types/input.d.ts index 53a4be7..0769a7e 100644 --- a/types/input.d.ts +++ b/types/input.d.ts @@ -32,7 +32,7 @@ export function table(options: TableInputOptions): TableInput; export function cosmosDB(options: CosmosDBInputOptions): CosmosDBInput; /** - * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-azure-cosmosdb-mongo-input?pivots=programming-language-javascript) + * [Link to docs and examples](tdb, will update later) */ export function cosmosDBMongo(options: CosmosDBMongoInputOptions): CosmosDBMongoInput; diff --git a/types/output.d.ts b/types/output.d.ts index 2084c11..0abccc1 100644 --- a/types/output.d.ts +++ b/types/output.d.ts @@ -66,7 +66,7 @@ export function eventGrid(options: EventGridOutputOptions): EventGridOutput; export function cosmosDB(options: CosmosDBOutputOptions): CosmosDBOutput; /** - * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-azure-cosmosdb-mongo-output?pivots=programming-language-javascript) + * [Link to docs and examples](tdb, will update later) */ export function cosmosDBMongo(options: CosmosDBMongoOutputOptions): CosmosDBMongoOutput; diff --git a/types/trigger.d.ts b/types/trigger.d.ts index a6dee6f..7d0e28b 100644 --- a/types/trigger.d.ts +++ b/types/trigger.d.ts @@ -74,7 +74,7 @@ export function eventGrid(options: EventGridTriggerOptions): EventGridTrigger; export function cosmosDB(options: CosmosDBTriggerOptions): CosmosDBTrigger; /** - * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-azure-cosmosdb-mongo-trigger?pivots=programming-language-javascript) + * [Link to docs and examples](tdb, will update later) */ export function cosmosDBMongo(options: CosmosDBMongoTriggerOptions): CosmosDBMongoTrigger; From 47cd9ecfe8258af4ad4988fde3e74118469a867b Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Mon, 20 Apr 2026 23:18:39 +0800 Subject: [PATCH 3/9] update with new version of nuget package --- sample/cosmosDBMongo/extensions.csproj | 11 +++ sample/cosmosDBMongo/host.json | 11 +++ sample/cosmosDBMongo/local.settings.json | 8 ++ sample/cosmosDBMongo/nuget.config | 7 ++ sample/cosmosDBMongo/package-lock.json | 87 +++++++++++++++++++ sample/cosmosDBMongo/package.json | 18 ++++ .../src/functions/httpGetDocuments.ts | 21 +++++ .../src/functions/httpWriteDocument.ts | 24 +++++ .../src/functions/mongoTrigger.ts | 12 +++ sample/cosmosDBMongo/tsconfig.json | 13 +++ 10 files changed, 212 insertions(+) create mode 100644 sample/cosmosDBMongo/extensions.csproj create mode 100644 sample/cosmosDBMongo/host.json create mode 100644 sample/cosmosDBMongo/local.settings.json create mode 100644 sample/cosmosDBMongo/nuget.config create mode 100644 sample/cosmosDBMongo/package-lock.json create mode 100644 sample/cosmosDBMongo/package.json create mode 100644 sample/cosmosDBMongo/src/functions/httpGetDocuments.ts create mode 100644 sample/cosmosDBMongo/src/functions/httpWriteDocument.ts create mode 100644 sample/cosmosDBMongo/src/functions/mongoTrigger.ts create mode 100644 sample/cosmosDBMongo/tsconfig.json diff --git a/sample/cosmosDBMongo/extensions.csproj b/sample/cosmosDBMongo/extensions.csproj new file mode 100644 index 0000000..ee92e28 --- /dev/null +++ b/sample/cosmosDBMongo/extensions.csproj @@ -0,0 +1,11 @@ + + + net6.0 + + ** + + + + + + \ No newline at end of file diff --git a/sample/cosmosDBMongo/host.json b/sample/cosmosDBMongo/host.json new file mode 100644 index 0000000..95b6932 --- /dev/null +++ b/sample/cosmosDBMongo/host.json @@ -0,0 +1,11 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + } +} diff --git a/sample/cosmosDBMongo/local.settings.json b/sample/cosmosDBMongo/local.settings.json new file mode 100644 index 0000000..5732777 --- /dev/null +++ b/sample/cosmosDBMongo/local.settings.json @@ -0,0 +1,8 @@ +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "UseDevelopmentStorage=true", + "FUNCTIONS_WORKER_RUNTIME": "node", + "CosmosDBMongo": "YOUR_CONNECTION_STRING_HERE" + } +} diff --git a/sample/cosmosDBMongo/nuget.config b/sample/cosmosDBMongo/nuget.config new file mode 100644 index 0000000..765346e --- /dev/null +++ b/sample/cosmosDBMongo/nuget.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/sample/cosmosDBMongo/package-lock.json b/sample/cosmosDBMongo/package-lock.json new file mode 100644 index 0000000..626f105 --- /dev/null +++ b/sample/cosmosDBMongo/package-lock.json @@ -0,0 +1,87 @@ +{ + "name": "cosmosdb-mongo-sample", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cosmosdb-mongo-sample", + "version": "1.0.0", + "dependencies": { + "@azure/functions": "file:../../" + }, + "devDependencies": { + "typescript": "^5.0.0" + } + }, + "../..": { + "version": "4.12.0", + "license": "MIT", + "dependencies": { + "@azure/functions-extensions-base": "0.2.0", + "cookie": "^0.7.0" + }, + "devDependencies": { + "@types/chai": "^4.2.22", + "@types/chai-as-promised": "^7.1.5", + "@types/cookie": "^0.6.0", + "@types/fs-extra": "^9.0.13", + "@types/long": "^4.0.2", + "@types/minimist": "^1.2.2", + "@types/mocha": "^9.1.1", + "@types/node": "^20.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", + "chai-as-promised": "^7.1.1", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-deprecation": "^1.3.2", + "eslint-plugin-header": "^3.1.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-prettier": "^4.0.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", + "long": "^4.0.0", + "minimist": "^1.2.6", + "mocha": "^11.1.0", + "mocha-junit-reporter": "^2.0.2", + "mocha-multi-reporters": "^1.5.1", + "prettier": "^2.4.1", + "semver": "^7.3.5", + "sinon": "^20.0.0", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "typescript": "~5.0.0", + "typescript4": "npm:typescript@~4.0.0", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@azure/functions": { + "resolved": "../..", + "link": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/sample/cosmosDBMongo/package.json b/sample/cosmosDBMongo/package.json new file mode 100644 index 0000000..88a19ef --- /dev/null +++ b/sample/cosmosDBMongo/package.json @@ -0,0 +1,18 @@ +{ + "name": "cosmosdb-mongo-sample", + "version": "1.0.0", + "private": true, + "main": "dist/src/functions/*.js", + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "prestart": "npm run build", + "start": "func start" + }, + "dependencies": { + "@azure/functions": "^4.12.0" + }, + "devDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts b/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts new file mode 100644 index 0000000..f82af5a --- /dev/null +++ b/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts @@ -0,0 +1,21 @@ +import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; + +const cosmosInput = input.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'SampleDB', + collectionName: 'Items', +}); + +app.http('httpGetDocuments', { + methods: ['GET'], + authLevel: 'anonymous', + extraInputs: [cosmosInput], + handler: async (request: HttpRequest, context: InvocationContext): Promise => { + const documents = context.extraInputs.get(cosmosInput); + context.log('Read documents from CosmosDB Mongo:', JSON.stringify(documents)); + + return { + jsonBody: documents, + }; + }, +}); diff --git a/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts b/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts new file mode 100644 index 0000000..6cc2816 --- /dev/null +++ b/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts @@ -0,0 +1,24 @@ +import { app, HttpRequest, HttpResponseInit, output, InvocationContext } from '@azure/functions'; + +const cosmosOutput = output.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'SampleDB', + collectionName: 'Items', + createIfNotExists: true, +}); + +app.http('httpWriteDocument', { + methods: ['POST'], + authLevel: 'anonymous', + extraOutputs: [cosmosOutput], + handler: async (request: HttpRequest, context: InvocationContext): Promise => { + const body = await request.json(); + context.log('Writing document to CosmosDB Mongo:', JSON.stringify(body)); + context.extraOutputs.set(cosmosOutput, body); + + return { + status: 201, + jsonBody: { message: 'Document written successfully', document: body }, + }; + }, +}); diff --git a/sample/cosmosDBMongo/src/functions/mongoTrigger.ts b/sample/cosmosDBMongo/src/functions/mongoTrigger.ts new file mode 100644 index 0000000..0b29894 --- /dev/null +++ b/sample/cosmosDBMongo/src/functions/mongoTrigger.ts @@ -0,0 +1,12 @@ +import { app, InvocationContext } from '@azure/functions'; + +app.cosmosDBMongo('mongoTrigger', { + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'SampleDB', + collectionName: 'Items', + createIfNotExists: true, + handler: (documents: unknown, context: InvocationContext) => { + context.log('CosmosDB Mongo trigger fired'); + context.log('Changed documents:', JSON.stringify(documents, null, 2)); + }, +}); diff --git a/sample/cosmosDBMongo/tsconfig.json b/sample/cosmosDBMongo/tsconfig.json new file mode 100644 index 0000000..3580085 --- /dev/null +++ b/sample/cosmosDBMongo/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "outDir": "dist", + "rootDir": ".", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts"] +} From cc5b8f57fdd7c8058044e64b1546b2c792a1a853 Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Mon, 20 Apr 2026 23:45:29 +0800 Subject: [PATCH 4/9] resolve lint error --- .../src/functions/httpGetDocuments.ts | 45 ++++++++-------- .../src/functions/httpWriteDocument.ts | 51 ++++++++++--------- .../src/functions/mongoTrigger.ts | 27 +++++----- test/cosmosDBMongo.test.ts | 1 + types/cosmosDBMongo.d.ts | 4 +- 5 files changed, 70 insertions(+), 58 deletions(-) diff --git a/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts b/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts index f82af5a..d7b602e 100644 --- a/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts +++ b/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts @@ -1,21 +1,24 @@ -import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; - -const cosmosInput = input.cosmosDBMongo({ - connectionStringSetting: 'CosmosDBMongo', - databaseName: 'SampleDB', - collectionName: 'Items', -}); - -app.http('httpGetDocuments', { - methods: ['GET'], - authLevel: 'anonymous', - extraInputs: [cosmosInput], - handler: async (request: HttpRequest, context: InvocationContext): Promise => { - const documents = context.extraInputs.get(cosmosInput); - context.log('Read documents from CosmosDB Mongo:', JSON.stringify(documents)); - - return { - jsonBody: documents, - }; - }, -}); +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; + +const cosmosInput = input.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'SampleDB', + collectionName: 'Items', +}); + +app.http('httpGetDocuments', { + methods: ['GET'], + authLevel: 'anonymous', + extraInputs: [cosmosInput], + handler: (request: HttpRequest, context: InvocationContext): HttpResponseInit => { + const documents = context.extraInputs.get(cosmosInput); + context.log('Read documents from CosmosDB Mongo:', JSON.stringify(documents)); + + return { + jsonBody: documents, + }; + }, +}); diff --git a/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts b/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts index 6cc2816..036ff1c 100644 --- a/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts +++ b/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts @@ -1,24 +1,27 @@ -import { app, HttpRequest, HttpResponseInit, output, InvocationContext } from '@azure/functions'; - -const cosmosOutput = output.cosmosDBMongo({ - connectionStringSetting: 'CosmosDBMongo', - databaseName: 'SampleDB', - collectionName: 'Items', - createIfNotExists: true, -}); - -app.http('httpWriteDocument', { - methods: ['POST'], - authLevel: 'anonymous', - extraOutputs: [cosmosOutput], - handler: async (request: HttpRequest, context: InvocationContext): Promise => { - const body = await request.json(); - context.log('Writing document to CosmosDB Mongo:', JSON.stringify(body)); - context.extraOutputs.set(cosmosOutput, body); - - return { - status: 201, - jsonBody: { message: 'Document written successfully', document: body }, - }; - }, -}); +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; + +const cosmosOutput = output.cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'SampleDB', + collectionName: 'Items', + createIfNotExists: true, +}); + +app.http('httpWriteDocument', { + methods: ['POST'], + authLevel: 'anonymous', + extraOutputs: [cosmosOutput], + handler: async (request: HttpRequest, context: InvocationContext): Promise => { + const body = await request.json(); + context.log('Writing document to CosmosDB Mongo:', JSON.stringify(body)); + context.extraOutputs.set(cosmosOutput, body); + + return { + status: 201, + jsonBody: { message: 'Document written successfully', document: body }, + }; + }, +}); diff --git a/sample/cosmosDBMongo/src/functions/mongoTrigger.ts b/sample/cosmosDBMongo/src/functions/mongoTrigger.ts index 0b29894..f5e70d4 100644 --- a/sample/cosmosDBMongo/src/functions/mongoTrigger.ts +++ b/sample/cosmosDBMongo/src/functions/mongoTrigger.ts @@ -1,12 +1,15 @@ -import { app, InvocationContext } from '@azure/functions'; - -app.cosmosDBMongo('mongoTrigger', { - connectionStringSetting: 'CosmosDBMongo', - databaseName: 'SampleDB', - collectionName: 'Items', - createIfNotExists: true, - handler: (documents: unknown, context: InvocationContext) => { - context.log('CosmosDB Mongo trigger fired'); - context.log('Changed documents:', JSON.stringify(documents, null, 2)); - }, -}); +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { app, InvocationContext } from '@azure/functions'; + +app.cosmosDBMongo('mongoTrigger', { + connectionStringSetting: 'CosmosDBMongo', + databaseName: 'SampleDB', + collectionName: 'Items', + createIfNotExists: true, + handler: (documents: unknown, context: InvocationContext) => { + context.log('CosmosDB Mongo trigger fired'); + context.log('Changed documents:', JSON.stringify(documents, null, 2)); + }, +}); diff --git a/test/cosmosDBMongo.test.ts b/test/cosmosDBMongo.test.ts index 5fca9d4..5db0f79 100644 --- a/test/cosmosDBMongo.test.ts +++ b/test/cosmosDBMongo.test.ts @@ -71,6 +71,7 @@ describe('cosmosDBMongo bindings', () => { const bindingValues = Object.values(result.bindings) as Record[]; const trig = bindingValues.find((b) => b['type'] === 'cosmosDBMongoTrigger'); expect(trig).to.exist; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion expect(trig!['direction']).to.equal('in'); }); }); diff --git a/types/cosmosDBMongo.d.ts b/types/cosmosDBMongo.d.ts index 917833a..5ae005d 100644 --- a/types/cosmosDBMongo.d.ts +++ b/types/cosmosDBMongo.d.ts @@ -13,7 +13,9 @@ export type CosmosDBMongoHandler = (documents: T, context: Invocati /** * Options for registering a CosmosDB Mongo-triggered function via `app.cosmosDBMongo()`. */ -export interface CosmosDBMongoFunctionOptions extends CosmosDBMongoTriggerOptions, Partial { +export interface CosmosDBMongoFunctionOptions + extends CosmosDBMongoTriggerOptions, + Partial { handler: CosmosDBMongoHandler; trigger?: CosmosDBMongoTrigger; From 2b9b69a0e801e5bdc9ba7da705fc1a2f77abc211 Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Fri, 15 May 2026 00:46:48 +0800 Subject: [PATCH 5/9] resolve comments --- package-lock.json | 6 +- package.json | 4 +- sample/cosmosDBMongo/extensions.csproj | 11 --- sample/cosmosDBMongo/host.json | 11 --- sample/cosmosDBMongo/local.settings.json | 8 -- sample/cosmosDBMongo/nuget.config | 7 -- sample/cosmosDBMongo/package-lock.json | 87 ------------------- sample/cosmosDBMongo/package.json | 18 ---- .../src/functions/httpGetDocuments.ts | 24 ----- .../src/functions/httpWriteDocument.ts | 27 ------ .../src/functions/mongoTrigger.ts | 15 ---- sample/cosmosDBMongo/tsconfig.json | 13 --- scripts/validateRelease.ts | 6 +- src/constants.ts | 4 +- test/cosmosDBMongo.test.ts | 55 +++++++++++- types/cosmosDBMongo.d.ts | 10 +-- 16 files changed, 68 insertions(+), 238 deletions(-) delete mode 100644 sample/cosmosDBMongo/extensions.csproj delete mode 100644 sample/cosmosDBMongo/host.json delete mode 100644 sample/cosmosDBMongo/local.settings.json delete mode 100644 sample/cosmosDBMongo/nuget.config delete mode 100644 sample/cosmosDBMongo/package-lock.json delete mode 100644 sample/cosmosDBMongo/package.json delete mode 100644 sample/cosmosDBMongo/src/functions/httpGetDocuments.ts delete mode 100644 sample/cosmosDBMongo/src/functions/httpWriteDocument.ts delete mode 100644 sample/cosmosDBMongo/src/functions/mongoTrigger.ts delete mode 100644 sample/cosmosDBMongo/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 2fd6f97..0dc95a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@azure/functions", - "version": "4.13.0", + "version": "4.15.0-preview", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@azure/functions", - "version": "4.13.0", + "version": "4.15.0-preview", "license": "MIT", "dependencies": { "@azure/functions-extensions-base": "0.2.0", @@ -7160,4 +7160,4 @@ } } } -} +} diff --git a/package.json b/package.json index 69f5018..5d3e306 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@azure/functions", - "version": "4.13.0", + "version": "4.15.0-preview", "description": "Microsoft Azure Functions NodeJS Framework", "keywords": [ "azure", @@ -85,4 +85,4 @@ "webpack": "^5.74.0", "webpack-cli": "^4.10.0" } -} +} diff --git a/sample/cosmosDBMongo/extensions.csproj b/sample/cosmosDBMongo/extensions.csproj deleted file mode 100644 index ee92e28..0000000 --- a/sample/cosmosDBMongo/extensions.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - net6.0 - - ** - - - - - - \ No newline at end of file diff --git a/sample/cosmosDBMongo/host.json b/sample/cosmosDBMongo/host.json deleted file mode 100644 index 95b6932..0000000 --- a/sample/cosmosDBMongo/host.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "2.0", - "logging": { - "applicationInsights": { - "samplingSettings": { - "isEnabled": true, - "excludedTypes": "Request" - } - } - } -} diff --git a/sample/cosmosDBMongo/local.settings.json b/sample/cosmosDBMongo/local.settings.json deleted file mode 100644 index 5732777..0000000 --- a/sample/cosmosDBMongo/local.settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "FUNCTIONS_WORKER_RUNTIME": "node", - "CosmosDBMongo": "YOUR_CONNECTION_STRING_HERE" - } -} diff --git a/sample/cosmosDBMongo/nuget.config b/sample/cosmosDBMongo/nuget.config deleted file mode 100644 index 765346e..0000000 --- a/sample/cosmosDBMongo/nuget.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/sample/cosmosDBMongo/package-lock.json b/sample/cosmosDBMongo/package-lock.json deleted file mode 100644 index 626f105..0000000 --- a/sample/cosmosDBMongo/package-lock.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "cosmosdb-mongo-sample", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cosmosdb-mongo-sample", - "version": "1.0.0", - "dependencies": { - "@azure/functions": "file:../../" - }, - "devDependencies": { - "typescript": "^5.0.0" - } - }, - "../..": { - "version": "4.12.0", - "license": "MIT", - "dependencies": { - "@azure/functions-extensions-base": "0.2.0", - "cookie": "^0.7.0" - }, - "devDependencies": { - "@types/chai": "^4.2.22", - "@types/chai-as-promised": "^7.1.5", - "@types/cookie": "^0.6.0", - "@types/fs-extra": "^9.0.13", - "@types/long": "^4.0.2", - "@types/minimist": "^1.2.2", - "@types/mocha": "^9.1.1", - "@types/node": "^20.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", - "chai-as-promised": "^7.1.1", - "eslint": "^7.32.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-deprecation": "^1.3.2", - "eslint-plugin-header": "^3.1.1", - "eslint-plugin-import": "^2.29.0", - "eslint-plugin-prettier": "^4.0.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", - "long": "^4.0.0", - "minimist": "^1.2.6", - "mocha": "^11.1.0", - "mocha-junit-reporter": "^2.0.2", - "mocha-multi-reporters": "^1.5.1", - "prettier": "^2.4.1", - "semver": "^7.3.5", - "sinon": "^20.0.0", - "ts-loader": "^9.5.1", - "ts-node": "^10.9.2", - "typescript": "~5.0.0", - "typescript4": "npm:typescript@~4.0.0", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@azure/functions": { - "resolved": "../..", - "link": true - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - } - } -} diff --git a/sample/cosmosDBMongo/package.json b/sample/cosmosDBMongo/package.json deleted file mode 100644 index 88a19ef..0000000 --- a/sample/cosmosDBMongo/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "cosmosdb-mongo-sample", - "version": "1.0.0", - "private": true, - "main": "dist/src/functions/*.js", - "scripts": { - "build": "tsc", - "watch": "tsc -w", - "prestart": "npm run build", - "start": "func start" - }, - "dependencies": { - "@azure/functions": "^4.12.0" - }, - "devDependencies": { - "typescript": "^5.0.0" - } -} diff --git a/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts b/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts deleted file mode 100644 index d7b602e..0000000 --- a/sample/cosmosDBMongo/src/functions/httpGetDocuments.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; - -const cosmosInput = input.cosmosDBMongo({ - connectionStringSetting: 'CosmosDBMongo', - databaseName: 'SampleDB', - collectionName: 'Items', -}); - -app.http('httpGetDocuments', { - methods: ['GET'], - authLevel: 'anonymous', - extraInputs: [cosmosInput], - handler: (request: HttpRequest, context: InvocationContext): HttpResponseInit => { - const documents = context.extraInputs.get(cosmosInput); - context.log('Read documents from CosmosDB Mongo:', JSON.stringify(documents)); - - return { - jsonBody: documents, - }; - }, -}); diff --git a/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts b/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts deleted file mode 100644 index 036ff1c..0000000 --- a/sample/cosmosDBMongo/src/functions/httpWriteDocument.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; - -const cosmosOutput = output.cosmosDBMongo({ - connectionStringSetting: 'CosmosDBMongo', - databaseName: 'SampleDB', - collectionName: 'Items', - createIfNotExists: true, -}); - -app.http('httpWriteDocument', { - methods: ['POST'], - authLevel: 'anonymous', - extraOutputs: [cosmosOutput], - handler: async (request: HttpRequest, context: InvocationContext): Promise => { - const body = await request.json(); - context.log('Writing document to CosmosDB Mongo:', JSON.stringify(body)); - context.extraOutputs.set(cosmosOutput, body); - - return { - status: 201, - jsonBody: { message: 'Document written successfully', document: body }, - }; - }, -}); diff --git a/sample/cosmosDBMongo/src/functions/mongoTrigger.ts b/sample/cosmosDBMongo/src/functions/mongoTrigger.ts deleted file mode 100644 index f5e70d4..0000000 --- a/sample/cosmosDBMongo/src/functions/mongoTrigger.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -import { app, InvocationContext } from '@azure/functions'; - -app.cosmosDBMongo('mongoTrigger', { - connectionStringSetting: 'CosmosDBMongo', - databaseName: 'SampleDB', - collectionName: 'Items', - createIfNotExists: true, - handler: (documents: unknown, context: InvocationContext) => { - context.log('CosmosDB Mongo trigger fired'); - context.log('Changed documents:', JSON.stringify(documents, null, 2)); - }, -}); diff --git a/sample/cosmosDBMongo/tsconfig.json b/sample/cosmosDBMongo/tsconfig.json deleted file mode 100644 index 3580085..0000000 --- a/sample/cosmosDBMongo/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "ES2020", - "outDir": "dist", - "rootDir": ".", - "sourceMap": true, - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true - }, - "include": ["src/**/*.ts"] -} diff --git a/scripts/validateRelease.ts b/scripts/validateRelease.ts index 751cbf1..91563ff 100644 --- a/scripts/validateRelease.ts +++ b/scripts/validateRelease.ts @@ -32,8 +32,8 @@ function validateRelease(publishTag: string, dropPath: string): void { let expectedFormat: string; switch (publishTag) { case 'preview': - regex = /^[0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+$/; - expectedFormat = 'x.x.x-alpha.x'; + regex = /^[0-9]+\.[0-9]+\.[0-9]+-preview$/; + expectedFormat = 'x.x.x-preview'; break; case 'latest': case 'legacy': @@ -48,4 +48,4 @@ function validateRelease(publishTag: string, dropPath: string): void { `Version number for tag "${publishTag}" should be in format "${expectedFormat}". Instead got "${versionNumber}"` ); } -} +} diff --git a/src/constants.ts b/src/constants.ts index b3819cd..87d0c3b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -export const version = '4.13.0'; +export const version = '4.15.0-preview'; -export const returnBindingKey = '$return'; +export const returnBindingKey = '$return'; diff --git a/test/cosmosDBMongo.test.ts b/test/cosmosDBMongo.test.ts index 5db0f79..2258f9c 100644 --- a/test/cosmosDBMongo.test.ts +++ b/test/cosmosDBMongo.test.ts @@ -14,7 +14,9 @@ describe('cosmosDBMongo bindings', () => { const minimalTriggerOptions = { connectionStringSetting: 'CosmosDBMongo', databaseName: 'MyDatabase', - collectionName: 'MyCollection', + collectionName: 'MyCollection', + leaseDatabaseName: 'MyDatabase', + leaseCollectionName: 'leases', }; // ------------------------------------------------------------------------- @@ -76,6 +78,55 @@ describe('cosmosDBMongo bindings', () => { }); }); + describe('app.cosmosDBMongo', () => { + it('registers a function through the public wrapper', () => { + const registerCalls: Array<{ metadata: { bindings: Record }; handler: unknown }> = []; + const fakeCoreApi = { + registerFunction: (metadata: { bindings: Record }, registeredHandler: unknown) => { + registerCalls.push({ metadata, handler: registeredHandler }); + }, + setProgrammingModel: () => {}, + }; + + const moduleCtor = require('module') as { _load: (...args: unknown[]) => unknown }; + const originalLoad = moduleCtor._load; + const appPath = require.resolve('../src/app'); + const coreApiPath = require.resolve('../src/utils/tryGetCoreApiLazy'); + + delete require.cache[appPath]; + delete require.cache[coreApiPath]; + + moduleCtor._load = function (...args: unknown[]) { + if (args[0] === '@azure/functions-core') { + return fakeCoreApi; + } + return originalLoad.apply(this, args); + }; + + try { + const appModule = require('../src/app') as typeof import('../src/app'); + const appHandler = (_doc: unknown, _context: InvocationContext) => {}; + + appModule.cosmosDBMongo('mongoAppFunc', { + ...minimalTriggerOptions, + handler: appHandler, + }); + + expect(registerCalls).to.have.lengthOf(1); + expect(registerCalls[0]?.handler).to.equal(appHandler); + + const bindingValues = Object.values(registerCalls[0]!.metadata.bindings) as Record[]; + const triggerBinding = bindingValues.find((b) => b['type'] === 'cosmosDBMongoTrigger'); + expect(triggerBinding).to.exist; + expect(triggerBinding?.['direction']).to.equal('in'); + } finally { + moduleCtor._load = originalLoad; + delete require.cache[appPath]; + delete require.cache[coreApiPath]; + } + }); + }); + // ------------------------------------------------------------------------- // input // ------------------------------------------------------------------------- @@ -191,4 +242,4 @@ describe('cosmosDBMongo bindings', () => { expect(outputBinding).to.exist; }); }); -}); +}); diff --git a/types/cosmosDBMongo.d.ts b/types/cosmosDBMongo.d.ts index 5ae005d..d6ea4cb 100644 --- a/types/cosmosDBMongo.d.ts +++ b/types/cosmosDBMongo.d.ts @@ -64,15 +64,15 @@ export interface CosmosDBMongoTriggerOptions { /** * The name of the database that holds the lease collection. - * Defaults to the monitored database name. + * The name of the database that holds the lease collection. */ - leaseDatabaseName?: string; + leaseDatabaseName: string; /** * The name of the collection used to store leases. - * Defaults to "leases". + * The name of the collection used to store leases. */ - leaseCollectionName?: string; + leaseCollectionName: string; /** * An app setting name for the connection string of the lease account. @@ -186,4 +186,4 @@ export interface CosmosDBMongoOutputOptions { managedIdentityClientId?: string; } -export type CosmosDBMongoOutput = FunctionOutput & CosmosDBMongoOutputOptions; +export type CosmosDBMongoOutput = FunctionOutput & CosmosDBMongoOutputOptions; From 40b6dd36f6d5880b9df1f09b0f7bd5824deb3551 Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Fri, 15 May 2026 16:26:06 +0800 Subject: [PATCH 6/9] fix lint error --- test/cosmosDBMongo.test.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/test/cosmosDBMongo.test.ts b/test/cosmosDBMongo.test.ts index 2258f9c..b7b2647 100644 --- a/test/cosmosDBMongo.test.ts +++ b/test/cosmosDBMongo.test.ts @@ -3,6 +3,7 @@ import 'mocha'; import { expect } from 'chai'; +import Module = require('module'); import { input, output, trigger } from '../src'; import { toCoreFunctionMetadata } from '../src/converters/toCoreFunctionMetadata'; import { InvocationContext } from '../types'; @@ -79,7 +80,7 @@ describe('cosmosDBMongo bindings', () => { }); describe('app.cosmosDBMongo', () => { - it('registers a function through the public wrapper', () => { + it('registers a function through the public wrapper', async () => { const registerCalls: Array<{ metadata: { bindings: Record }; handler: unknown }> = []; const fakeCoreApi = { registerFunction: (metadata: { bindings: Record }, registeredHandler: unknown) => { @@ -88,7 +89,7 @@ describe('cosmosDBMongo bindings', () => { setProgrammingModel: () => {}, }; - const moduleCtor = require('module') as { _load: (...args: unknown[]) => unknown }; + const moduleCtor = Module as unknown as { _load: (...args: unknown[]) => unknown }; const originalLoad = moduleCtor._load; const appPath = require.resolve('../src/app'); const coreApiPath = require.resolve('../src/utils/tryGetCoreApiLazy'); @@ -104,7 +105,7 @@ describe('cosmosDBMongo bindings', () => { }; try { - const appModule = require('../src/app') as typeof import('../src/app'); + const appModule = await import('../src/app'); const appHandler = (_doc: unknown, _context: InvocationContext) => {}; appModule.cosmosDBMongo('mongoAppFunc', { @@ -113,9 +114,13 @@ describe('cosmosDBMongo bindings', () => { }); expect(registerCalls).to.have.lengthOf(1); - expect(registerCalls[0]?.handler).to.equal(appHandler); + const registerCall = registerCalls[0]; + if (!registerCall) { + throw new Error('Expected app.cosmosDBMongo to register a function.'); + } + expect(registerCall.handler).to.equal(appHandler); - const bindingValues = Object.values(registerCalls[0]!.metadata.bindings) as Record[]; + const bindingValues = Object.values(registerCall.metadata.bindings) as Record[]; const triggerBinding = bindingValues.find((b) => b['type'] === 'cosmosDBMongoTrigger'); expect(triggerBinding).to.exist; expect(triggerBinding?.['direction']).to.equal('in'); From e3f7abb95c6ba6d45245722d71de4e0333e77587 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 21:37:02 +0000 Subject: [PATCH 7/9] Clarify web pubsub connections documentation Co-authored-by: swapnil-nagar <1988068+swapnil-nagar@users.noreply.github.com> --- types/webpubsub.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types/webpubsub.d.ts b/types/webpubsub.d.ts index 5b9b2ba..334beab 100644 --- a/types/webpubsub.d.ts +++ b/types/webpubsub.d.ts @@ -101,7 +101,9 @@ export interface WebPubSubContextInputOptions { /** * Optional - The names of app settings or setting collections that specify the upstream Azure Web PubSub services. - * The value is used for Abuse Protection and Signature validation. + * This replaces the deprecated `connection` option. + * The values are used for Abuse Protection and Signature validation. + * When multiple values are provided, each configured service is considered during signature validation. * The value is auto resolved with "WebPubSubConnectionString" by default. */ connections?: string[]; From 8dfb12bfba98559edde6a9a14feadbf9547c0ae1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 21:37:56 +0000 Subject: [PATCH 8/9] Fix plural wording for web pubsub connections docs Co-authored-by: swapnil-nagar <1988068+swapnil-nagar@users.noreply.github.com> --- types/webpubsub.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/webpubsub.d.ts b/types/webpubsub.d.ts index 334beab..79211e9 100644 --- a/types/webpubsub.d.ts +++ b/types/webpubsub.d.ts @@ -104,7 +104,7 @@ export interface WebPubSubContextInputOptions { * This replaces the deprecated `connection` option. * The values are used for Abuse Protection and Signature validation. * When multiple values are provided, each configured service is considered during signature validation. - * The value is auto resolved with "WebPubSubConnectionString" by default. + * The values are auto resolved with "WebPubSubConnectionString" by default. */ connections?: string[]; From 7bb23a78c6b7367535ffbe9ed29d6f8795f909ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 21:38:51 +0000 Subject: [PATCH 9/9] Clarify web pubsub setting collection docs Co-authored-by: swapnil-nagar <1988068+swapnil-nagar@users.noreply.github.com> --- types/webpubsub.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/webpubsub.d.ts b/types/webpubsub.d.ts index 79211e9..b72cd0d 100644 --- a/types/webpubsub.d.ts +++ b/types/webpubsub.d.ts @@ -44,7 +44,8 @@ export interface WebPubSubTriggerOptions { clientProtocols?: 'all' | 'webPubSub' | 'mqtt'; /** - * Optional - The names of app settings or setting collections that specify the upstream Azure Web PubSub services + * Optional - The names of app settings or app setting collections (for identity-based grouped settings) + * that specify the upstream Azure Web PubSub services. * Used for signature validation * Defaults to "WebPubSubConnectionString" if not specified */