├── .devcontainer ├── azure-upload-file-to-storage │ └── devcontainer.json └── devcontainer.json ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── dependency-review.yml │ └── scorecards.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── api-expressjs-vm ├── .github │ ├── CODE_OF_CONDUCT.md │ ├── ISSUE_TEMPLATE.md │ └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── cloud-init-github.txt ├── index-logging.js ├── index.js ├── json │ └── az-vm-public-ip.json ├── package-lock.json ├── package.json ├── public │ └── leaves.jpg └── readme.md ├── api-functions-v4-azure-resource-management ├── .eslintignore ├── .eslintrc ├── .funcignore ├── .gitignore ├── .prettierignore ├── .prettierrc ├── README.md ├── host.json ├── package-lock.json ├── package.json ├── src │ ├── functions │ │ ├── resourcegroup.ts │ │ ├── resourcegroups.ts │ │ └── resources.ts │ └── lib │ │ ├── azure-resource-groups.ts │ │ ├── azure-resource.ts │ │ ├── environment-vars.ts │ │ └── error.ts └── tsconfig.json ├── api-inmemory ├── .funcignore ├── .gitignore ├── host.json ├── local.settings.json ├── local.settings.sample.json ├── package.json ├── src │ └── functions │ │ ├── status.ts │ │ └── todo.ts └── tsconfig.json ├── app-react-vite ├── .gitignore ├── README.md ├── index.html ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.css │ ├── App.tsx │ ├── Components │ │ ├── NavBar.tsx │ │ └── Status.tsx │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── staticwebapp.config.json ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── azure-upload-file-to-storage ├── README.md ├── api │ ├── .funcignore │ ├── .gitignore │ ├── .prettierrc │ ├── .vscode │ │ ├── extensions.json │ │ ├── launch.json │ │ ├── settings.json │ │ └── tasks.json │ ├── README.md │ ├── eslint.config.mjs │ ├── host.json │ ├── http │ │ ├── sas.http │ │ └── status.http │ ├── local.settings.json.sample │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── functions │ │ │ ├── list.ts │ │ │ ├── sas.ts │ │ │ └── status.ts │ │ └── lib │ │ │ └── azure-storage.ts │ ├── test-file.txt │ └── tsconfig.json └── app │ ├── .env.sample │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc.json │ ├── eslint.config.js │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.css │ ├── App.tsx │ ├── components │ │ └── error-boundary.tsx │ ├── lib │ │ └── convert-file-to-arraybuffer.ts │ ├── main.tsx │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite.config.dev.ts │ └── vite.config.ts ├── docs ├── azure-functions.md └── troubleshooting.md ├── example-workflows ├── api-inmem.yml └── app-react-vite.yml ├── package.json ├── quickstarts ├── ai-agents │ ├── README.md │ ├── js │ │ ├── output.txt │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── sample.env │ │ └── src │ │ │ └── index.js │ └── ts │ │ ├── output.txt │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── sample.env │ │ ├── src │ │ └── index.ts │ │ └── tsconfig.json ├── ai-search │ ├── .env.sample │ ├── package.json │ ├── src │ │ ├── full-text-search.ts │ │ ├── hotels.json │ │ └── hotels_quickstart_index.json │ └── tsconfig.json ├── azure-openai-assistants │ ├── js │ │ ├── package.json │ │ ├── sample.env │ │ ├── scripts │ │ │ └── create-azure-resource.sh │ │ └── src │ │ │ ├── index-using-password.mjs │ │ │ └── index.mjs │ ├── readme.md │ └── ts │ │ ├── package.json │ │ ├── sample.env │ │ ├── scripts │ │ └── create-azure-resource.sh │ │ ├── src │ │ ├── index-using-password.ts │ │ └── index.ts │ │ └── tsconfig.json ├── azure-sql │ └── connect-and-query │ │ ├── README.md │ │ ├── create-resources.sh │ │ ├── js │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── .prettierrc.json │ │ ├── .vscode │ │ │ └── launch.json │ │ ├── README.md │ │ ├── config.js │ │ ├── database.js │ │ ├── index.js │ │ ├── mssql-no-password.js │ │ ├── openApiSchema.yml │ │ ├── openapi.js │ │ ├── package.json │ │ ├── person.js │ │ ├── sample.env │ │ ├── scripts │ │ │ └── create-service-connector-connection.sh │ │ └── sql │ │ │ ├── create-azure-sql-user.sql │ │ │ └── create-table.sql │ │ ├── media │ │ └── azure-sql-openapi-screenshot.png │ │ └── ts │ │ ├── .eslintignore │ │ ├── .eslintrc │ │ ├── .gitignore │ │ ├── .prettierrc │ │ ├── README.md │ │ ├── mssql-no-password.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── sample.env │ │ ├── scripts │ │ └── create-service-connector-connection.sh │ │ ├── sql │ │ ├── create-azure-sql-user.sql │ │ └── create-table.sql │ │ ├── src │ │ ├── config.ts │ │ ├── dbazuresql.ts │ │ ├── index.ts │ │ ├── openApiSchema.yml │ │ └── routes │ │ │ ├── openapi.ts │ │ │ └── person.ts │ │ └── tsconfig.json ├── key-vault │ ├── .env.sample │ ├── .eslintignore │ ├── .eslintrc │ ├── .prettierrc │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── certificates.ts │ │ ├── keys.ts │ │ └── secrets.ts │ └── tsconfig.json ├── openai │ ├── .eslintignore │ ├── .eslintrc │ ├── .prettierrc │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── chat-key.ts │ │ ├── chat-no-key.ts │ │ ├── completion-key.ts │ │ ├── completion-no-key.ts │ │ ├── dall-e-key.ts │ │ ├── dall-e-no-key.ts │ │ ├── text-to-speech-key.ts │ │ ├── text-to-speech-no-key.ts │ │ ├── use-your-data-key.ts │ │ ├── use-your-data-no-key.ts │ │ ├── vision-key.ts │ │ ├── vision-no-key.ts │ │ ├── whisper-key.ts │ │ └── whisper-no-key.ts │ └── tsconfig.json ├── service-bus │ ├── README.md │ └── ts │ │ ├── package.json │ │ ├── src │ │ ├── queue-connection-string-receive.ts │ │ ├── queue-connection-string-send.ts │ │ ├── queue-passwordless-receive.ts │ │ ├── queue-passwordless-send.ts │ │ ├── topic-connection-string-receive.ts │ │ ├── topic-connection-string-send.ts │ │ ├── topic-passwordless-receive.ts │ │ └── topic-passwordless-send.ts │ │ └── tsconfig.json └── storage │ ├── index.js │ ├── package-lock.json │ └── package.json ├── resources └── 2024-js-dev-day.md ├── scripts ├── clean.sh ├── openai-request.js └── package.json ├── sdk └── chained-credentials │ ├── chained-token-credential.js │ ├── custom-tenant-credential.js │ ├── debug-chained-credential.js │ ├── default-azure-credential.js │ ├── managed-identity-credential.js │ ├── package.json │ ├── user-assigned-managed-identity.js │ ├── why-use-credential-chains.js │ └── workload-identity.js ├── swa-cli.config.json ├── test-api-functions-v4 ├── .gitignore ├── package.json ├── playwright.config.ts ├── test-api.spec.ts └── tests │ └── test-api.spec.ts ├── ts-boilerplate-common ├── .gitignore ├── http │ ├── get-root.http │ └── post-api.http ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── index.ts │ └── public │ │ ├── index.html │ │ └── styles.css └── tsconfig.json └── ts-boilerplate-esm ├── .gitignore ├── .prettierignore ├── .prettierrc ├── http ├── get-root.http └── post-data.http ├── package-lock.json ├── package.json ├── readme.md ├── src └── index.ts └── tsconfig.json /.devcontainer/azure-upload-file-to-storage/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node 3 | { 4 | "name": "Tutorial: Upload file to storage with SAS token", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/typescript-node:0-20", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | "features": { 10 | "ghcr.io/jsburckhardt/devcontainer-features/gitleaks:1": {}, 11 | "ghcr.io/devcontainers-contrib/features/pre-commit:2": {} 12 | }, 13 | 14 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 15 | // 5173: Vite React 16 | // 7071: Azure Functions 17 | "forwardPorts": [5173, 7071], 18 | 19 | // Use 'postCreateCommand' to run commands after the container is created. 20 | "postCreateCommand": "npm install -g azure-functions-core-tools@4 --save-exact --unsafe-perm true", 21 | 22 | // Configure tool-specific properties. 23 | // "customizations": {}, 24 | 25 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 26 | "remoteUser": "root", 27 | "customizations": { 28 | "vscode": { 29 | "extensions": [ 30 | "ms-azuretools.vscode-azurefunctions", 31 | "ms-azuretools.vscode-azurestaticwebapps", 32 | "ms-azuretools.vscode-azurestorage", 33 | "humao.rest-client" 34 | ] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node 3 | { 4 | "name": "Repo owner - all projects", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/typescript-node:0-20", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 12 | "forwardPorts": [7071], 13 | 14 | // Use 'postCreateCommand' to run commands after the container is created. 15 | "postCreateCommand": "npm install -g azure-functions-core-tools@4.0.6610 --save-exact --unsafe-perm true", 16 | "features": { 17 | "ghcr.io/jsburckhardt/devcontainer-features/gitleaks:1": {}, 18 | "ghcr.io/devcontainers/features/azure-cli:1": {} 19 | }, 20 | "customizations": { 21 | "vscode": { 22 | "extensions": [ 23 | "humao.rest-client" 24 | ] 25 | } 26 | } 27 | 28 | // Configure tool-specific properties. 29 | // "customizations": {}, 30 | 31 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 32 | // "remoteUser": "root" 33 | } 34 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | > Please provide us with the following information: 5 | > --------------------------------------------------------------- 6 | 7 | ### This issue is for a: (mark with an `x`) 8 | ``` 9 | - [ ] bug report -> please search issues before submitting 10 | - [ ] feature request 11 | - [ ] documentation issue or request 12 | - [ ] regression (a behavior that used to work and stopped in a new release) 13 | ``` 14 | 15 | ### Minimal steps to reproduce 16 | > 17 | 18 | ### Any log messages given by the failure 19 | > 20 | 21 | ### Expected/desired behavior 22 | > 23 | 24 | ### OS and Version? 25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) 26 | 27 | ### Versions 28 | > 29 | 30 | ### Mention any other details that might be useful 31 | 32 | > --------------------------------------------------------------- 33 | > Thanks! We'll be in touch soon. 34 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | * ... 4 | 5 | ## Does this introduce a breaking change? 6 | 7 | ``` 8 | [ ] Yes 9 | [ ] No 10 | ``` 11 | 12 | ## Pull Request Type 13 | What kind of change does this Pull Request introduce? 14 | 15 | 16 | ``` 17 | [ ] Bugfix 18 | [ ] Feature 19 | [ ] Code style update (formatting, local variables) 20 | [ ] Refactoring (no functional changes, no api changes) 21 | [ ] Documentation content changes 22 | [ ] Other... Please describe: 23 | ``` 24 | 25 | ## How to Test 26 | * Get the code 27 | 28 | ``` 29 | git clone [repo-address] 30 | cd [repo-name] 31 | git checkout [branch-name] 32 | npm install 33 | ``` 34 | 35 | * Test the code 36 | 37 | ``` 38 | ``` 39 | 40 | ## What to Check 41 | Verify that the following are valid 42 | * ... 43 | 44 | ## Other Information 45 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, 4 | # surfacing known-vulnerable versions of the packages declared or updated in the PR. 5 | # Once installed, if the workflow run is marked as required, 6 | # PRs introducing known-vulnerable packages will be blocked from merging. 7 | # 8 | # Source repository: https://github.com/actions/dependency-review-action 9 | name: 'Dependency Review' 10 | on: [pull_request] 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | dependency-review: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Harden Runner 20 | uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0 21 | with: 22 | egress-policy: audit 23 | 24 | - name: 'Checkout Repository' 25 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 26 | - name: 'Dependency Review' 27 | uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 28 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/gitleaks/gitleaks 3 | rev: v8.18.2 4 | hooks: 5 | - id: gitleaks 6 | - repo: https://github.com/jumanjihouse/pre-commit-hooks 7 | rev: 3.0.0 8 | hooks: 9 | - id: shellcheck 10 | - repo: https://github.com/pre-commit/mirrors-eslint 11 | rev: v8.38.0 12 | hooks: 13 | - id: eslint 14 | - repo: https://github.com/pre-commit/pre-commit-hooks 15 | rev: v4.4.0 16 | hooks: 17 | - id: end-of-file-fixer 18 | - id: trailing-whitespace 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [Azure/static-web-apps-deploy] Changelog 2 | 3 | # x1.0.0 (2023.04) 4 | 5 | *Features* 6 | * SWA + API 7 | * `.devcontainer`: local proxied react + api using [SWA CLI](https://learn.microsoft.com/en-us/azure/static-web-apps/static-web-apps-cli-configuration) 8 | * `app-react-vite`: very simple React 18 + Vite app with Azure _easy auth_ 9 | * `api`: very simple Node.js Azure Functions v4 (new programming model) with `/status` route 10 | * `api-inmemory`: very simple Node.js Azure Functions v4 (new programming model) with `/status` and in-memory db for `/todo` route 11 | * `docs`: helpful information about resources 12 | * `example-workflows`: example GitHub workflow files you can use to build and deploy apps 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Azure TypeScript apps 3 | description: A variety of TypeScript apps to deploy on Azure or integrate with Azure services. 4 | page_type: sample 5 | languages: 6 | - javascript 7 | - typescript 8 | products: 9 | - azure-app-service 10 | - azure-functions 11 | --- 12 | 13 | # Azure TypeScript E2E apps 14 | 15 | A monorepo of apps used with the Azure cloud as part of the [Azure Developer Center for JavaScript](https://learn.microsoft.com/azure/developer/javascript/). This repo provides sample code and project to deploy JavaScript and TypeScript to Azure. 16 | 17 | ## Features 18 | 19 | * `.devcontainer`: local proxied react + api using [SWA CLI](https://learn.microsoft.com/en-us/azure/static-web-apps/static-web-apps-cli-configuration) 20 | * `app-react-vite`: very simple React 18 + Vite app with Azure _easy auth_ 21 | * `api`: very simple Node.js Azure Functions v4 (new programming model) with `/status` route 22 | * `api-inmemory`: very simple Node.js Azure Functions v4 (new programming model) with `/status` and in-memory db for `/todo` route 23 | * `docs`: helpful information about resources 24 | * `example-workflows`: example GitHub workflow files you can use to build and deploy apps 25 | 26 | ## Documentation 27 | 28 | * React 18 (Vite) + Azure Functions API v4 29 | 30 | ## Naming conventions 31 | 32 | |Name|Description| 33 | |--|--| 34 | |`app-`|Client or full-stack web app.| 35 | |`api=`|HTTP API.| 36 | |`lib-`|Library. Included in other projects.| 37 | |`cli-`|Command-line interface.| 38 | -------------------------------------------------------------------------------- /api-expressjs-vm/.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /api-expressjs-vm/.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | > Please provide us with the following information: 5 | > --------------------------------------------------------------- 6 | 7 | ### This issue is for a: (mark with an `x`) 8 | ``` 9 | - [ ] bug report -> please search issues before submitting 10 | - [ ] feature request 11 | - [ ] documentation issue or request 12 | - [ ] regression (a behavior that used to work and stopped in a new release) 13 | ``` 14 | 15 | ### Minimal steps to reproduce 16 | > 17 | 18 | ### Any log messages given by the failure 19 | > 20 | 21 | ### Expected/desired behavior 22 | > 23 | 24 | ### OS and Version? 25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) 26 | 27 | ### Versions 28 | > 29 | 30 | ### Mention any other details that might be useful 31 | 32 | > --------------------------------------------------------------- 33 | > Thanks! We'll be in touch soon. 34 | -------------------------------------------------------------------------------- /api-expressjs-vm/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | * ... 4 | 5 | ## Does this introduce a breaking change? 6 | 7 | ``` 8 | [ ] Yes 9 | [ ] No 10 | ``` 11 | 12 | ## Pull Request Type 13 | What kind of change does this Pull Request introduce? 14 | 15 | 16 | ``` 17 | [ ] Bugfix 18 | [ ] Feature 19 | [ ] Code style update (formatting, local variables) 20 | [ ] Refactoring (no functional changes, no api changes) 21 | [ ] Documentation content changes 22 | [ ] Other... Please describe: 23 | ``` 24 | 25 | ## How to Test 26 | * Get the code 27 | 28 | ``` 29 | git clone [repo-address] 30 | cd [repo-name] 31 | git checkout [branch-name] 32 | npm install 33 | ``` 34 | 35 | * Test the code 36 | 37 | ``` 38 | ``` 39 | 40 | ## What to Check 41 | Verify that the following are valid 42 | * ... 43 | 44 | ## Other Information 45 | -------------------------------------------------------------------------------- /api-expressjs-vm/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /api-expressjs-vm/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [project-title] Changelog 2 | 3 | 4 | # x.y.z (yyyy-mm-dd) 5 | 6 | *Features* 7 | * ... 8 | 9 | *Bug Fixes* 10 | * ... 11 | 12 | *Breaking Changes* 13 | * ... 14 | -------------------------------------------------------------------------------- /api-expressjs-vm/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /api-expressjs-vm/cloud-init-github.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | package_upgrade: true 3 | packages: 4 | - nginx 5 | write_files: 6 | - owner: www-data:www-data 7 | path: /etc/nginx/sites-available/default 8 | content: | 9 | server { 10 | listen 80 default_server; 11 | server_name _; 12 | location / { 13 | # First, try if the file exists locally, otherwise request it from the app 14 | try_files $uri @app; 15 | } 16 | location @app { 17 | proxy_pass http://localhost:3000; 18 | proxy_http_version 1.1; 19 | proxy_set_header Upgrade $http_upgrade; 20 | proxy_set_header Connection 'upgrade'; 21 | proxy_set_header X-Forwarded-For $remote_addr; 22 | proxy_set_header Host $host; 23 | proxy_cache_bypass $http_upgrade; 24 | } 25 | } 26 | runcmd: 27 | # install Node.js 28 | - 'curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -' 29 | - 'sudo apt-get install -y nodejs' 30 | # clone GitHub Repo into myapp directory 31 | - 'cd /home/azureuser' 32 | - git clone "https://github.com/Azure-Samples/js-e2e-vm" myapp 33 | # Start app 34 | - 'cd myapp && npm install && npm start' 35 | # restart NGINX 36 | - systemctl restart nginx 37 | -------------------------------------------------------------------------------- /api-expressjs-vm/index-logging.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const app = express() 3 | const os = require('os'); 4 | 5 | // console.log(JSON.stringify(process.env)); 6 | 7 | const AppInsights = require('applicationinsights'); 8 | 9 | if (process.env.APPINSIGHTS_INSTRUMENTATIONKEY) { 10 | console.log(`AppInsights configured with key ${process.env.APPINSIGHTS_INSTRUMENTATIONKEY}`); 11 | } else{ 12 | console.log(`AppInsights not configured`); 13 | } 14 | 15 | AppInsights.setup(process.env.APPINSIGHTS_INSTRUMENTATIONKEY) 16 | .setAutoDependencyCorrelation(true) 17 | .setAutoCollectRequests(true) 18 | .setAutoCollectPerformance(true, true) 19 | .setAutoCollectExceptions(true) 20 | .setAutoCollectDependencies(true) 21 | .setAutoCollectConsole(true) 22 | .setUseDiskRetryCaching(true) 23 | .setSendLiveMetrics(false) 24 | .setDistributedTracingMode(AppInsights.DistributedTracingModes.AI) 25 | .start(); 26 | 27 | const AppInsightsClient = AppInsights.defaultClient; 28 | 29 | 30 | app.get('/trace', (req, res) => { 31 | 32 | const clientIP = req.headers['x-forwarded-for']; 33 | const msg = `trace route ${os.hostname()} ${clientIP} ${new Date()}`; 34 | 35 | console.log(msg) 36 | 37 | if (process.env.APPINSIGHTS_INSTRUMENTATIONKEY) { 38 | AppInsightsClient.trackPageView(); 39 | AppInsightsClient.trackTrace({ message: msg }) 40 | AppInsightsClient.flush(); 41 | } else { 42 | msg += ' AppInsights not configured'; 43 | } 44 | 45 | res.send(`${msg}`) 46 | }) 47 | 48 | app.get('/', function (req, res) { 49 | 50 | const clientIP = req.headers['x-forwarded-for']; 51 | const msg = `root route ${os.hostname()} ${clientIP} ${new Date()}` 52 | 53 | console.log(msg) 54 | 55 | res.send(msg) 56 | 57 | }) 58 | app.listen(3000, function () { 59 | console.log(`Hello world app listening on port 3000! ${os.hostname()}`) 60 | }) 61 | -------------------------------------------------------------------------------- /api-expressjs-vm/index.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const express = require('express') 3 | const app = express() 4 | 5 | app.use('/public', express.static('public')) 6 | app.get('/', function (req, res) { 7 | 8 | const clientIP = req.headers['x-forwarded-for']; 9 | const msg = `HostName: ${os.hostname()}
ClientIP: ${clientIP}
DateTime: ${new Date()}
flowers` 10 | console.log(msg) 11 | 12 | res.send(msg) 13 | }) 14 | app.listen(3000, function () { 15 | console.log(`Hello world app listening on port 3000! ${Date.now()}`) 16 | }) 17 | -------------------------------------------------------------------------------- /api-expressjs-vm/json/az-vm-public-ip.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "virtualMachine": { 4 | "name": "demo-vm", 5 | "network": { 6 | "privateIpAddresses": [ 7 | "YOUR-VM-PRIVATE-IP" 8 | ], 9 | "publicIpAddresses": [ 10 | { 11 | "id": "/subscriptions/YOUR-SUBSCRIPTION-ID/resourceGroups/YOUR-RESOURCE-GROUP-NAME/providers/Microsoft.Network/publicIPAddresses/YOUR-RESOURCE-NAME-ip", 12 | "ipAddress": "YOUR-VM-PUBLIC-IP", 13 | "ipAllocationMethod": "Static", 14 | "name": "YOUR-RESOURCE-NAME-ip", 15 | "resourceGroup": "YOUR-RESOURCE-GROUP-NAME", 16 | "zone": "1" 17 | } 18 | ] 19 | }, 20 | "resourceGroup": "YOUR-RESOURCE-GROUP-NAME" 21 | } 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /api-expressjs-vm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-e2e-vm", 3 | "version": "1.0.0", 4 | "description": "JavaScript server written with Express.js", 5 | "main": "index.js", 6 | "scripts": { 7 | "stop": "pm2 kill", 8 | "start": "pm2 start index.js --watch --log /var/log/pm2.log", 9 | "list": "pm2 list", 10 | "restart": "pm2 restart index.js", 11 | "appinsights": "cp index.js index-wo-insights.js && cp index-insights.js index.js" 12 | }, 13 | "license": "MIT", 14 | "dependencies": { 15 | "express": "^4.21.0", 16 | "pm2": "^5.4.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /api-expressjs-vm/public/leaves.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-typescript-e2e-apps/e3b9c39fbb85c6cc3eeef8702ec9607163f88919/api-expressjs-vm/public/leaves.jpg -------------------------------------------------------------------------------- /api-expressjs-vm/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | name: Create Express.js virtual machine using Azure CLI 4 | description: In this tutorial, create a Linux virtual machine (VM) for an Express.js app. The VM is configured with a cloud-init configuration file and includes NGINX and a GitHub repository for an Express.js app. Connect to the VM with SSH, change the web app to including trace logging, and view the public Express.js server app in a web browser. 5 | languages: 6 | - javascript 7 | - nodejs 8 | products: 9 | - azure-virtual-machines 10 | extensions: 11 | ms.doc: /azure/developer/javascript/tutorial/run-nodejs-virtual-machine 12 | --- 13 | 14 | # Create Express.js virtual machine using Azure CLI 15 | 16 | This sample is used as part of a [Tutorial: Create Express.js virtual machine using Azure CLI](https://learn.microsoft.com/en-us/azure/developer/javascript/tutorial/run-nodejs-virtual-machine). 17 | 18 | In this tutorial, create a Linux virtual machine (VM) for an Express.js app. The VM is configured with a cloud-init configuration file and includes NGINX and a GitHub repository for an Express.js app. Connect to the VM with SSH, change the web app to including trace logging, and view the public Express.js server app in a web browser. -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | ./jest.config.ts 4 | scripts -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint", "prettier"], 5 | "extends": [ 6 | "eslint:recommended", 7 | "plugin:@typescript-eslint/eslint-recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "prettier" 10 | ], 11 | "rules": { 12 | "no-console": 1, // Means warning 13 | "prettier/prettier": 2, // Means error 14 | "ban-ts-comment": 0, 15 | "@typescript-eslint/no-unused-vars": [ 16 | "warn", // or "error" 17 | { 18 | "argsIgnorePattern": "^_", 19 | "varsIgnorePattern": "^_", 20 | "caughtErrorsIgnorePattern": "^_" 21 | } 22 | ], 23 | "sort-imports": [ 24 | "error", 25 | { 26 | "ignoreCase": true, 27 | "ignoreDeclarationSort": true 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | local.settings.json 6 | test 7 | tsconfig.json -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | dist -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "singleQuote": true, 5 | "printWidth": 80 6 | } -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | }, 11 | "extensionBundle": { 12 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 13 | "version": "[2.*, 3.0.0)" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/src/functions/*.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "build:format": "prettier --write ./src/**/*.ts", 9 | "build:lint": "eslint **/*.ts --fix", 10 | "watch": "tsc -w", 11 | "prestart": "npm run build", 12 | "start": "func start", 13 | "test": "echo \"No tests yet...\"" 14 | }, 15 | "dependencies": { 16 | "@azure/arm-resources": "^5.2.0", 17 | "@azure/functions": "^4.0.0-alpha.7", 18 | "@azure/identity": "^3.1.3" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^18.x", 22 | "@typescript-eslint/eslint-plugin": "^5.57.0", 23 | "prettier": "^2.8.7", 24 | "typescript": "^4.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/src/functions/resourcegroups.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Get resources in a resource group 3 | 4 | curl http://localhost:7071/api/resource-groups 5 | */ 6 | // 7 | import { ResourceGroup } from '@azure/arm-resources'; 8 | import { 9 | app, 10 | HttpRequest, 11 | HttpResponseInit, 12 | InvocationContext 13 | } from '@azure/functions'; 14 | import { listResourceGroups } from '../lib/azure-resource-groups'; 15 | import { processError } from '../lib/error'; 16 | 17 | 18 | export async function resourcegroups( 19 | request: HttpRequest, 20 | context: InvocationContext 21 | ): Promise { 22 | try { 23 | const { 24 | list, 25 | subscriptionId 26 | }: { list: ResourceGroup[]; subscriptionId: string } = 27 | await listResourceGroups(); 28 | 29 | context.log( 30 | `${list && list.length ? list.length : 0} resource groups found` 31 | ); 32 | 33 | return { 34 | jsonBody: { 35 | subscriptionId, 36 | list 37 | } 38 | }; 39 | } catch (err: unknown) { 40 | return processError(err); 41 | } 42 | } 43 | 44 | app.http('resourcegroups', { 45 | methods: ['GET'], 46 | authLevel: 'anonymous', 47 | handler: resourcegroups 48 | }); 49 | // -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/src/functions/resources.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Get resources in a subscription 4 | 5 | curl http://localhost:7071/api/resources 6 | 7 | Get resources in a resource group 8 | 9 | curl http://localhost:7071/api/resources?resourceGroupName=REPLACE-WITH-YOUR-RESOURCE-GROUP-NAME 10 | 11 | */ 12 | // 13 | import { 14 | app, 15 | HttpRequest, 16 | HttpResponseInit, 17 | InvocationContext 18 | } from '@azure/functions'; 19 | import { 20 | listResourceByResourceGroup, listResourceBySubscription 21 | } from '../lib/azure-resource'; 22 | import { processError } from '../lib/error'; 23 | 24 | export async function resources( 25 | request: HttpRequest, 26 | context: InvocationContext 27 | ): Promise { 28 | try { 29 | const resourceGroupName: string = request.query.get('resourceGroupName'); 30 | context.log(`resourceGroupName: '${resourceGroupName}'`); 31 | 32 | if (resourceGroupName) { 33 | const resourcesByName = await listResourceByResourceGroup( 34 | resourceGroupName 35 | ); 36 | return { jsonBody: resourcesByName }; 37 | } else { 38 | const resourcesBySubscription = await listResourceBySubscription(); 39 | return { jsonBody: resourcesBySubscription }; 40 | } 41 | } catch (err: unknown) { 42 | return processError(err); 43 | } 44 | } 45 | app.http('resources', { 46 | methods: ['GET'], 47 | authLevel: 'anonymous', 48 | handler: resources 49 | }); 50 | // -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/src/lib/azure-resource-groups.ts: -------------------------------------------------------------------------------- 1 | // Include npm dependencies 2 | import { 3 | ResourceGroup, ResourceManagementClient 4 | } from '@azure/arm-resources'; 5 | import { DefaultAzureCredential } from '@azure/identity'; 6 | import { getSubscriptionId } from './environment-vars'; 7 | 8 | const subscriptionId = getSubscriptionId(); 9 | 10 | // Create Azure authentication credentials 11 | const credentials = new DefaultAzureCredential(); 12 | 13 | // Create Azure SDK client for Resource Management such as resource groups 14 | const resourceManagement = new ResourceManagementClient( 15 | credentials, 16 | subscriptionId 17 | ); 18 | 19 | // all resources groups in subscription 20 | export const listResourceGroups = async (): Promise<{ 21 | list: ResourceGroup[]; 22 | subscriptionId: string; 23 | }> => { 24 | const list: ResourceGroup[] = []; 25 | for await (const resourceGroup of resourceManagement.resourceGroups.list()) { 26 | list.push(resourceGroup); 27 | } 28 | return { 29 | subscriptionId, 30 | list 31 | }; 32 | }; 33 | export const createResourceGroup = async ( 34 | resourceGroupName: string, 35 | location: string, 36 | tags: { [propertyName: string]: string } 37 | ): Promise => { 38 | const resourceGroupParameters = { 39 | location: location, 40 | tags 41 | }; 42 | 43 | return await resourceManagement.resourceGroups.createOrUpdate( 44 | resourceGroupName, 45 | resourceGroupParameters 46 | ); 47 | }; 48 | export const deleteResourceGroup = async ( 49 | resourceGroupName: string 50 | ): Promise => { 51 | return await resourceManagement.resourceGroups.beginDeleteAndWait( 52 | resourceGroupName 53 | ); 54 | }; 55 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/src/lib/azure-resource.ts: -------------------------------------------------------------------------------- 1 | // Include npm dependencies 2 | import { Resource, ResourceManagementClient } from '@azure/arm-resources'; 3 | import { DefaultAzureCredential } from '@azure/identity'; 4 | import { getSubscriptionId } from './environment-vars'; 5 | 6 | const subscriptionId = getSubscriptionId(); 7 | 8 | // Create Azure authentication credentials 9 | const credentials = new DefaultAzureCredential(); 10 | 11 | // Create Azure SDK client for Resource Management such as resource groups 12 | const resourceManagement = new ResourceManagementClient( 13 | credentials, 14 | subscriptionId 15 | ); 16 | 17 | // all resources groups in subscription 18 | export const listResourceBySubscription = async (): Promise<{ 19 | list: Resource[]; 20 | subscriptionId: string; 21 | }> => { 22 | const list: Resource[] = []; 23 | 24 | for await (const resource of resourceManagement.resources.list()) { 25 | list.push(resource); 26 | } 27 | 28 | return { 29 | subscriptionId, 30 | list 31 | }; 32 | }; 33 | // all resources groups in resource group 34 | export const listResourceByResourceGroup = async ( 35 | resourceGroupName: string 36 | ): Promise<{ 37 | list: Resource[]; 38 | subscriptionId: string; 39 | resourceGroupName: string; 40 | }> => { 41 | const list: Resource[] = []; 42 | 43 | for await (const resource of resourceManagement.resources.listByResourceGroup( 44 | resourceGroupName 45 | )) { 46 | list.push(resource); 47 | } 48 | 49 | return { 50 | subscriptionId, 51 | resourceGroupName, 52 | list 53 | }; 54 | }; 55 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/src/lib/environment-vars.ts: -------------------------------------------------------------------------------- 1 | export const checkAzureAuth = () => { 2 | // The following code is only used to check you have environment 3 | // variables configured. The DefaultAzureCredential reads your 4 | // environment - it doesn't read these variables. 5 | const tenantId = process.env['AZURE_TENANT_ID']; 6 | if (!tenantId) 7 | throw Error('AZURE_TENANT_ID is missing from environment variables.'); 8 | const clientId = process.env['AZURE_CLIENT_ID']; 9 | if (!clientId) 10 | throw Error('AZURE_CLIENT_ID is missing from environment variables.'); 11 | const secret = process.env['AZURE_CLIENT_SECRET']; 12 | if (!secret) 13 | throw Error('AZURE_CLIENT_SECRET is missing from environment variables.'); 14 | }; 15 | 16 | export const getSubscriptionId = (): string => { 17 | checkAzureAuth(); 18 | 19 | // Get subscription from environment variables 20 | const subscriptionId = process.env['AZURE_SUBSCRIPTION_ID']; 21 | if (!subscriptionId) 22 | throw Error('Azure Subscription is missing from environment variables.'); 23 | return subscriptionId; 24 | }; 25 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/src/lib/error.ts: -------------------------------------------------------------------------------- 1 | export function processError(err: unknown): any { 2 | if (typeof err === 'string') { 3 | return { body: err.toUpperCase(), status: 500 }; 4 | } else if ( 5 | err['stack'] && 6 | process.env.NODE_ENV.toLowerCase() !== 'production' 7 | ) { 8 | return { jsonBody: { stack: err['stack'], message: err['message'] } }; 9 | } else if (err instanceof Error) { 10 | return { body: err.message, status: 500 }; 11 | } else { 12 | return { body: JSON.stringify(err) }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /api-functions-v4-azure-resource-management/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "rootDir": ".", 7 | "sourceMap": true, 8 | "strict": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /api-inmemory/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | __azurite_db*__.json 6 | __blobstorage__ 7 | __queuestorage__ 8 | local.settings.json 9 | test 10 | tsconfig.json 11 | .devcontainer 12 | .vscode 13 | node_modules -------------------------------------------------------------------------------- /api-inmemory/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | .env.test 64 | 65 | # parcel-bundler cache (https://parceljs.org/) 66 | .cache 67 | 68 | # next.js build output 69 | .next 70 | 71 | # nuxt.js build output 72 | .nuxt 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless/ 79 | 80 | # FuseBox cache 81 | .fusebox/ 82 | 83 | # DynamoDB Local files 84 | .dynamodb/ 85 | 86 | # TypeScript output 87 | dist 88 | out 89 | 90 | # Azure Functions artifacts 91 | bin 92 | obj 93 | appsettings.json 94 | local.settings.json 95 | 96 | # Azurite artifacts 97 | __blobstorage__ 98 | __queuestorage__ 99 | __azurite_db*__.json -------------------------------------------------------------------------------- /api-inmemory/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | }, 11 | "extensionBundle": { 12 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 13 | "version": "[3.15.0, 4.0.0)" 14 | } 15 | } -------------------------------------------------------------------------------- /api-inmemory/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "node", 6 | "AzureWebJobsFeatureFlags": "EnableWorkerIndexing" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /api-inmemory/local.settings.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "node", 6 | "AzureWebJobsFeatureFlags": "EnableWorkerIndexing" 7 | } 8 | } -------------------------------------------------------------------------------- /api-inmemory/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api4", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "build": "echo 'build v2 api' && tsc", 7 | "watch": "tsc -w", 8 | "prestart": "rm -rf dist && npm run build", 9 | "start": "echo 'run v2 api' && func start --typescript --verbose", 10 | "test": "echo \"No tests yet...\"" 11 | }, 12 | "dependencies": { 13 | "@azure/functions": "4.0.0-alpha.9" 14 | }, 15 | "devDependencies": { 16 | "azure-functions-core-tools": "4.0.5095", 17 | "@types/node": "^18.x", 18 | "typescript": "^4.0.0" 19 | }, 20 | "main": "dist/src/functions/*.js" 21 | } 22 | -------------------------------------------------------------------------------- /api-inmemory/src/functions/status.ts: -------------------------------------------------------------------------------- 1 | import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; 2 | 3 | import { name, version } from '../../package.json'; 4 | function isObject(v) { 5 | return '[object Object]' === Object.prototype.toString.call(v); 6 | }; 7 | function sortJson(o){ 8 | if (Array.isArray(o)) { 9 | return o.sort().map(sortJson); 10 | } else if (isObject(o)) { 11 | return Object 12 | .keys(o) 13 | .sort() 14 | .reduce(function(a, k) { 15 | a[k] = sortJson(o[k]); 16 | 17 | return a; 18 | }, {}); 19 | } 20 | return o; 21 | } 22 | 23 | export async function status(request: HttpRequest, context: InvocationContext): Promise { 24 | context.log(`Http function processed request for url "${request.url}"`); 25 | 26 | const sortedEnv = sortJson(process.env); 27 | 28 | return { jsonBody: { 29 | name, 30 | version, 31 | env: sortedEnv, 32 | requestHeaders: request.headers 33 | }}; 34 | }; 35 | 36 | app.http('status', { 37 | route: "status", 38 | methods: ['GET'], 39 | authLevel: 'anonymous', 40 | handler: status 41 | }); -------------------------------------------------------------------------------- /api-inmemory/src/functions/todo.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | //create a todo, view a todo, modify a todo, list all todos, delete all todos 4 | 5 | import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; 6 | // import { MongoClient } from 'mongodb'; 7 | 8 | let nextId = 2; 9 | 10 | type Todo = { 11 | title: string; 12 | } 13 | 14 | let todos = { 15 | "1": "Say hello" 16 | }; 17 | 18 | 19 | app.get('getAll', { 20 | route: "todo", 21 | authLevel: 'anonymous', 22 | handler: async function getAll(request: HttpRequest, context: InvocationContext): Promise { 23 | 24 | return { jsonBody: todos } 25 | } 26 | }) 27 | 28 | // curl --location 'http://localhost:7071/api/users?user=mike' \ 29 | // --header 'Content-Type: application/json' \ 30 | // --data '{ 31 | // "name": "dina", 32 | // "age": "21" 33 | // }' 34 | 35 | app.post('addOne', { 36 | route: "todo", 37 | authLevel: 'anonymous', 38 | handler: async function addOne(request: HttpRequest, context: InvocationContext): Promise { 39 | 40 | const body = await request.json(); 41 | console.log(body) 42 | 43 | if(body && body.title){ 44 | todos[nextId++] = body.title; 45 | 46 | console.log(todos); 47 | 48 | return { 49 | jsonBody: body.title 50 | } 51 | } 52 | return { status: 404 } 53 | 54 | } 55 | }) 56 | 57 | 58 | app.deleteRequest('deleteAll', { 59 | route: "todo", 60 | authLevel: 'anonymous', 61 | handler: async function deleteAll(request: HttpRequest, context: InvocationContext): Promise { 62 | 63 | todos = {}; 64 | nextId=1; 65 | 66 | return { 67 | jsonBody: todos 68 | } 69 | } 70 | }) 71 | -------------------------------------------------------------------------------- /api-inmemory/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "rootDir": ".", 7 | "strict": false, 8 | "sourceMap": true, 9 | "noImplicitAny": false, 10 | "resolveJsonModule": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app-react-vite/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /app-react-vite/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Tutorial: Create a Static web app with a serverless API" 3 | description: Learn how to locally run then deploy a static web app with a serverless API to Azure. This tutorial uses the preview version of the latest Azure Functions Node.js programming model. Because this article uses a preview version of Azure Functions, it is deployed as a separate app from the static web app. 4 | page_type: sample 5 | languages: 6 | - javascript 7 | - typescript 8 | products: 9 | - azure-functions 10 | - static-web-apps 11 | extensions: 12 | ms.doc: /azure/developer/javascript/how-to/with-web-app/static-web-app-with-swa-cli 13 | --- 14 | # Create a Static web app with a serverless API 15 | 16 | This sample is used as part of a [Tutorial: Create a Static web app with a serverless API](https://learn.microsoft.com/azure/developer/javascript/how-to/with-web-app/static-web-app-with-swa-cli). 17 | -------------------------------------------------------------------------------- /app-react-vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app-react-vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-react-demo-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "styled-components": "^5.3.9" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^18.16.0", 18 | "@types/react": "^18.0.28", 19 | "@types/react-dom": "^18.0.11", 20 | "@types/styled-components": "^5.1.26", 21 | "@vitejs/plugin-react": "^3.1.0", 22 | "typescript": "^4.9.3", 23 | "vite": "^4.2.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app-react-vite/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app-react-vite/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /app-react-vite/src/Components/NavBar.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | const NavBar = ({user}:any) => { 3 | 4 | const providers = [ 5 | { displayName: 'Twitter', useName: 'twitter' }, 6 | { displayName: 'GitHub', useName: 'github' }, 7 | { displayName: 'Microsoft Entra ID', useName: 'aad' } 8 | ]; 9 | const redirect = `/`; 10 | 11 | useEffect(() => { 12 | console.log(`NavBar user object: ${JSON.stringify(user)}`) 13 | }, [user]); 14 | 15 | return ( 16 | <> 17 | {!user && providers.map((provider, index) => ( 18 | 19 | {provider.displayName} 20 | {index < providers.length - 1 ? ' | ' : ''} 21 | 22 | ))} 23 | {user && ( 24 |
25 |

26 | {user && user?.userDetails.toLowerCase().split(' ').map(x=>x[0].toUpperCase()+x.slice(1)).join(' ')} ({user && user?.identityProvider}) 27 | 28 | Logout 29 | 30 | 31 |

32 |
33 | )} 34 | 35 | ) 36 | 37 | } 38 | export default NavBar; -------------------------------------------------------------------------------- /app-react-vite/src/Components/Status.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from 'react'; 2 | 3 | let url = `/api/status`; 4 | 5 | const cloudEnv = import.meta.env.VITE_CLOUD_ENV || `production`; 6 | const backendEnv = import.meta.env.VITE_BACKEND_URI || `https://localhost:7071`; 7 | 8 | console.log(`CLOUD_ENV = ${cloudEnv}`) 9 | console.log(`BACKEND_URI = ${backendEnv}`) 10 | 11 | if (cloudEnv.toLowerCase()=='production') { 12 | if (backendEnv) { 13 | url = `${backendEnv}${url}` 14 | } else { 15 | throw Error(`Missing backendEnv`) 16 | } 17 | } 18 | 19 | console.log(`URL = ${url}`) 20 | 21 | 22 | function Status({ user }:any) { 23 | 24 | const [envvars, setEnvVars] = useState([]); 25 | const mountFlag = useRef(false) 26 | 27 | useEffect(() => { 28 | const fetchData = async () => { 29 | if (user?.userDetails) { 30 | mountFlag.current = true; 31 | const data = await fetch(url); 32 | const json = await data.json(); 33 | setEnvVars(json); 34 | } 35 | } 36 | 37 | fetchData(); 38 | }, []); 39 | 40 | return ( 41 |
42 |
43 |

Hi {user?.userDetails.toLowerCase().split(' ').map(x=>x[0].toUpperCase()+x.slice(1)).join(' ')}

44 | {JSON.stringify(envvars)} 45 |
46 |
47 | ); 48 | } 49 | export default Status; -------------------------------------------------------------------------------- /app-react-vite/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | button { 40 | border-radius: 8px; 41 | border: 1px solid transparent; 42 | padding: 0.6em 1.2em; 43 | font-size: 1em; 44 | font-weight: 500; 45 | font-family: inherit; 46 | background-color: #1a1a1a; 47 | cursor: pointer; 48 | transition: border-color 0.25s; 49 | } 50 | button:hover { 51 | border-color: #646cff; 52 | } 53 | button:focus, 54 | button:focus-visible { 55 | outline: 4px auto -webkit-focus-ring-color; 56 | } 57 | 58 | @media (prefers-color-scheme: light) { 59 | :root { 60 | color: #213547; 61 | background-color: #ffffff; 62 | } 63 | a:hover { 64 | color: #747bff; 65 | } 66 | button { 67 | background-color: #f9f9f9; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app-react-vite/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /app-react-vite/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /app-react-vite/staticwebapp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "platform": { 3 | "apiRuntime": "node:18" 4 | } 5 | } -------------------------------------------------------------------------------- /app-react-vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "noImplicitAny": false, 19 | "sourceMap": true 20 | }, 21 | "include": ["src"], 22 | "references": [{ "path": "./tsconfig.node.json" }] 23 | } 24 | -------------------------------------------------------------------------------- /app-react-vite/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /app-react-vite/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | server: { 9 | port: 3000, 10 | }, 11 | plugins: [react()], 12 | }) 13 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Tutorial: Upload an image to an Azure Storage blob with JavaScript" 3 | description: Use a static web app to upload a file to an Azure Storage blob. 4 | page_type: sample 5 | languages: 6 | - javascript 7 | - typescript 8 | products: 9 | - azure-functions 10 | - static-web-apps 11 | extensions: 12 | ms.doc: /azure/developer/javascript/tutorial/browser-file-upload-azure-storage-blob 13 | --- 14 | # Upload an image to an Azure Storage blob with JavaScript 15 | 16 | This sample is used as part of a [Tutorial: Upload an image to an Azure Storage blob with JavaScript](https://learn.microsoft.com/en-us/azure/developer/javascript/tutorial/browser-file-upload-azure-storage-blob?tabs=github-codespaces). 17 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | local.settings.json 6 | test 7 | tsconfig.json -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | .env.test 64 | 65 | # parcel-bundler cache (https://parceljs.org/) 66 | .cache 67 | 68 | # next.js build output 69 | .next 70 | 71 | # nuxt.js build output 72 | .nuxt 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless/ 79 | 80 | # FuseBox cache 81 | .fusebox/ 82 | 83 | # DynamoDB Local files 84 | .dynamodb/ 85 | 86 | # TypeScript output 87 | dist 88 | out 89 | 90 | # Azure Functions artifacts 91 | bin 92 | obj 93 | appsettings.json 94 | *.settings.json 95 | local.settings.json 96 | local* 97 | 98 | # Azurite Storage emulator 99 | azure/ 100 | 101 | # MacOs 102 | .DS_Store -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "singleQuote": true, 5 | "printWidth": 80 6 | } -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Node Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 9229, 9 | "preLaunchTask": "func: host start" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": ".", 3 | "azureFunctions.postDeployTask": "npm install (functions)", 4 | "azureFunctions.projectLanguage": "TypeScript", 5 | "azureFunctions.projectRuntime": "~4", 6 | "debug.internalConsoleOptions": "neverOpen", 7 | "azureFunctions.preDeployTask": "npm prune (functions)" 8 | } -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "func", 6 | "command": "host start", 7 | "problemMatcher": "$func-node-watch", 8 | "isBackground": true, 9 | "dependsOn": "npm build (functions)" 10 | }, 11 | { 12 | "type": "shell", 13 | "label": "npm build (functions)", 14 | "command": "npm run build", 15 | "dependsOn": "npm install (functions)", 16 | "problemMatcher": "$tsc" 17 | }, 18 | { 19 | "type": "shell", 20 | "label": "npm install (functions)", 21 | "command": "npm install" 22 | }, 23 | { 24 | "type": "shell", 25 | "label": "npm prune (functions)", 26 | "command": "npm prune --production", 27 | "dependsOn": "npm build (functions)", 28 | "problemMatcher": [] 29 | }, 30 | { 31 | "type": "func", 32 | "command": "extensions install", 33 | "problemMatcher": [], 34 | "label": "func: extensions install" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/README.md: -------------------------------------------------------------------------------- 1 | # Azure Functions V4 app to upload file to Azure Storage 2 | 3 | Upload a file to Azure Storage using Azure Functions V4 and the Azure SDK package for Azure Storage. 4 | 5 | 1. Upload file to HTTP endpoint. 6 | 1. File is saved to Azure Storage. 7 | 1. Read-only SAS token is generated for the file. 8 | 1. Read-only URL including SAS token is returned to the client. 9 | 10 | ## Prerequisite 11 | 12 | You need an Azure Storage account created and ready for Azure Functions. 13 | 14 | ## Environment variables 15 | 16 | The app needs the following environment variables. These should be available in the `local.settings.json` while developing locally. 17 | 18 | ``` 19 | "AzureWebJobsStorage": "", 20 | "FUNCTIONS_WORKER_RUNTIME": "node", 21 | "AzureWebJobsFeatureFlags": "EnableWorkerIndexing", 22 | "Azure_Storage_AccountName": "", 23 | "Azure_Storage_AccountKey":"" 24 | ``` 25 | 26 | ## Clone, install and run locally 27 | 28 | 1. In a new folder, use the following commands to get source code for this project. 29 | 30 | ```bash 31 | git init 32 | git remote add origin https://github.com/azure-samples/azure-typescript-e2e-apps 33 | git config core.sparseCheckout true 34 | git sparse-checkout set api-functions-v4-upload-file 35 | git pull origin main 36 | git sparse-checkout disable 37 | ``` 38 | 39 | 2. Install the dependencies. 40 | 41 | ```bash 42 | npm install 43 | ``` 44 | 45 | ## Call function 46 | 47 | Use the following cURL command, provided in [`upload-text-file.sh`](upload-text-file.sh) to automate your file uploads during development. 48 | 49 | ```bash 50 | curl --location 'http://localhost:7071/api/upload' -F "file=@test-file.txt" --form 'name="tom"' --verbose 51 | ``` 52 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | import tseslint from "typescript-eslint"; 4 | 5 | 6 | /** @type {import('eslint').Linter.Config[]} */ 7 | export default [ 8 | {files: ["**/*.{js,mjs,cjs,ts}"]}, 9 | {languageOptions: { globals: globals.browser }}, 10 | pluginJs.configs.recommended, 11 | ...tseslint.configs.recommended, 12 | ]; -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | }, 11 | "extensionBundle": { 12 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 13 | "version": "[3.3.0, 4.0.0)" 14 | } 15 | } -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/http/sas.http: -------------------------------------------------------------------------------- 1 | POST http://localhost:7071/api/sas?file=test&permissions=w&container=upload&timerange=5 HTTP/1.1 2 | content-type: application/json -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/http/status.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:7071/api/status HTTP/1.1 2 | content-type: application/json 3 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/local.settings.json.sample: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "node", 6 | "AzureWebJobsFeatureFlags": "EnableWorkerIndexing", 7 | "Azure_Storage_AccountName": "", 8 | "Azure_Storage_AccountKey":"" 9 | }, 10 | "Host": { 11 | "CORS": "*" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "upload-file-api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/src/functions/*.js", 6 | "scripts": { 7 | "setup:core-tools": "npm i -g azure-functions-core-tools@4 --unsafe-perm true", 8 | "prestart": "npm run build", 9 | "dev": "npm run build && func start --verbose", 10 | "start": "func start", 11 | "test": "echo \"No tests yet...\"", 12 | "build:all": "npm run clean && npm run format && npm run lint && npm run build", 13 | "format": "prettier --write src/**/*.ts", 14 | "lint": "eslint src/**/*.ts --fix", 15 | "build": "tsc", 16 | "clean": "rimraf dist" 17 | }, 18 | "devDependencies": { 19 | "@eslint/js": "^9.20.0", 20 | "@types/node": "^22.13.4", 21 | "eslint": "^9.20.1", 22 | "globals": "^15.15.0", 23 | "rimraf": "^6.0.1", 24 | "typescript": "^5.7.3", 25 | "typescript-eslint": "^8.24.0" 26 | }, 27 | "dependencies": { 28 | "@azure/functions": "^4.6.1", 29 | "@azure/storage-blob": "^12.26.0", 30 | "prettier": "^3.5.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/src/functions/list.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpRequest, 3 | HttpResponseInit, 4 | InvocationContext, 5 | app 6 | } from '@azure/functions'; 7 | import { listFilesInContainer } from '../lib/azure-storage.js'; 8 | 9 | export async function getFilesInContainer( 10 | request: HttpRequest, 11 | context: InvocationContext 12 | ): Promise { 13 | context.log(`Http function processed request for url "${request.url}"`); 14 | 15 | try { 16 | if ( 17 | !process.env?.Azure_Storage_AccountName || 18 | !process.env?.Azure_Storage_AccountKey 19 | ) { 20 | return { 21 | status: 405, 22 | jsonBody: 'Missing required app configuration' 23 | }; 24 | } 25 | 26 | const containerName = request.query.get('container'); 27 | context.log(`containerName: ${containerName}`); 28 | 29 | if (!containerName) { 30 | return { 31 | status: 405, 32 | jsonBody: 'Missing required container name' 33 | }; 34 | } 35 | 36 | const { error, errorMessage, data } = await listFilesInContainer( 37 | process.env?.Azure_Storage_AccountName as string, 38 | process.env?.Azure_Storage_AccountKey as string, 39 | containerName 40 | ); 41 | context.log(errorMessage); 42 | context.log(JSON.stringify(data)); 43 | if (!error) { 44 | return { 45 | jsonBody: { list: data } 46 | }; 47 | } else { 48 | return { 49 | status: 500, 50 | jsonBody: errorMessage 51 | }; 52 | } 53 | } catch (error) { 54 | return { 55 | status: 500, 56 | jsonBody: error 57 | }; 58 | } 59 | } 60 | 61 | app.http('list', { 62 | methods: ['POST', 'GET'], 63 | authLevel: 'anonymous', 64 | handler: getFilesInContainer 65 | }); 66 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/src/functions/sas.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpRequest, 3 | HttpResponseInit, 4 | InvocationContext, 5 | app 6 | } from '@azure/functions'; 7 | import { generateSASUrl } from '../lib/azure-storage.js'; 8 | 9 | export async function getGenerateSasToken( 10 | request: HttpRequest, 11 | context: InvocationContext 12 | ): Promise { 13 | context.log(`Http function processed request for url "${request.url}"`); 14 | 15 | try { 16 | if ( 17 | !process.env?.Azure_Storage_AccountName || 18 | !process.env?.Azure_Storage_AccountKey 19 | ) { 20 | return { 21 | status: 405, 22 | jsonBody: 'Missing required app configuration' 23 | }; 24 | } 25 | 26 | const containerName = request.query.get('container') || 'anonymous'; 27 | const fileName = request.query.get('file') || 'nonamefile'; 28 | const permissions = request.query.get('permission') || 'w'; 29 | const timerange = parseInt(request.query.get('timerange') || '10'); // 10 minutes 30 | 31 | context.log(`containerName: ${containerName}`); 32 | context.log(`fileName: ${fileName}`); 33 | context.log(`permissions: ${permissions}`); 34 | context.log(`timerange: ${timerange}`); 35 | 36 | const url = await generateSASUrl( 37 | process.env?.Azure_Storage_AccountName, 38 | process.env?.Azure_Storage_AccountKey, 39 | containerName, 40 | fileName, 41 | permissions 42 | ); 43 | 44 | return { 45 | jsonBody: { 46 | url 47 | } 48 | }; 49 | } catch (error) { 50 | return { 51 | status: 500, 52 | jsonBody: error 53 | }; 54 | } 55 | } 56 | 57 | app.http('sas', { 58 | methods: ['POST', 'GET'], 59 | authLevel: 'anonymous', 60 | handler: getGenerateSasToken 61 | }); 62 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/src/functions/status.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpRequest, 3 | HttpResponseInit, 4 | InvocationContext, 5 | app 6 | } from '@azure/functions'; 7 | 8 | export async function status( 9 | request: HttpRequest, 10 | context: InvocationContext 11 | ): Promise { 12 | const responseBody = { 13 | status: 'ok', 14 | request: { 15 | method: request.method, 16 | url: request.url, 17 | headers: request.headers 18 | }, 19 | context: { 20 | invocationId: context.invocationId 21 | // Other context properties can be added here if needed 22 | } 23 | }; 24 | 25 | return { jsonBody: responseBody }; 26 | } 27 | 28 | app.get('status', { 29 | authLevel: 'anonymous', 30 | handler: status 31 | }); 32 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/test-file.txt: -------------------------------------------------------------------------------- 1 | https://azure.microsoft.com/en-us/overview/what-is-azure/ 2 | 3 | The Azure cloud platform is more than 200 products and cloud services designed to help you bring new solutions to life—to solve today’s challenges and create the future. Build, run, and manage applications across multiple clouds, on-premises, and at the edge, with the tools and frameworks of your choice. -------------------------------------------------------------------------------- /azure-upload-file-to-storage/api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "rootDir": ".", 7 | "sourceMap": true, 8 | "strict": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/.env.sample: -------------------------------------------------------------------------------- 1 | # Do not add ending slash to URL 2 | VITE_API_SERVER=http://localhost:7071 3 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .env* 26 | 27 | .eslintcache -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | dist 3 | build 4 | coverage -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma":"none" 7 | } -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/eslint.config.js: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | import tseslint from "typescript-eslint"; 4 | import pluginReact from "eslint-plugin-react"; 5 | 6 | 7 | /** @type {import('eslint').Linter.Config[]} */ 8 | export default [ 9 | {files: ["./src/**/*.{ts,tsx}"]}, 10 | {languageOptions: { globals: globals.browser }}, 11 | pluginJs.configs.recommended, 12 | ...tseslint.configs.recommended, 13 | pluginReact.configs.flat.recommended, 14 | { 15 | settings: { 16 | react: { 17 | version: "detect" 18 | } 19 | }, 20 | rules: { 21 | "react/react-in-jsx-scope": "off" 22 | } 23 | } 24 | ]; -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "upload-file-app", 3 | "private": true, 4 | "version": "0.1.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "npm run build && vite --host --config vite.config.dev.ts", 8 | "start": "vite", 9 | "prestart": "npm run build", 10 | "build": "npm run clean && tsc && vite build", 11 | "compile": "tsc", 12 | "lint": "eslint \"src/**/*.{ts,tsx}\" --report-unused-disable-directives --max-warnings 0 --cache", 13 | "preview": "vite preview", 14 | "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,md}\"", 15 | "clean": "rimraf dist" 16 | }, 17 | "dependencies": { 18 | "@azure/storage-blob": "^12.14.0", 19 | "@emotion/react": "^11.11.1", 20 | "@emotion/styled": "^11.11.0", 21 | "@mui/material": "^5.14.2", 22 | "react": "^18.2.0", 23 | "react-dom": "^18.2.0", 24 | "rimraf": "^5.0.1" 25 | }, 26 | "devDependencies": { 27 | "@eslint/js": "^9.20.0", 28 | "@types/react": "^18.2.14", 29 | "@types/react-dom": "^18.2.6", 30 | "@vitejs/plugin-react": "^4.0.1", 31 | "eslint": "^9.20.1", 32 | "eslint-plugin-react": "^7.37.4", 33 | "globals": "^15.15.0", 34 | "prettier": "^3.0.0", 35 | "typescript": "^5.0.2", 36 | "typescript-eslint": "^8.24.0", 37 | "vite": "^4.4.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/src/App.css: -------------------------------------------------------------------------------- 1 | /* debug red border outline */ 2 | 3 | /* 4 | * { 5 | border: 1px solid red; 6 | } 7 | */ 8 | 9 | .container { 10 | margin: 1em; 11 | padding: 1em; 12 | } 13 | 14 | button { 15 | border: 1px solid blue; 16 | border-radius: 5%; 17 | background-color: lightblue; 18 | } 19 | .select-file input { 20 | 21 | border-radius: 5%; 22 | } 23 | input::-webkit-file-upload-button { 24 | background-color: transparent; 25 | } 26 | 27 | /* Make the status box auto-size */ 28 | .get-sas-token .status { 29 | 30 | display: flex; 31 | flex-direction: column; 32 | 33 | } 34 | .get-sas-token .status .text{ 35 | 36 | flex-grow: 1; 37 | background-color: pink; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/src/components/error-boundary.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // @ts-nocheck 3 | import React, { useState, useEffect } from 'react'; 4 | 5 | const ErrorBoundary = ({ children }: any) => { 6 | const [hasError, setHasError] = useState(false); 7 | const [error, setError] = useState(null); 8 | 9 | useEffect(() => { 10 | const errorHandler = (error: any, errorInfo: any) => { 11 | console.error('Error caught by ErrorBoundary:', error, errorInfo); 12 | setHasError(true); 13 | setError(error); 14 | }; 15 | 16 | window.addEventListener('error', errorHandler); 17 | return () => { 18 | window.removeEventListener('error', errorHandler); 19 | }; 20 | }, []); 21 | 22 | if (hasError) { 23 | return ( 24 | <> 25 |

Something went wrong.

26 |
{JSON.stringify(error)}
27 | 28 | ); 29 | } 30 | 31 | return children; 32 | }; 33 | 34 | export default ErrorBoundary; 35 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/src/lib/convert-file-to-arraybuffer.ts: -------------------------------------------------------------------------------- 1 | const convertStringToArrayBuffer = (str: string) => { 2 | const textEncoder = new TextEncoder(); 3 | return textEncoder.encode(str).buffer; 4 | }; 5 | 6 | export function convertFileToArrayBuffer( 7 | file: File 8 | ): Promise { 9 | return new Promise((resolve, reject) => { 10 | if (!file || !file.name) { 11 | reject(new Error('Invalid or missing file.')); 12 | } 13 | 14 | const reader = new FileReader(); 15 | 16 | reader.onload = () => { 17 | const arrayBuffer: ArrayBuffer | null | string = reader.result; 18 | 19 | if (arrayBuffer === null) { 20 | resolve(null); 21 | return; 22 | } 23 | if (typeof arrayBuffer === 'string') { 24 | resolve(convertStringToArrayBuffer(arrayBuffer)); 25 | return; 26 | } 27 | if (!arrayBuffer) { 28 | reject(new Error('Failed to read file into ArrayBuffer.')); 29 | return; 30 | } 31 | 32 | resolve(arrayBuffer); 33 | }; 34 | 35 | reader.onerror = () => { 36 | reject(new Error('Error reading file.')); 37 | }; 38 | 39 | reader.readAsArrayBuffer(file); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import App from './App.tsx'; 4 | 5 | ReactDOM.createRoot(document.getElementById('root')!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/vite.config.dev.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | build: { 8 | rollupOptions: { 9 | output: { 10 | manualChunks: { 11 | //@azure/storage-blob: ['@azure/storage-blob'] 12 | } 13 | } 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /azure-upload-file-to-storage/app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | build: { 8 | rollupOptions: { 9 | output: { 10 | manualChunks: { 11 | //@azure/storage-blob: ['@azure/storage-blob'] 12 | } 13 | } 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /docs/azure-functions.md: -------------------------------------------------------------------------------- 1 | # Azure Functions 2 | 3 | ## Create a new function with V4 model 4 | 5 | 1. Create a new folder and change into that folder: 6 | 7 | ```bash 8 | mkdir api-v4 9 | cd api-v4 10 | ``` 11 | 12 | 1. Install the latest version of [Azure Functions core tools](https://www.npmjs.com/package/azure-functions-core-tools). 13 | 14 | ```bash 15 | npm install -g https://www.npmjs.com/package/azure-functions-core-tools 16 | ``` 17 | 18 | 1. Run following commands to create new TypeScript Functions app. 19 | 20 | ```bash 21 | func init --worker-runtime node --model V4 --language typescript 22 | func new 23 | npm run build 24 | nom run start 25 | ``` -------------------------------------------------------------------------------- /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ## Error messages 4 | 5 | |Message|Steps to resolve| 6 | |--|--| 7 | |Can't determine project language from files|In an Azure Function app, this indicates the `./local.settings.json` file can't be found.| 8 | 9 | ## Static web app with API 10 | 11 | Tip: Start the SWA CLI with the `--verbose=silly` to see the logs. 12 | 13 | |Issue|Resolution| 14 | |--|--| 15 | |When using SWA CLI to proxy requests from client to API, request to API fails.|The SWA CLI uses 4280 as the port to use to access both the client and its ability to reach the API. If you use the client's usual port instead of port 4280, you aren't using the proxy and the request to the API will fail.| 16 | 17 | 18 | ## Azure Functions app 19 | 20 | Tip: Start the Functions app with the `--verbose` to see the logs. 21 | 22 | |Issue|Resolution| 23 | |--|--| 24 | |`Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]`|Create a `local.settings.json` file.| 25 | -------------------------------------------------------------------------------- /example-workflows/api-inmem.yml: -------------------------------------------------------------------------------- 1 | # Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action 2 | # More GitHub Actions for Azure: https://github.com/Azure/actions 3 | 4 | # Deploy Azure Functions Node.js v4 runtime 5 | # with api-inmemory subdir 6 | 7 | name: Azure Function App - api-inmemory 8 | 9 | on: 10 | push: 11 | branches: 12 | - main 13 | paths: 14 | - 'api-inmemory/**' 15 | workflow_dispatch: 16 | 17 | env: 18 | AZURE_FUNCTIONAPP_PACKAGE_PATH: 'api-inmemory' # set this to the path to your web app project, defaults to the repository root 19 | NODE_VERSION: '18.x' # Azure Functions v4 runtime requires 18 20 | VERBOSE: true # For debugging 21 | 22 | jobs: 23 | build-and-deploy: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: 'Checkout GitHub Action' 27 | uses: actions/checkout@v2 28 | 29 | - name: Setup Node ${{ env.NODE_VERSION }} Environment 30 | uses: actions/setup-node@v1 31 | with: 32 | node-version: ${{ env.NODE_VERSION }} 33 | 34 | - name: 'Resolve Project Dependencies Using Npm' 35 | shell: bash 36 | run: | 37 | pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' 38 | npm install 39 | npm run build --if-present 40 | npm run test --if-present 41 | popd 42 | - name: 'Upload artifact for deployment job' # For debugging 43 | uses: actions/upload-artifact@v3 44 | with: 45 | name: azure-function-v4-app 46 | path: | 47 | ${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}} 48 | !${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}/node_modules 49 | !${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}/dist 50 | - name: 'Run Azure Functions Action' 51 | uses: Azure/functions-action@v1 52 | id: fa 53 | with: 54 | app-name: 'swa-api' # change this to your Azure Function app name 55 | slot-name: 'Production' 56 | package: ${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}} 57 | publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_123 }} 58 | scm-do-build-during-deployment: false 59 | enable-oryx-build: false 60 | -------------------------------------------------------------------------------- /example-workflows/app-react-vite.yml: -------------------------------------------------------------------------------- 1 | name: Azure Static Web Apps CI/CD 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'app-react-vite/**' 9 | pull_request: 10 | types: [opened, synchronize, reopened, closed] 11 | branches: 12 | - main 13 | paths: 14 | - 'app-react-vite/**' 15 | workflow_dispatch: 16 | 17 | jobs: 18 | build_and_deploy_job: 19 | if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.action != 'closed') 20 | runs-on: ubuntu-latest 21 | name: Build and Deploy Job 22 | steps: 23 | - uses: actions/checkout@v2 24 | with: 25 | submodules: true 26 | - name: Build And Deploy 27 | id: builddeploy 28 | uses: Azure/static-web-apps-deploy@v1 29 | with: 30 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_DUNE_123 }} 31 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) 32 | action: "upload" 33 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### 34 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig 35 | app_location: "/app-react-vite" # App source code path 36 | api_location: "" # Api source code path - optional 37 | output_location: "dist" # Built app content directory - optional 38 | ###### End of Repository/Build Configurations ###### 39 | env: 40 | VITE_BACKEND_URI: https://swa-api-123.azurewebsites.net 41 | VITE_CLOUD_ENV: production 42 | 43 | close_pull_request_job: 44 | if: github.event_name == 'pull_request' && github.event.action == 'closed' 45 | runs-on: ubuntu-latest 46 | name: Close Pull Request Job 47 | steps: 48 | - name: Close Pull Request 49 | id: closepullrequest 50 | uses: Azure/static-web-apps-deploy@v1 51 | with: 52 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_DUNE_123 }} 53 | action: "close" 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-typescript-e2e-apps", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "build:swa": "swa build", 7 | "login:swa": "swa login", 8 | "deploy:sea": "swa deploy", 9 | "watch": "tsc -w", 10 | "prestart": "npm run build", 11 | "start": "swa start", 12 | "test": "echo \"No tests yet...\"", 13 | "install:functions": "npm install azure-functions-core-tools@4.0.5095 --save-exact --unsafe-perm tru", 14 | "install:swa": "npm install -g @azure/static-web-apps-cli" 15 | }, 16 | "devDependencies": {}, 17 | "workspaces": [ 18 | "lib-openai/", 19 | "cli-openai/" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /quickstarts/ai-agents/README.md: -------------------------------------------------------------------------------- 1 | # Azure AI Agents quickstarts 2 | 3 | Azure AI Agent Service allows you to create AI agents tailored to your needs through custom instructions and augmented by advanced tools like code interpreter, and custom functions. 4 | 5 | * [Quickstart documentation](https://learn.microsoft.com/azure/ai-services/agents/quickstart?pivots=programming-language-typescript) 6 | * [Reference documentation](https://learn.microsoft.com/en-us/javascript/api/@azure/ai-projects/?view=azure-node-preview) 7 | * [@azure/ai-projects](https://www.npmjs.com/package/@azure/ai-projects) 8 | 9 | ## Use the quickstarts 10 | 11 | 1. Verify the [prerequisites](https://learn.microsoft.com/azure/ai-services/agents/quickstart?pivots=programming-language-typescript#prerequisites). 12 | 1. Create resources, as documented in the quickstart. We recommend [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazureai-samples%2Fmain%2Fscenarios%2FAgents%2Fsetup%2Fbasic-agent-identity%2Fazuredeploy.json) to create the resources. Be aware some fields are empty in the deployment template because they are optional. 13 | 1. Rename `sample.env` to `.env` and set your AI project connection string. 14 | 1. In the terminal go to either the JS or TS subfolder. 15 | 16 | ```bash 17 | npm install 18 | npm start 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /quickstarts/ai-agents/js/output.txt: -------------------------------------------------------------------------------- 1 | Type: text 2 | Text: Sure, I can help you solve the equation \(3x + 11 = 14\). 3 | 4 | To solve for \(x\), we need to isolate \(x\) on one side of the equation. Here are the steps: 5 | 6 | 1. Subtract 11 from both sides of the equation: 7 | \[3x + 11 - 11 = 14 - 11\] 8 | \[3x = 3\] 9 | 10 | 2. Divide both sides of the equation by 3: 11 | \[\frac{3x}{3} = \frac{3}{3}\] 12 | \[x = 1\] 13 | 14 | So the solution to the equation \(3x + 11 = 14\) is \(x = 1\). 15 | Type: text 16 | Text: I need to solve the equation `3x + 11 = 14`. Can you help me? -------------------------------------------------------------------------------- /quickstarts/ai-agents/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azureaiagents-js", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "type": "module", 6 | "scripts": { 7 | "start": "node -r dotenv/config src/index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "description": "", 13 | "dependencies": { 14 | "@azure/ai-projects": "^1.0.0-beta.2", 15 | "@azure/core-util": "^1.11.0", 16 | "@azure/identity": "^4.6.0", 17 | "dotenv": "^16.4.7" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^22.9.1", 21 | "prettier": "3.3.3", 22 | "typescript": "^5.6.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /quickstarts/ai-agents/js/sample.env: -------------------------------------------------------------------------------- 1 | PROJECT_CONNECTION_STRING= -------------------------------------------------------------------------------- /quickstarts/ai-agents/ts/output.txt: -------------------------------------------------------------------------------- 1 | Sure! To solve the equation \(3x + 11 = 14\), we need to isolate the variable \(x\). 2 | 3 | Here are the steps: 4 | 5 | 1. Subtract 11 from both sides of the equation: 6 | \[3x + 11 - 11 = 14 - 11\] 7 | 8 | 2. Simplify both sides: 9 | \[3x = 3\] 10 | 11 | 3. Divide both sides by 3: 12 | \[x = \frac{3}{3}\] 13 | 14 | 4. Simplify: 15 | \[x = 1\] 16 | 17 | So, the solution to the equation \(3x + 11 = 14\) is \(x = 1\).Messages: 18 | ---------------------------------------------- 19 | Type: text 20 | Text: Sure! To solve the equation \(3x + 11 = 14\), we need to isolate the variable \(x\). 21 | 22 | Here are the steps: 23 | 24 | 1. Subtract 11 from both sides of the equation: 25 | \[3x + 11 - 11 = 14 - 11\] 26 | 27 | 2. Simplify both sides: 28 | \[3x = 3\] 29 | 30 | 3. Divide both sides by 3: 31 | \[x = \frac{3}{3}\] 32 | 33 | 4. Simplify: 34 | \[x = 1\] 35 | 36 | So, the solution to the equation \(3x + 11 = 14\) is \(x = 1\). 37 | Type: text 38 | Text: I need to solve the equation `3x + 11 = 14`. Can you help me? -------------------------------------------------------------------------------- /quickstarts/ai-agents/ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azureaiagents", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "tsc && node -r dotenv/config dist/index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "description": "", 14 | "dependencies": { 15 | "@azure/ai-projects": "^1.0.0-beta.2", 16 | "@azure/core-util": "^1.11.0", 17 | "@azure/identity": "^4.6.0", 18 | "dotenv": "^16.4.7" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^22.9.1", 22 | "prettier": "3.3.3", 23 | "typescript": "^5.6.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /quickstarts/ai-agents/ts/sample.env: -------------------------------------------------------------------------------- 1 | PROJECT_CONNECTION_STRING= -------------------------------------------------------------------------------- /quickstarts/ai-agents/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "target": "ESNext", 5 | "moduleResolution": "NodeNext", 6 | 7 | "outDir": "dist", 8 | "rootDir": "./src", 9 | 10 | "strict": true, 11 | "noImplicitAny": true, 12 | 13 | "sourceMap": true, 14 | "resolveJsonModule": true, 15 | "esModuleInterop": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } -------------------------------------------------------------------------------- /quickstarts/ai-search/.env.sample: -------------------------------------------------------------------------------- 1 | SEARCH_API_KEY= 2 | SEARCH_API_ENDPOINT= -------------------------------------------------------------------------------- /quickstarts/ai-search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ai-search-full-text-search-quickstart", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "tsc", 8 | "prettier:fix": "prettier --write \"src/**/*.ts\"" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "description": "", 13 | "dependencies": { 14 | "@azure/identity": "^4.3.0", 15 | "@azure/search-documents": "^12.1.0", 16 | "dotenv": "^16.4.5" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20.12.2", 20 | "@typescript-eslint/parser": "^5.62.0", 21 | "eslint": "^8.57.0", 22 | "prettier": "^3.3.3", 23 | "prettier-eslint": "^16.3.0", 24 | "ts-node": "^10.9.2", 25 | "typescript": "^5.4.3" 26 | }, 27 | "prettier": { 28 | "printWidth": 80 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /quickstarts/ai-search/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "target": "ESNext", 5 | "moduleResolution": "NodeNext", 6 | 7 | "outDir": "dist", 8 | "rootDir": "./src", 9 | 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "resolveJsonModule": true, 13 | 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "dist"] 17 | } 18 | -------------------------------------------------------------------------------- /quickstarts/azure-openai-assistants/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-openai-assistants-javascript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type": "module", 6 | "main": "dist/index.js", 7 | "scripts": { 8 | "create-resource": "bash scripts/create-azure-resource.sh", 9 | "build": "tsc", 10 | "start": "node dist/index.js", 11 | "test": "ts-node" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@azure/identity": "^4.0.1", 17 | "openai": "^4.42.0", 18 | "dotenv": "^16.4.5" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /quickstarts/azure-openai-assistants/js/sample.env: -------------------------------------------------------------------------------- 1 | # Used to authenticate using Azure AD as a service principal for role-based 2 | # authentication. 3 | # 4 | # See the documentation for `EnvironmentCredential` at the following link: 5 | # https://docs.microsoft.com/javascript/api/@azure/identity/environmentcredential 6 | # AZURE_TENANT_ID= 7 | # AZURE_CLIENT_ID= 8 | # AZURE_CLIENT_SECRET= 9 | 10 | # Used to authenticate with the Azure OpenAI. Retrieve these 11 | # values from an Azure OpenAI instance in the Azure Portal. 12 | AZURE_OPENAI_KEY= 13 | AZURE_OPENAI_RESOURCE= 14 | AZURE_OPENAI_ENDPOINT=https://.openai.azure.com/ 15 | AZURE_OPENAI_DEPLOYMENT_NAME= 16 | OPENAI_API_VERSION= 17 | -------------------------------------------------------------------------------- /quickstarts/azure-openai-assistants/js/src/index-using-password.mjs: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { AzureOpenAI } from "openai"; 3 | 4 | // Get environment variables 5 | const azureOpenAIKey = process.env.AZURE_OPENAI_KEY; 6 | const azureOpenAIEndpoint = process.env.AZURE_OPENAI_ENDPOINT; 7 | const azureOpenAIDeployment = process.env.AZURE_OPENAI_DEPLOYMENT_NAME; 8 | const azureOpenAIVersion = process.env.OPENAI_API_VERSION; 9 | 10 | // Check env variables 11 | if (!azureOpenAIKey || !azureOpenAIEndpoint || !azureOpenAIDeployment || !azureOpenAIVersion) { 12 | throw new Error( 13 | "Please set AZURE_OPENAI_KEY and AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME in your environment variables." 14 | ); 15 | } 16 | 17 | // Get Azure SDK client 18 | const getClient = () => { 19 | const assistantsClient = new AzureOpenAI({ 20 | endpoint: azureOpenAIEndpoint, 21 | apiVersion: azureOpenAIVersion, 22 | apiKey: azureOpenAIKey, 23 | }); 24 | return assistantsClient; 25 | }; 26 | 27 | const assistantsClient = getClient(); 28 | 29 | const options = { 30 | model: azureOpenAIDeployment, // Deployment name seen in Azure AI Studio 31 | name: "Math Tutor", 32 | instructions: 33 | "You are a personal math tutor. Write and run JavaScript code to answer math questions.", 34 | tools: [{ type: "code_interpreter" }], 35 | }; 36 | const role = "user"; 37 | const message = "I need to solve the equation `3x + 11 = 14`. Can you help me?"; 38 | 39 | // Create an assistant 40 | const assistantResponse = await assistantsClient.beta.assistants.create( 41 | options 42 | ); 43 | console.log(`Assistant created: ${JSON.stringify(assistantResponse)}`); 44 | 45 | // Create a thread 46 | const assistantThread = await assistantsClient.beta.threads.create({}); 47 | console.log(`Thread created: ${JSON.stringify(assistantThread)}`); 48 | 49 | // Add a user question to the thread 50 | const threadResponse = await assistantsClient.beta.threads.messages.create( 51 | assistantThread.id, 52 | { 53 | role, 54 | content: message, 55 | } 56 | ); 57 | console.log(`Message created: ${JSON.stringify(threadResponse)}`); 58 | 59 | // Run the thread and poll it until it is in a terminal state 60 | const runResponse = await assistantsClient.beta.threads.runs.createAndPoll( 61 | assistantThread.id, 62 | { 63 | assistant_id: assistantResponse.id, 64 | }, 65 | { pollIntervalMs: 500 } 66 | ); 67 | console.log(`Run created: ${JSON.stringify(runResponse)}`); 68 | 69 | // Get the messages 70 | const runMessages = await assistantsClient.beta.threads.messages.list( 71 | assistantThread.id 72 | ); 73 | for await (const runMessageDatum of runMessages) { 74 | for (const item of runMessageDatum.content) { 75 | // types are: "image_file" or "text" 76 | if (item.type === "text") { 77 | console.log(`Message content: ${JSON.stringify(item.text?.value)}`); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /quickstarts/azure-openai-assistants/ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azure-openai-assistants-typescript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type": "module", 6 | "main": "dist/index.js", 7 | "scripts": { 8 | "create-resource": "bash scripts/create-azure-resource.sh", 9 | "build": "tsc", 10 | "start": "node dist/index.js", 11 | "test": "ts-node" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@azure/identity": "^4.0.1", 17 | "openai": "^4.42.0", 18 | "dotenv": "^16.4.5" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^20.12.2", 22 | "ts-node": "^10.9.2", 23 | "typescript": "^5.4.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /quickstarts/azure-openai-assistants/ts/sample.env: -------------------------------------------------------------------------------- 1 | # Used to authenticate using Azure AD as a service principal for role-based 2 | # authentication. 3 | # 4 | # See the documentation for `EnvironmentCredential` at the following link: 5 | # https://docs.microsoft.com/javascript/api/@azure/identity/environmentcredential 6 | # AZURE_TENANT_ID= 7 | # AZURE_CLIENT_ID= 8 | # AZURE_CLIENT_SECRET= 9 | 10 | # Used to authenticate with the Azure OpenAI. Retrieve these 11 | # values from an Azure OpenAI instance in the Azure Portal. 12 | AZURE_OPENAI_KEY= 13 | AZURE_OPENAI_RESOURCE= 14 | AZURE_OPENAI_ENDPOINT=https://.openai.azure.com/ 15 | AZURE_OPENAI_DEPLOYMENT_NAME= 16 | OPENAI_API_VERSION= 17 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Connect to and query Azure SQL Database using Node.js and mssql npm package 3 | description: Learn how to connect to a database in Azure SQL Database and query data using Node.js and mssql npm package. 4 | page_type: sample 5 | languages: 6 | - javascript 7 | - typescript 8 | products: 9 | - azure-app-service 10 | - azure-sql-database 11 | --- 12 | 13 | # Connect to and query Azure SQL Database using Node.js and mssql 14 | 15 | Learn how to connect to a database in Azure SQL Database and query data using Node.js and mssql npm package. 16 | 17 | * [Quickstart in official documentation](https://learn.microsoft.com/azure/azure-sql/database/azure-sql-javascript-mssql-quickstart) 18 | 19 | Samples provided include: 20 | 21 | * [JavaScript ESM](./js) 22 | * [TypeScript ESM](./ts) 23 | * [Create Azure resource to be used with passwords](./create-resources.sh) 24 | * [Create SQL table](#set-up) 25 | 26 | ## Set up 27 | 28 | 1. Create the table in Azure SQL: 29 | 30 | ```sql 31 | SET ANSI_NULLS ON 32 | GO 33 | 34 | SET QUOTED_IDENTIFIER ON 35 | GO 36 | 37 | CREATE TABLE [dbo].[Person]( 38 | [id] [int] IDENTITY(1,1) NOT NULL, 39 | [firstName] [nvarchar](255) NULL, 40 | [lastName] [nvarchar](255) NULL 41 | PRIMARY KEY CLUSTERED 42 | ( 43 | [id] ASC 44 | )WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] 45 | ) ON [PRIMARY] 46 | 47 | GO 48 | 49 | INSERT INTO [dbo].[Person] 50 | ([firstName] 51 | ,[lastName]) 52 | VALUES 53 | ('Willam' 54 | ,'Jones') 55 | GO 56 | ``` 57 | 58 | 59 | 1. Install dependencies: 60 | 61 | ``` 62 | npm install 63 | ``` 64 | 65 | 1. Create `.env.development` and set the environment variables: 66 | 67 | ``` 68 | AZURE_SQL_SERVER=.database.windows.net 69 | AZURE_SQL_DATABASE= 70 | AZURE_SQL_PORT=1433 71 | # Passwordless 72 | # AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default 73 | # With password 74 | AZURE_SQL_USER= 75 | AZURE_SQL_PASSWORD= 76 | ``` 77 | 78 | 1. In `person.js`, verify or set which configuration you want: 79 | 80 | * `const database = await createDatabaseConnection(SQLAuthentication);` 81 | * `const database = await createDatabaseConnection(PasswordlessConfig);` 82 | 83 | 84 | 1. Start the app: 85 | 86 | ``` 87 | NODE_ENV=development node index.js 88 | ``` 89 | 90 | ![App Screenshot](./media/azure-sql-openapi-screenshot.png) -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/create-resources.sh: -------------------------------------------------------------------------------- 1 | subscription="de0e88c4-ba0d-4910-bd9d-9e59573c59e6" # add subscription here 2 | 3 | az account set -s $subscription # ...or use 'az login' 4 | 5 | # Variable block 6 | let "randomIdentifier=$RANDOM*$RANDOM" 7 | location="East US" 8 | resourceGroup="msdocs-azuresql-rg-$randomIdentifier" 9 | tag="create-and-configure-database" 10 | server="msdocs-azuresql-server-$randomIdentifier" 11 | database="msdocsazuresqldb$randomIdentifier" 12 | login="azureuser" 13 | password="Pa$$w0rD-$randomIdentifier" 14 | # Specify appropriate IP address values for your environment 15 | # to limit access to the SQL Database server 16 | startIp=76.22.73.183 17 | endIp=76.22.73.183 18 | 19 | echo "Using resource group $resourceGroup with login: $login, password: $password..." 20 | 21 | echo "Creating $resourceGroup in $location..." 22 | az group create --name $resourceGroup --location "$location" --tags $tag 23 | 24 | echo "Creating $server in $location..." 25 | az sql server create --name $server --resource-group $resourceGroup --location "$location" --admin-user $login --admin-password $password 26 | 27 | echo "Configuring firewall..." 28 | az sql server firewall-rule create --resource-group $resourceGroup --server $server -n AllowYourIp --start-ip-address $startIp --end-ip-address $endIp 29 | 30 | echo "Creating $database in serverless tier" 31 | az sql db create --resource-group $resourceGroup --server $server --name $database --sample-name AdventureWorksLT --edition GeneralPurpose --compute-model Serverless --family Gen5 --capacity 2 32 | 33 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | .env.test 64 | .env.development 65 | 66 | # parcel-bundler cache (https://parceljs.org/) 67 | .cache 68 | 69 | # next.js build output 70 | .next 71 | 72 | # nuxt.js build output 73 | .nuxt 74 | 75 | # vuepress build output 76 | .vuepress/dist 77 | 78 | # Serverless directories 79 | .serverless/ 80 | 81 | # FuseBox cache 82 | .fusebox/ 83 | 84 | # DynamoDB Local files 85 | .dynamodb/ 86 | 87 | # TypeScript output 88 | dist 89 | out 90 | 91 | # Azure Functions artifacts 92 | bin 93 | obj 94 | appsettings.json 95 | local.settings.json 96 | 97 | # Azurite artifacts 98 | __blobstorage__ 99 | __queuestorage__ 100 | __azurite_db*__.json -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | dist 3 | build 4 | coverage -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma":"none" 7 | } -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch via NPM", 9 | "request": "launch", 10 | "runtimeArgs": [ 11 | "run-script", 12 | "dev" 13 | ], 14 | "runtimeExecutable": "npm", 15 | "skipFiles": [ 16 | "/**" 17 | ], 18 | "type": "node" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: 4 | - javascript 5 | - typescript 6 | - nodejs 7 | products: 8 | - azure-app-service 9 | - azure-sql 10 | --- 11 | 12 | # Express.js with OpenAPI with Azure SQL (JavaScript) 13 | 14 | * /users 15 | * /api-docs 16 | 17 | ## App Service app settings 18 | 19 | When you use the Azure CLI service connector to add a system-assigned identity between the App Service and the Azure SQL server, the process creates 4 environment variables in the App Service: 20 | 21 | * Don't change the environment variable names 22 | * Use the environment variables in the **mssql** configuration object 23 | 24 | ```bash 25 | AZURE_SQL_SERVER=SERVER.database.windows.net 26 | AZURE_SQL_DATABASE=mySampleDatabase 27 | AZURE_SQL_PORT=1433 28 | AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default 29 | ``` 30 | 31 | ## Passwordless config 32 | 33 | ```javascript 34 | // ./src/config.ts 35 | export const passwordlessConfiguration = { 36 | server: process.env.AZURE_SQL_SERVER, 37 | port: +process.env.AZURE_SQL_PORT, 38 | database: process.env.AZURE_SQL_DATABASE, 39 | authentication: { 40 | type: process.env.AZURE_SQL_AUTHENTICATIONTYPE, 41 | }, 42 | options: { 43 | encrypt: true // for Azure users 44 | } 45 | }; 46 | ``` 47 | ## Troubleshooting 48 | 49 | ### Local development 50 | 51 | * Use [mssql-no-password.js](mssql-no-password.js) to verify you can connect to the database 52 | * If you connect through a VPN or Proxy, make sure that IP address is allowed in the Azure SQL firewall. 53 | 54 | ### Azure App Service 55 | 56 | * Passwords: 57 | * Add environment variables to App Service 58 | * Use [SQL script to create user with roles](./scripts/create-azure-sql-user.sql) 59 | * No Passwords: 60 | Use [Azure CLI service connector script](./scripts/create-service-connector-connection.sh) -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/config.js: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | 3 | if(process.env.NODE_ENV === 'development') { 4 | dotenv.config({ path: `.env.${process.env.NODE_ENV}`, debug: true }); 5 | } 6 | 7 | // TIP: Port must be a number, not a string! 8 | const server = process.env.AZURE_SQL_SERVER; 9 | const database = process.env.AZURE_SQL_DATABASE; 10 | const port = +process.env.AZURE_SQL_PORT; 11 | const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE; 12 | const user = process.env.AZURE_SQL_USER; 13 | const password = process.env.AZURE_SQL_PASSWORD; 14 | 15 | export const noPasswordConfig = { 16 | server, 17 | port, 18 | database, 19 | authentication: { 20 | type 21 | }, 22 | options: { 23 | encrypt: true 24 | } 25 | }; 26 | 27 | export const passwordConfig = { 28 | server, 29 | port, 30 | database, 31 | user, 32 | password, 33 | options: { 34 | encrypt: true 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | // Import App routes 4 | import person from './person.js'; 5 | import openapi from './openapi.js'; 6 | 7 | const port = process.env.PORT || 3000; 8 | 9 | const app = express(); 10 | 11 | // Connect App routes 12 | app.use('/api-docs', openapi); 13 | app.use('/persons', person); 14 | app.use('*', (_, res) => { 15 | res.redirect('/api-docs'); 16 | }); 17 | 18 | // Start the server 19 | app.listen(port, () => { 20 | console.log(`Server started on port ${port}`); 21 | }); 22 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/mssql-no-password.js: -------------------------------------------------------------------------------- 1 | import sql from 'mssql'; 2 | import * as dotenv from 'dotenv'; 3 | dotenv.config({ path: `.env.development`, debug: true }); 4 | 5 | const server = process.env.AZURE_SQL_SERVER; 6 | const database = process.env.AZURE_SQL_DATABASE; 7 | const port = +process.env.AZURE_SQL_PORT; 8 | const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE; 9 | const user = process.env.AZURE_SQL_USER; 10 | const password = process.env.AZURE_SQL_PASSWORD; 11 | 12 | const passwordConfig = { 13 | server, 14 | port, 15 | database, 16 | user, 17 | password, 18 | options: { 19 | encrypt: true 20 | } 21 | }; 22 | const noPasswordConfig = { 23 | server, 24 | port, 25 | database, 26 | authentication: { 27 | type 28 | }, 29 | options: { 30 | encrypt: true 31 | } 32 | }; 33 | 34 | const getAllPersons = `select * from [dbo].[Person]`; 35 | 36 | const myQuery = async () => { 37 | const config = passwordConfig; 38 | 39 | var poolConnection = await sql.connect(config); 40 | const result = await poolConnection.request().query(getAllPersons); 41 | console.log(`Result: ${JSON.stringify(result)}`); 42 | poolConnection.close(); 43 | return; 44 | }; 45 | 46 | myQuery() 47 | .then(() => console.log('done')) 48 | .catch((err) => console.log(err)); 49 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/openApiSchema.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Persons API 5 | paths: 6 | /persons: 7 | get: 8 | summary: Get all persons 9 | responses: 10 | '200': 11 | description: OK 12 | content: 13 | application/json: 14 | schema: 15 | type: array 16 | items: 17 | $ref: '#/components/schemas/Person' 18 | post: 19 | summary: Create a new person 20 | requestBody: 21 | required: true 22 | content: 23 | application/json: 24 | schema: 25 | $ref: '#/components/schemas/Person' 26 | responses: 27 | '201': 28 | description: Created 29 | content: 30 | application/json: 31 | schema: 32 | $ref: '#/components/schemas/Person' 33 | /persons/{id}: 34 | parameters: 35 | - name: id 36 | in: path 37 | required: true 38 | schema: 39 | type: integer 40 | get: 41 | summary: Get a person by ID 42 | responses: 43 | '200': 44 | description: OK 45 | content: 46 | application/json: 47 | schema: 48 | $ref: '#/components/schemas/Person' 49 | '404': 50 | description: Person not found 51 | put: 52 | summary: Update a person by ID 53 | requestBody: 54 | required: true 55 | content: 56 | application/json: 57 | schema: 58 | $ref: '#/components/schemas/Person' 59 | responses: 60 | '200': 61 | description: OK 62 | content: 63 | application/json: 64 | schema: 65 | $ref: '#/components/schemas/Person' 66 | '404': 67 | description: Person not found 68 | delete: 69 | summary: Delete a person by ID 70 | responses: 71 | '204': 72 | description: No Content 73 | '404': 74 | description: Person not found 75 | components: 76 | schemas: 77 | Person: 78 | type: object 79 | properties: 80 | id: 81 | type: integer 82 | readOnly: true 83 | firstName: 84 | type: string 85 | lastName: 86 | type: string -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/openapi.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import { join, dirname } from 'path'; 3 | import swaggerUi from 'swagger-ui-express'; 4 | import yaml from 'yamljs'; 5 | import { fileURLToPath } from 'url'; 6 | 7 | const __dirname = dirname(fileURLToPath(import.meta.url)); 8 | 9 | const router = express.Router(); 10 | router.use(express.json()); 11 | 12 | const pathToSpec = join(__dirname, './openApiSchema.yml'); 13 | const openApiSpec = yaml.load(pathToSpec); 14 | 15 | router.use('/', swaggerUi.serve, swaggerUi.setup(openApiSpec)); 16 | 17 | export default router; 18 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-expressjs-openapi-azuresql", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type":"module", 6 | "main": "dist/index", 7 | "scripts": { 8 | "format": "prettier --write *.js", 9 | "dev": "cross-env NODE_ENV=development DEBUG=express:* node index.js", 10 | "start": "node index.js" 11 | }, 12 | "dependencies": { 13 | "express": "^4.17.21", 14 | "mssql": "^11.0.1", 15 | "swagger-ui-express": "^5.0.1", 16 | "yamljs": "^0.3.0" 17 | }, 18 | "devDependencies": { 19 | "cross-env": "^7.0.3", 20 | "dotenv": "^16.0.3", 21 | "prettier": "^3.3.3", 22 | "eslint": "^8.40.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/person.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import { 3 | passwordConfig as SQLAuthentication, 4 | noPasswordConfig as PasswordlessConfig 5 | } from './config.js'; 6 | import { createDatabaseConnection } from './database.js'; 7 | 8 | const router = express.Router(); 9 | router.use(express.json()); 10 | 11 | const database = await createDatabaseConnection(SQLAuthentication); 12 | 13 | router.get('/', async (req, res) => { 14 | try { 15 | // Return a list of persons 16 | 17 | const persons = await database.readAll(); 18 | console.log(`persons: ${JSON.stringify(persons)}`); 19 | res.status(200).json(persons); 20 | } catch (err) { 21 | res.status(500).json({ error: err?.message }); 22 | } 23 | }); 24 | 25 | router.post('/', async (req, res) => { 26 | try { 27 | // add a person 28 | const person = req.body; 29 | console.log(`person: ${JSON.stringify(person)}`); 30 | const rowsAffected = await database.create(person); 31 | res.status(201).json({ rowsAffected }); 32 | } catch (err) { 33 | res.status(500).json({ error: err?.message }); 34 | } 35 | }); 36 | 37 | router.get('/:id', async (req, res) => { 38 | try { 39 | // Get the person with the specified ID 40 | const personId = req.params.id; 41 | console.log(`personId: ${personId}`); 42 | if (personId) { 43 | const result = await database.read(personId); 44 | console.log(`persons: ${JSON.stringify(result)}`); 45 | res.status(200).json(result); 46 | } else { 47 | res.status(404); 48 | } 49 | } catch (err) { 50 | res.status(500).json({ error: err?.message }); 51 | } 52 | }); 53 | 54 | router.put('/:id', async (req, res) => { 55 | try { 56 | // Update the person with the specified ID 57 | const personId = req.params.id; 58 | console.log(`personId: ${personId}`); 59 | const person = req.body; 60 | 61 | if (personId && person) { 62 | delete person.id; 63 | console.log(`person: ${JSON.stringify(person)}`); 64 | const rowsAffected = await database.update(personId, person); 65 | res.status(200).json({ rowsAffected }); 66 | } else { 67 | res.status(404); 68 | } 69 | } catch (err) { 70 | res.status(500).json({ error: err?.message }); 71 | } 72 | }); 73 | 74 | router.delete('/:id', async (req, res) => { 75 | try { 76 | // Delete the person with the specified ID 77 | const personId = req.params.id; 78 | console.log(`personId: ${personId}`); 79 | 80 | if (!personId) { 81 | res.status(404); 82 | } else { 83 | const rowsAffected = await database.delete(personId); 84 | res.status(204).json({ rowsAffected }); 85 | } 86 | } catch (err) { 87 | res.status(500).json({ error: err?.message }); 88 | } 89 | }); 90 | 91 | export default router; 92 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/sample.env: -------------------------------------------------------------------------------- 1 | AZURE_SQL_SERVER=.database.windows.net 2 | AZURE_SQL_DATABASE= 3 | AZURE_SQL_PORT=1433 4 | # Passwordless 5 | # AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default 6 | # With password 7 | AZURE_SQL_USER= 8 | AZURE_SQL_PASSWORD= 9 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/scripts/create-service-connector-connection.sh: -------------------------------------------------------------------------------- 1 | az webapp connection create sql 2 | -g 3 | -n 4 | --tg 5 | --server 6 | --database 7 | --system-identity -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/sql/create-azure-sql-user.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE USER FROM EXTERNAL PROVIDER; 3 | ALTER ROLE db_datareader ADD MEMBER ; 4 | ALTER ROLE db_datawriter ADD MEMBER ; 5 | ALTER ROLE db_ddladmin ADD MEMBER ; 6 | GO -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/js/sql/create-table.sql: -------------------------------------------------------------------------------- 1 | SET ANSI_NULLS ON 2 | GO 3 | 4 | SET QUOTED_IDENTIFIER ON 5 | GO 6 | 7 | CREATE TABLE [dbo].[Person]( 8 | [id] [int] IDENTITY(1,1) NOT NULL, 9 | [firstName] [nvarchar](255) NULL, 10 | [lastName] [nvarchar](255) NULL 11 | PRIMARY KEY CLUSTERED 12 | ( 13 | [id] ASC 14 | )WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] 15 | ) ON [PRIMARY] 16 | 17 | GO 18 | 19 | INSERT INTO [dbo].[Person] 20 | ([firstName] 21 | ,[lastName]) 22 | VALUES 23 | ('Willam' 24 | ,'Jones') 25 | GO -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/media/azure-sql-openapi-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-typescript-e2e-apps/e3b9c39fbb85c6cc3eeef8702ec9607163f88919/quickstarts/azure-sql/connect-and-query/media/azure-sql-openapi-screenshot.png -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | ./jest.config.ts -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint", 6 | "prettier" 7 | ], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "prettier" 13 | ], 14 | "rules": { 15 | "no-console": 0, // Means warning 16 | "prettier/prettier": 2 // Means error 17 | } 18 | } -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | .env.test 64 | 65 | # parcel-bundler cache (https://parceljs.org/) 66 | .cache 67 | 68 | # next.js build output 69 | .next 70 | 71 | # nuxt.js build output 72 | .nuxt 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless/ 79 | 80 | # FuseBox cache 81 | .fusebox/ 82 | 83 | # DynamoDB Local files 84 | .dynamodb/ 85 | 86 | # TypeScript output 87 | dist 88 | out 89 | 90 | # Azure Functions artifacts 91 | bin 92 | obj 93 | appsettings.json 94 | local.settings.json 95 | 96 | # Azurite artifacts 97 | __blobstorage__ 98 | __queuestorage__ 99 | __azurite_db*__.json -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "singleQuote": true, 5 | "printWidth": 80 6 | } -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: 4 | - javascript 5 | - typescript 6 | - nodejs 7 | products: 8 | - azure-app-service 9 | - azure-sql 10 | --- 11 | 12 | # Express.js with OpenAPI with Azure SQL (TypeScript) 13 | 14 | * /users 15 | * /api-docs 16 | 17 | ## App Service app settings 18 | 19 | When you use the Azure CLI service connector to add a system-assigned identity between the App Service and the Azure SQL server, the process creates 4 environment variables in the App Service: 20 | 21 | * Don't change the environment variable names 22 | * Use the environment variables in the **mssql** configuration object 23 | 24 | ```bash 25 | AZURE_SQL_SERVER=SERVER.database.windows.net 26 | AZURE_SQL_DATABASE=mySampleDatabase 27 | AZURE_SQL_PORT=1433 28 | AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default 29 | ``` 30 | 31 | ## Passwordless config 32 | 33 | ```javascript 34 | // ./src/config.ts 35 | export const passwordlessConfiguration = { 36 | server: process.env.AZURE_SQL_SERVER, 37 | port: +process.env.AZURE_SQL_PORT, 38 | database: process.env.AZURE_SQL_DATABASE, 39 | authentication: { 40 | type: process.env.AZURE_SQL_AUTHENTICATIONTYPE, 41 | }, 42 | options: { 43 | encrypt: true // for Azure users 44 | } 45 | }; 46 | ``` 47 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/mssql-no-password.js: -------------------------------------------------------------------------------- 1 | const sql = require('mssql') 2 | require('dotenv').config({ debug: true }) 3 | 4 | const server = process.env.AZURE_SQL_SERVER; 5 | const database = process.env.AZURE_SQL_DATABASE; 6 | const port = +process.env.AZURE_SQL_PORT; 7 | const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE; 8 | const user = process.env.AZURE_SQL_USER; 9 | const password = process.env.AZURE_SQL_PASSWORD; 10 | 11 | const passwordConfig = { 12 | server, 13 | port, 14 | database, 15 | user, 16 | password, 17 | options: { 18 | encrypt: true 19 | } 20 | } 21 | const noPasswordConfig = { 22 | server, 23 | port, 24 | database, 25 | authentication: { 26 | type 27 | }, 28 | options: { 29 | encrypt: true 30 | } 31 | } 32 | 33 | 34 | const getAllPersons = `select * from [dbo].[Users]`; 35 | 36 | const myQuery = async () => { 37 | 38 | const config = noPasswordConfig; 39 | 40 | var poolConnection = await sql.connect(config); 41 | const result = await poolConnection.request().query(getAllPersons) 42 | console.log(`Result: ${JSON.stringify(result)}`) 43 | poolConnection.close(); 44 | return; 45 | } 46 | 47 | myQuery().then(() => console.log('done')).catch(err => console.log(err)) -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-expressjs-openapi-azuresql", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/app", 6 | "type":"module", 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development DEBUG=express:* node dist/index.js", 9 | "build": "echo 'build api-expressjs-openapi-azuresql' && tsc && cp ./src/openApiSchema.yml dist/", 10 | "watch": "tsc -w", 11 | "prestart": "rm -rf dist && npm run build", 12 | "start": "cross-env NODE_ENV=development node ./dist/index.js", 13 | 14 | "format": "prettier --write src/**/*.ts", 15 | "lint": "eslint src/**/*.ts --fix" 16 | }, 17 | "dependencies": { 18 | "dotenv": "^16.0.3", 19 | "express": "^4.17.21", 20 | "mssql": "^11.0.1", 21 | "swagger-ui-express": "^5.0.1", 22 | "yamljs": "^0.3.0" 23 | }, 24 | "devDependencies": { 25 | "@types/express": "^4.17.21", 26 | "@types/mssql": "^9.1.5", 27 | "@types/node": "^22.7.4", 28 | "cross-env": "^7.0.3", 29 | "typescript": "^5.0.4", 30 | "@typescript-eslint/eslint-plugin": "^5.59.6", 31 | "eslint": "^8.40.0", 32 | "eslint-config-prettier": "^8.8.0", 33 | "eslint-plugin-prettier": "^4.2.1", 34 | "prettier": "^2.8.8" 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/sample.env: -------------------------------------------------------------------------------- 1 | AZURE_SQL_SERVER=.database.windows.net 2 | AZURE_SQL_DATABASE= 3 | AZURE_SQL_PORT=1433 4 | # Passwordless 5 | # AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default 6 | # With password 7 | AZURE_SQL_USER= 8 | AZURE_SQL_PASSWORD= 9 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/scripts/create-service-connector-connection.sh: -------------------------------------------------------------------------------- 1 | az webapp connection create sql 2 | -g 3 | -n 4 | --tg 5 | --server 6 | --database 7 | --system-identity -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/sql/create-azure-sql-user.sql: -------------------------------------------------------------------------------- 1 | CREATE USER FROM EXTERNAL PROVIDER; 2 | ALTER ROLE db_datareader ADD MEMBER ; 3 | ALTER ROLE db_datawriter ADD MEMBER ; 4 | ALTER ROLE db_ddladmin ADD MEMBER ; 5 | GO -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/sql/create-table.sql: -------------------------------------------------------------------------------- 1 | SET ANSI_NULLS ON 2 | GO 3 | 4 | SET QUOTED_IDENTIFIER ON 5 | GO 6 | 7 | CREATE TABLE [dbo].[Person]( 8 | [id] [int] IDENTITY(1,1) NOT NULL, 9 | [firstName] [nvarchar](255) NULL, 10 | [lastName] [nvarchar](255) NULL 11 | PRIMARY KEY CLUSTERED 12 | ( 13 | [id] ASC 14 | )WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] 15 | ) ON [PRIMARY] 16 | 17 | GO 18 | 19 | INSERT INTO [dbo].[Person] 20 | ([firstName] 21 | ,[lastName]) 22 | VALUES 23 | ('Willam' 24 | ,'Jones') 25 | GO -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/src/config.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | if(process.env.NODE_ENV === 'development') { 3 | dotenv.config({ path: `.env.${process.env.NODE_ENV}`, debug: true }); 4 | } 5 | /* 6 | 7 | Example .env file: 8 | 9 | AZURE_SQL_SERVER=SERVER.database.windows.net 10 | AZURE_SQL_DATABASE=mySampleDatabase 11 | AZURE_SQL_PORT=1433 12 | AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default 13 | AZURE_SQL_USER= 14 | AZURE_SQL_PASSWORD= 15 | 16 | */ 17 | 18 | // 19 | 20 | // TIP: Port must be a number, not a string! 21 | 22 | const server = process.env.AZURE_SQL_SERVER; 23 | const database = process.env.AZURE_SQL_DATABASE; 24 | const port = +process.env.AZURE_SQL_PORT; 25 | const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE; 26 | const user = process.env.AZURE_SQL_USER; 27 | const password = process.env.AZURE_SQL_PASSWORD; 28 | 29 | export const noPasswordConfig = { 30 | server, 31 | port, 32 | database, 33 | authentication: { 34 | type 35 | }, 36 | options: { 37 | encrypt: true 38 | } 39 | }; 40 | // 41 | 42 | export const passwordConfig = { 43 | server, 44 | port, 45 | database, 46 | user, 47 | password, 48 | options: { 49 | encrypt: true 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/src/index.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | // Import App routes 4 | import person from './routes/person.js'; 5 | import openapi from './routes/openapi.js'; 6 | 7 | const port = process.env.PORT || 3000; 8 | 9 | const app = express(); 10 | 11 | // Connect App routes 12 | app.use('/api-docs', openapi); 13 | app.use('/persons', person); 14 | app.use('*', (_, res) => { 15 | res.redirect('/api-docs'); 16 | }); 17 | 18 | // Start the server 19 | app.listen(port, () => { 20 | console.log(`Server started on port ${port}`); 21 | }); 22 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/src/openApiSchema.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Persons API 5 | paths: 6 | /persons: 7 | get: 8 | summary: Get all persons 9 | responses: 10 | '200': 11 | description: OK 12 | content: 13 | application/json: 14 | schema: 15 | type: array 16 | items: 17 | $ref: '#/components/schemas/Person' 18 | post: 19 | summary: Create a new person 20 | requestBody: 21 | required: true 22 | content: 23 | application/json: 24 | schema: 25 | $ref: '#/components/schemas/Person' 26 | responses: 27 | '201': 28 | description: Created 29 | content: 30 | application/json: 31 | schema: 32 | $ref: '#/components/schemas/Person' 33 | /persons/{id}: 34 | parameters: 35 | - name: id 36 | in: path 37 | required: true 38 | schema: 39 | type: integer 40 | get: 41 | summary: Get a person by ID 42 | responses: 43 | '200': 44 | description: OK 45 | content: 46 | application/json: 47 | schema: 48 | $ref: '#/components/schemas/Person' 49 | '404': 50 | description: Person not found 51 | put: 52 | summary: Update a person by ID 53 | requestBody: 54 | required: true 55 | content: 56 | application/json: 57 | schema: 58 | $ref: '#/components/schemas/Person' 59 | responses: 60 | '200': 61 | description: OK 62 | content: 63 | application/json: 64 | schema: 65 | $ref: '#/components/schemas/Person' 66 | '404': 67 | description: Person not found 68 | delete: 69 | summary: Delete a person by ID 70 | responses: 71 | '204': 72 | description: No Content 73 | '404': 74 | description: Person not found 75 | components: 76 | schemas: 77 | Person: 78 | type: object 79 | properties: 80 | id: 81 | type: integer 82 | readOnly: true 83 | firstName: 84 | type: string 85 | lastName: 86 | type: string -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/src/routes/openapi.ts: -------------------------------------------------------------------------------- 1 | import express, { Router } from 'express'; 2 | import path from 'path'; 3 | import { fileURLToPath } from 'url'; 4 | import swaggerUi from 'swagger-ui-express'; 5 | import yaml from 'yamljs'; 6 | 7 | // Convert import.meta.url to __dirname equivalent 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | 11 | const router: Router = express.Router(); 12 | router.use(express.json()); 13 | 14 | const pathToSpec = path.join(__dirname, '../openApiSchema.yml'); 15 | const openApiSpec = yaml.load(pathToSpec); 16 | 17 | router.use('/', swaggerUi.serve, swaggerUi.setup(openApiSpec)); 18 | 19 | export default router; 20 | -------------------------------------------------------------------------------- /quickstarts/azure-sql/connect-and-query/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "target": "ESNext", 5 | "moduleResolution": "NodeNext", 6 | 7 | "outDir": "dist", 8 | "rootDir": "./src", 9 | "esModuleInterop": true 10 | } 11 | } -------------------------------------------------------------------------------- /quickstarts/key-vault/.env.sample: -------------------------------------------------------------------------------- 1 | KEY_VAULT_URL=https://.vault.azure.net/ -------------------------------------------------------------------------------- /quickstarts/key-vault/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | ./jest.config.ts -------------------------------------------------------------------------------- /quickstarts/key-vault/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint", 6 | "prettier" 7 | ], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "prettier" 13 | ], 14 | "rules": { 15 | "no-console": 1, // Means warning 16 | "prettier/prettier": 2 // Means error 17 | } 18 | } -------------------------------------------------------------------------------- /quickstarts/key-vault/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "singleQuote": true, 5 | "printWidth": 80 6 | } -------------------------------------------------------------------------------- /quickstarts/key-vault/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "key-vault-quickstart", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "scripts": { 6 | "build": "npm run clean && npm run format && npm run lint && npm run build:tsc", 7 | "format": "prettier --write src/**/*.ts", 8 | "lint": "eslint src/**/*.ts --fix", 9 | "build:tsc": "tsc", 10 | "clean": "rm -rf dist" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "description": "", 15 | "dependencies": { 16 | "@azure/identity": "^4.4.0", 17 | "@azure/keyvault-certificates": "^4.8.0", 18 | "@azure/keyvault-keys": "^4.8.0", 19 | "@azure/keyvault-secrets": "^4.8.0", 20 | "dotenv": "^16.4.5" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^20.12.2", 24 | "@typescript-eslint/eslint-plugin": "^5.59.6", 25 | "eslint": "^8.40.0", 26 | "eslint-config-prettier": "^8.8.0", 27 | "eslint-plugin-prettier": "^4.2.1", 28 | "prettier": "^2.8.8", 29 | "wtfnode": "^0.9.1", 30 | "ts-node": "^10.9.2", 31 | "typescript": "^5.4.3" 32 | }, 33 | "prettier": { 34 | "printWidth": 80 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /quickstarts/key-vault/src/secrets.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SecretClient, 3 | KeyVaultSecret, 4 | SecretProperties, 5 | } from "@azure/keyvault-secrets"; 6 | import { DefaultAzureCredential } from "@azure/identity"; 7 | import "dotenv/config"; 8 | 9 | // Passwordless credential 10 | const credential = new DefaultAzureCredential(); 11 | 12 | // Get Key Vault name from environment variables 13 | // such as `https://${keyVaultName}.vault.azure.net` 14 | const keyVaultUrl = process.env.KEY_VAULT_URL; 15 | if (!keyVaultUrl) throw new Error("KEY_VAULT_URL is empty"); 16 | 17 | function printSecret(secret: KeyVaultSecret): void { 18 | const { name, value, properties } = secret; 19 | const { enabled, expiresOn, createdOn } = properties; 20 | console.log("Secret: ", { name, value, enabled, expiresOn, createdOn }); 21 | } 22 | function printSecretProperties(secret: SecretProperties): void { 23 | const { name, enabled, expiresOn, createdOn } = secret; 24 | console.log("Secret: ", { name, enabled, expiresOn, createdOn }); 25 | } 26 | 27 | async function main(): Promise { 28 | // Create a new SecretClient 29 | const client = new SecretClient(keyVaultUrl, credential); 30 | 31 | // Create a unique secret name 32 | const uniqueString = new Date().getTime().toString(); 33 | const secretName = `secret${uniqueString}`; 34 | 35 | // Create a secret 36 | const createSecretResult = await client.setSecret( 37 | secretName, 38 | "MySecretValue" 39 | ); 40 | printSecret(createSecretResult); 41 | 42 | // Get the secret by name 43 | const getSecretResult = await client.getSecret(secretName); 44 | printSecret(getSecretResult); 45 | 46 | // Update properties 47 | const updatedSecret = await client.updateSecretProperties( 48 | secretName, 49 | getSecretResult.properties.version, 50 | { 51 | enabled: false, 52 | } 53 | ); 54 | printSecretProperties(updatedSecret); 55 | 56 | // Delete secret (without immediate purge) 57 | const deletePoller = await client.beginDeleteSecret(secretName); 58 | await deletePoller.pollUntilDone(); 59 | } 60 | 61 | main().catch((error) => { 62 | console.error("An error occurred:", error); 63 | process.exit(1); 64 | }); 65 | -------------------------------------------------------------------------------- /quickstarts/key-vault/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "target": "ESNext", 5 | "moduleResolution": "NodeNext", 6 | 7 | "outDir": "dist", 8 | "rootDir": "./src", 9 | 10 | "esModuleInterop": true, 11 | "skipLibCheck": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | -------------------------------------------------------------------------------- /quickstarts/openai/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | ./jest.config.ts -------------------------------------------------------------------------------- /quickstarts/openai/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint", 6 | "prettier" 7 | ], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "prettier" 13 | ], 14 | "rules": { 15 | "no-console": 0, // Means warning 16 | "prettier/prettier": 2 // Means error 17 | } 18 | } -------------------------------------------------------------------------------- /quickstarts/openai/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "singleQuote": true, 5 | "printWidth": 80 6 | } -------------------------------------------------------------------------------- /quickstarts/openai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "completions", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "completion-key": "ts-node src/completion-key.ts", 7 | "chat-key": "ts-node src/chat-key.ts", 8 | "vision-key": "ts-node src/vision-key.ts", 9 | "dall-e-key": "ts-node src/dall-e.ts", 10 | "text-to-speech-key": "ts-node src/text-to-speech-key.ts", 11 | "use-your-data-key": "ts-node src/use-your-data-key.ts", 12 | "whisper-key": "ts-node src/whisper-key.ts", 13 | 14 | "completion-no-key": "ts-node src/completion-no-key.ts", 15 | "chat-no-key": "ts-node src/chat-no-key.ts", 16 | 17 | 18 | "build": "npm run clean && npm run format && npm run lint && npm run build:tsc", 19 | "format": "prettier --write src/**/*.ts", 20 | "lint": "eslint src/**/*.ts --fix", 21 | "build:tsc": "tsc", 22 | "clean": "rm -rf dist" 23 | }, 24 | "author": "", 25 | "license": "ISC", 26 | "description": "", 27 | "dependencies": { 28 | "@azure/identity": "^4.4.1", 29 | "@azure/openai": "^2.0.0-beta.2", 30 | "dotenv": "^16.4.5", 31 | "openai": "^4.57.1" 32 | }, 33 | "devDependencies": { 34 | "@types/node": "^20.12.2", 35 | "@typescript-eslint/eslint-plugin": "^5.59.6", 36 | "eslint": "^8.40.0", 37 | "eslint-config-prettier": "^8.8.0", 38 | "eslint-plugin-prettier": "^4.2.1", 39 | "prettier": "^2.8.8", 40 | "ts-node": "^10.9.2", 41 | "typescript": "^5.4.3", 42 | "wtfnode": "^0.9.1" 43 | }, 44 | "prettier": { 45 | "printWidth": 80 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /quickstarts/openai/src/chat-key.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { AzureOpenAI } from "openai"; 3 | import type { 4 | ChatCompletion, 5 | ChatCompletionCreateParamsNonStreaming, 6 | } from "openai/resources/index"; 7 | 8 | // You will need to set these environment variables or edit the following values 9 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 10 | const apiKey = process.env["AZURE_OPENAI_API_KEY"] || ""; 11 | 12 | // Required Azure OpenAI deployment name and API version 13 | const apiVersion = "2024-07-01-preview"; 14 | const deploymentName = "gpt-4"; //This must match your deployment name. 15 | 16 | function getClient(): AzureOpenAI { 17 | return new AzureOpenAI({ 18 | endpoint, 19 | apiKey, 20 | apiVersion, 21 | deployment: deploymentName, 22 | }); 23 | } 24 | 25 | function createMessages(): ChatCompletionCreateParamsNonStreaming { 26 | return { 27 | messages: [ 28 | { role: "system", content: "You are a helpful assistant." }, 29 | { 30 | role: "user", 31 | content: "Does Azure OpenAI support customer managed keys?", 32 | }, 33 | { 34 | role: "assistant", 35 | content: "Yes, customer managed keys are supported by Azure OpenAI?", 36 | }, 37 | { role: "user", content: "Do other Azure AI services support this too?" }, 38 | ], 39 | model: "", 40 | }; 41 | } 42 | async function printChoices(completion: ChatCompletion): Promise { 43 | for (const choice of completion.choices) { 44 | console.log(choice.message); 45 | } 46 | } 47 | export async function main() { 48 | const client = getClient(); 49 | const messages = createMessages(); 50 | const result = await client.chat.completions.create(messages); 51 | await printChoices(result); 52 | } 53 | 54 | main().catch((err) => { 55 | console.error("The sample encountered an error:", err); 56 | }); 57 | -------------------------------------------------------------------------------- /quickstarts/openai/src/chat-no-key.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultAzureCredential, 3 | getBearerTokenProvider, 4 | } from "@azure/identity"; 5 | import "dotenv/config"; 6 | import { AzureOpenAI } from "openai"; 7 | import type { 8 | ChatCompletion, 9 | ChatCompletionCreateParamsNonStreaming, 10 | } from "openai/resources/index"; 11 | 12 | // You will need to set these environment variables or edit the following values 13 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 14 | 15 | // Required Azure OpenAI deployment name and API version 16 | const apiVersion = "2024-07-01-preview"; 17 | const deploymentName = "gpt-4o"; //This must match your deployment name. 18 | 19 | function getClient(): AzureOpenAI { 20 | const scope = "https://cognitiveservices.azure.com/.default"; 21 | const azureADTokenProvider = getBearerTokenProvider( 22 | new DefaultAzureCredential(), 23 | scope 24 | ); 25 | return new AzureOpenAI({ 26 | endpoint, 27 | azureADTokenProvider, 28 | deployment: deploymentName, 29 | apiVersion, 30 | }); 31 | } 32 | 33 | function createMessages(): ChatCompletionCreateParamsNonStreaming { 34 | return { 35 | messages: [ 36 | { role: "system", content: "You are a helpful assistant." }, 37 | { 38 | role: "user", 39 | content: "Does Azure OpenAI support customer managed keys?", 40 | }, 41 | { 42 | role: "assistant", 43 | content: "Yes, customer managed keys are supported by Azure OpenAI?", 44 | }, 45 | { role: "user", content: "Do other Azure AI services support this too?" }, 46 | ], 47 | model: "", 48 | }; 49 | } 50 | async function printChoices(completion: ChatCompletion): Promise { 51 | for (const choice of completion.choices) { 52 | console.log(choice.message); 53 | } 54 | } 55 | export async function main() { 56 | const client = getClient(); 57 | const messages = createMessages(); 58 | const result = await client.chat.completions.create(messages); 59 | await printChoices(result); 60 | } 61 | 62 | main().catch((err) => { 63 | console.error("The sample encountered an error:", err); 64 | }); 65 | -------------------------------------------------------------------------------- /quickstarts/openai/src/completion-key.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { AzureOpenAI } from "openai"; 3 | import { type Completion } from "openai/resources/index"; 4 | 5 | // You will need to set these environment variables or edit the following values 6 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 7 | const apiKey = process.env["AZURE_OPENAI_API_KEY"] || ""; 8 | 9 | // Required Azure OpenAI deployment name and API version 10 | const apiVersion = "2024-07-01-preview"; 11 | const deploymentName = "gpt-35-turbo-instruct"; 12 | 13 | // Chat prompt and max tokens 14 | const prompt = ["When was Microsoft founded?"]; 15 | const maxTokens = 128; 16 | 17 | function getClient(): AzureOpenAI { 18 | return new AzureOpenAI({ 19 | endpoint, 20 | apiKey, 21 | apiVersion, 22 | deployment: deploymentName, 23 | }); 24 | } 25 | async function getCompletion( 26 | client: AzureOpenAI, 27 | prompt: string[], 28 | max_tokens: number 29 | ): Promise { 30 | return client.completions.create({ 31 | prompt, 32 | model: "", 33 | max_tokens, 34 | }); 35 | } 36 | async function printChoices(completion: Completion): Promise { 37 | for (const choice of completion.choices) { 38 | console.log(choice.text); 39 | } 40 | } 41 | export async function main() { 42 | console.log("== Get completions Sample =="); 43 | 44 | const client = getClient(); 45 | const completion = await getCompletion(client, prompt, maxTokens); 46 | await printChoices(completion); 47 | } 48 | 49 | main().catch((err) => { 50 | console.error("Error occurred:", err); 51 | }); 52 | -------------------------------------------------------------------------------- /quickstarts/openai/src/completion-no-key.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultAzureCredential, 3 | getBearerTokenProvider, 4 | } from "@azure/identity"; 5 | import "dotenv/config"; 6 | import { AzureOpenAI } from "openai"; 7 | import { type Completion } from "openai/resources/index"; 8 | 9 | // You will need to set these environment variables or edit the following values 10 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 11 | 12 | // Required Azure OpenAI deployment name and API version 13 | const apiVersion = "2024-07-01-preview"; 14 | const deploymentName = "gpt-35-turbo-instruct"; 15 | 16 | // Chat prompt and max tokens 17 | const prompt = ["When was Microsoft founded?"]; 18 | const maxTokens = 128; 19 | 20 | function getClient(): AzureOpenAI { 21 | const scope = "https://cognitiveservices.azure.com/.default"; 22 | const azureADTokenProvider = getBearerTokenProvider( 23 | new DefaultAzureCredential(), 24 | scope 25 | ); 26 | return new AzureOpenAI({ 27 | endpoint, 28 | azureADTokenProvider, 29 | deployment: deploymentName, 30 | apiVersion, 31 | }); 32 | } 33 | async function getCompletion( 34 | client: AzureOpenAI, 35 | prompt: string[], 36 | max_tokens: number 37 | ): Promise { 38 | return client.completions.create({ 39 | prompt, 40 | model: "", 41 | max_tokens, 42 | }); 43 | } 44 | async function printChoices(completion: Completion): Promise { 45 | for (const choice of completion.choices) { 46 | console.log(choice.text); 47 | } 48 | } 49 | export async function main() { 50 | console.log("== Get completions Sample =="); 51 | 52 | const client = getClient(); 53 | const completion = await getCompletion(client, prompt, maxTokens); 54 | await printChoices(completion); 55 | } 56 | 57 | main().catch((err) => { 58 | console.error("Error occurred:", err); 59 | }); 60 | -------------------------------------------------------------------------------- /quickstarts/openai/src/dall-e-key.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { AzureOpenAI } from "openai"; 3 | 4 | // You will need to set these environment variables or edit the following values 5 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"]; 6 | const apiKey = process.env["AZURE_OPENAI_API_KEY"]; 7 | 8 | // Required Azure OpenAI deployment name and API version 9 | const apiVersion = "2024-07-01"; 10 | const deploymentName = "dall-e-3"; 11 | 12 | // The prompt to generate images from 13 | const prompt = "a monkey eating a banana"; 14 | const numberOfImagesToGenerate = 1; 15 | 16 | function getClient(): AzureOpenAI { 17 | return new AzureOpenAI({ 18 | endpoint, 19 | apiKey, 20 | apiVersion, 21 | deployment: deploymentName, 22 | }); 23 | } 24 | async function main() { 25 | console.log("== Image Generation =="); 26 | 27 | const client = getClient(); 28 | 29 | const results = await client.images.generate({ 30 | prompt, 31 | size: "1024x1024", 32 | n: numberOfImagesToGenerate, 33 | model: "", 34 | style: "vivid", // or "natural" 35 | }); 36 | 37 | for (const image of results.data) { 38 | console.log(`Image generation result URL: ${image.url}`); 39 | } 40 | } 41 | 42 | main().catch((err) => { 43 | console.error("The sample encountered an error:", err); 44 | }); 45 | -------------------------------------------------------------------------------- /quickstarts/openai/src/dall-e-no-key.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultAzureCredential, 3 | getBearerTokenProvider, 4 | } from "@azure/identity"; 5 | import "dotenv/config"; 6 | import { AzureOpenAI } from "openai"; 7 | 8 | // You will need to set these environment variables or edit the following values 9 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 10 | 11 | // Required Azure OpenAI deployment name and API version 12 | const apiVersion = "2024-07-01"; 13 | const deploymentName = "dall-e-3"; 14 | 15 | // The prompt to generate images from 16 | const prompt = "a monkey eating a banana"; 17 | const numberOfImagesToGenerate = 1; 18 | 19 | function getClient(): AzureOpenAI { 20 | const scope = "https://cognitiveservices.azure.com/.default"; 21 | const azureADTokenProvider = getBearerTokenProvider( 22 | new DefaultAzureCredential(), 23 | scope 24 | ); 25 | return new AzureOpenAI({ 26 | endpoint, 27 | azureADTokenProvider, 28 | deployment: deploymentName, 29 | apiVersion, 30 | }); 31 | } 32 | async function main() { 33 | console.log("== Image Generation =="); 34 | 35 | const client = getClient(); 36 | 37 | const results = await client.images.generate({ 38 | prompt: prompt, 39 | size: "1024x1024", 40 | n: numberOfImagesToGenerate, 41 | model: "", 42 | style: "vivid", // or "natural" 43 | }); 44 | 45 | for (const image of results.data) { 46 | console.log(`Image generation result URL: ${image.url}`); 47 | } 48 | } 49 | 50 | main().catch((err) => { 51 | console.error("The sample encountered an error:", err); 52 | }); 53 | -------------------------------------------------------------------------------- /quickstarts/openai/src/text-to-speech-key.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { writeFile } from "fs/promises"; 3 | import { AzureOpenAI } from "openai"; 4 | import type { SpeechCreateParams } from "openai/resources/audio/speech"; 5 | import "openai/shims/node"; 6 | 7 | // You will need to set these environment variables or edit the following values 8 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 9 | const apiKey = process.env["AZURE_OPENAI_API_KEY"] || ""; 10 | const speechFilePath = 11 | process.env["SPEECH_FILE_PATH"] || ""; 12 | 13 | // Required Azure OpenAI deployment name and API version 14 | const deploymentName = "tts"; 15 | const apiVersion = "2024-07-01-preview"; 16 | 17 | function getClient(): AzureOpenAI { 18 | return new AzureOpenAI({ 19 | endpoint, 20 | apiKey, 21 | apiVersion, 22 | deployment: deploymentName, 23 | }); 24 | } 25 | 26 | async function generateAudioStream( 27 | client: AzureOpenAI, 28 | params: SpeechCreateParams 29 | ): Promise { 30 | const response = await client.audio.speech.create(params); 31 | if (response.ok) return response.body; 32 | throw new Error(`Failed to generate audio stream: ${response.statusText}`); 33 | } 34 | export async function main() { 35 | console.log("== Text to Speech Sample =="); 36 | 37 | const client = getClient(); 38 | const streamToRead = await generateAudioStream(client, { 39 | model: deploymentName, 40 | voice: "alloy", 41 | input: "the quick brown chicken jumped over the lazy dogs", 42 | }); 43 | 44 | console.log(`Streaming response to ${speechFilePath}`); 45 | await writeFile(speechFilePath, streamToRead); 46 | console.log("Finished streaming"); 47 | } 48 | 49 | main().catch((err) => { 50 | console.error("The sample encountered an error:", err); 51 | }); 52 | -------------------------------------------------------------------------------- /quickstarts/openai/src/text-to-speech-no-key.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultAzureCredential, 3 | getBearerTokenProvider, 4 | } from "@azure/identity"; 5 | import "dotenv/config"; 6 | import { writeFile } from "fs/promises"; 7 | import { AzureOpenAI } from "openai"; 8 | import type { SpeechCreateParams } from "openai/resources/audio/speech"; 9 | import "openai/shims/node"; 10 | 11 | // You will need to set these environment variables or edit the following values 12 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 13 | const speechFilePath = 14 | process.env["SPEECH_FILE_PATH"] || ""; 15 | 16 | // Required Azure OpenAI deployment name and API version 17 | const deploymentName = "tts"; 18 | const apiVersion = "2024-07-01-preview"; 19 | 20 | function getClient(): AzureOpenAI { 21 | const scope = "https://cognitiveservices.azure.com/.default"; 22 | const azureADTokenProvider = getBearerTokenProvider( 23 | new DefaultAzureCredential(), 24 | scope 25 | ); 26 | return new AzureOpenAI({ 27 | endpoint, 28 | azureADTokenProvider, 29 | deployment: deploymentName, 30 | apiVersion, 31 | }); 32 | } 33 | 34 | async function generateAudioStream( 35 | client: AzureOpenAI, 36 | params: SpeechCreateParams 37 | ): Promise { 38 | const response = await client.audio.speech.create(params); 39 | if (response.ok) return response.body; 40 | throw new Error(`Failed to generate audio stream: ${response.statusText}`); 41 | } 42 | export async function main() { 43 | console.log("== Text to Speech Sample =="); 44 | 45 | const client = getClient(); 46 | const streamToRead = await generateAudioStream(client, { 47 | model: "", 48 | voice: "alloy", 49 | input: "the quick brown chicken jumped over the lazy dogs", 50 | }); 51 | 52 | console.log(`Streaming response to ${speechFilePath}`); 53 | await writeFile(speechFilePath, streamToRead); 54 | console.log("Finished streaming"); 55 | } 56 | 57 | main().catch((err) => { 58 | console.error("The sample encountered an error:", err); 59 | }); 60 | -------------------------------------------------------------------------------- /quickstarts/openai/src/use-your-data-key.ts: -------------------------------------------------------------------------------- 1 | import "@azure/openai/types"; 2 | import "dotenv/config"; 3 | import { AzureOpenAI } from "openai"; 4 | 5 | // Set the Azure and AI Search values from environment variables 6 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"]; 7 | const apiKey = process.env["AZURE_OPENAI_API_KEY"]; 8 | const searchEndpoint = process.env["AZURE_AI_SEARCH_ENDPOINT"]; 9 | const searchKey = process.env["AZURE_AI_SEARCH_API_KEY"]; 10 | const searchIndex = process.env["AZURE_AI_SEARCH_INDEX"]; 11 | 12 | // Required Azure OpenAI deployment name and API version 13 | const deploymentName = "gpt-4"; 14 | const apiVersion = "2024-07-01-preview"; 15 | 16 | function getClient(): AzureOpenAI { 17 | return new AzureOpenAI({ 18 | endpoint, 19 | apiKey: apiKey, 20 | deployment: deploymentName, 21 | apiVersion, 22 | }); 23 | } 24 | 25 | async function main() { 26 | const client = getClient(); 27 | 28 | const messages = [ 29 | { role: "user", content: "What are my available health plans?" }, 30 | ]; 31 | 32 | console.log(`Message: ${messages.map((m) => m.content).join("\n")}`); 33 | 34 | const events = await client.chat.completions.create({ 35 | stream: true, 36 | messages: [ 37 | { 38 | role: "user", 39 | content: 40 | "What's the most common feedback we received from our customers about the product?", 41 | }, 42 | ], 43 | max_tokens: 128, 44 | model: "", 45 | data_sources: [ 46 | { 47 | type: "azure_search", 48 | parameters: { 49 | endpoint: searchEndpoint, 50 | index_name: searchIndex, 51 | authentication: { 52 | type: "api_key", 53 | key: searchKey, 54 | }, 55 | }, 56 | }, 57 | ], 58 | }); 59 | 60 | let response = ""; 61 | for await (const event of events) { 62 | for (const choice of event.choices) { 63 | const newText = choice.delta?.content; 64 | if (newText) { 65 | response += newText; 66 | // To see streaming results as they arrive, uncomment line below 67 | // console.log(newText); 68 | } 69 | } 70 | } 71 | console.log(response); 72 | } 73 | 74 | main().catch((err) => { 75 | console.error("The sample encountered an error:", err); 76 | }); 77 | -------------------------------------------------------------------------------- /quickstarts/openai/src/use-your-data-no-key.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultAzureCredential, 3 | getBearerTokenProvider, 4 | } from "@azure/identity"; 5 | import "@azure/openai/types"; 6 | import "dotenv/config"; 7 | import { AzureOpenAI } from "openai"; 8 | 9 | // You will need to set these environment variables or edit the following values 10 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 11 | const searchEndpoint = process.env["AZURE_AI_SEARCH_ENDPOINT"]; 12 | const searchIndex = process.env["AZURE_AI_SEARCH_INDEX"]; 13 | 14 | // Required Azure OpenAI deployment name and API version 15 | const deploymentName = "gpt-4"; 16 | const apiVersion = "2024-07-01-preview"; 17 | 18 | function getClient(): AzureOpenAI { 19 | const scope = "https://cognitiveservices.azure.com/.default"; 20 | const azureADTokenProvider = getBearerTokenProvider( 21 | new DefaultAzureCredential(), 22 | scope 23 | ); 24 | return new AzureOpenAI({ 25 | endpoint, 26 | azureADTokenProvider, 27 | deployment: deploymentName, 28 | apiVersion, 29 | }); 30 | } 31 | 32 | async function main() { 33 | const client = getClient(); 34 | 35 | const messages = [ 36 | { role: "user", content: "What are my available health plans?" }, 37 | ]; 38 | 39 | console.log(`Message: ${messages.map((m) => m.content).join("\n")}`); 40 | 41 | const events = await client.chat.completions.create({ 42 | stream: true, 43 | messages: [ 44 | { 45 | role: "user", 46 | content: 47 | "What's the most common feedback we received from our customers about the product?", 48 | }, 49 | ], 50 | max_tokens: 128, 51 | model: "", 52 | data_sources: [ 53 | { 54 | type: "azure_search", 55 | parameters: { 56 | endpoint: searchEndpoint, 57 | index_name: searchIndex, 58 | authentication: { 59 | type: "system_assigned_managed_identity", 60 | }, 61 | }, 62 | }, 63 | ], 64 | }); 65 | 66 | let response = ""; 67 | for await (const event of events) { 68 | for (const choice of event.choices) { 69 | const newText = choice.delta?.content; 70 | if (newText) { 71 | response += newText; 72 | // To see streaming results as they arrive, uncomment line below 73 | // console.log(newText); 74 | } 75 | } 76 | } 77 | console.log(response); 78 | } 79 | 80 | main().catch((err) => { 81 | console.error("The sample encountered an error:", err); 82 | }); 83 | -------------------------------------------------------------------------------- /quickstarts/openai/src/vision-key.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { AzureOpenAI } from "openai"; 3 | import type { 4 | ChatCompletion, 5 | ChatCompletionCreateParamsNonStreaming, 6 | } from "openai/resources/index"; 7 | 8 | // You will need to set these environment variables or edit the following values 9 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 10 | const apiKey = process.env["AZURE_OPENAI_API_KEY"] || ""; 11 | const imageUrl = process.env["IMAGE_URL"] || ""; 12 | 13 | // Required Azure OpenAI deployment name and API version 14 | const apiVersion = "2024-07-01-preview"; 15 | const deploymentName = "gpt-4-with-turbo"; 16 | 17 | function getClient(): AzureOpenAI { 18 | return new AzureOpenAI({ 19 | endpoint, 20 | apiKey, 21 | apiVersion, 22 | deployment: deploymentName, 23 | }); 24 | } 25 | function createMessages(): ChatCompletionCreateParamsNonStreaming { 26 | return { 27 | messages: [ 28 | { role: "system", content: "You are a helpful assistant." }, 29 | { 30 | role: "user", 31 | content: [ 32 | { 33 | type: "text", 34 | text: "Describe this picture:", 35 | }, 36 | { 37 | type: "image_url", 38 | image_url: { 39 | url: imageUrl, 40 | }, 41 | }, 42 | ], 43 | }, 44 | ], 45 | model: "", 46 | max_tokens: 2000, 47 | }; 48 | } 49 | async function printChoices(completion: ChatCompletion): Promise { 50 | for (const choice of completion.choices) { 51 | console.log(choice.message); 52 | } 53 | } 54 | export async function main() { 55 | console.log("== Get GPT-4 Turbo with vision Sample =="); 56 | 57 | const client = getClient(); 58 | const messages = createMessages(); 59 | const completion = await client.chat.completions.create(messages); 60 | await printChoices(completion); 61 | } 62 | 63 | main().catch((err) => { 64 | console.error("Error occurred:", err); 65 | }); 66 | -------------------------------------------------------------------------------- /quickstarts/openai/src/vision-no-key.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultAzureCredential, 3 | getBearerTokenProvider, 4 | } from "@azure/identity"; 5 | import "dotenv/config"; 6 | import { AzureOpenAI } from "openai"; 7 | import type { 8 | ChatCompletion, 9 | ChatCompletionCreateParamsNonStreaming, 10 | } from "openai/resources/index"; 11 | 12 | // You will need to set these environment variables or edit the following values 13 | const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; 14 | const imageUrl = process.env["IMAGE_URL"] || ""; 15 | 16 | // Required Azure OpenAI deployment name and API version 17 | const apiVersion = "2024-07-01-preview"; 18 | const deploymentName = "gpt-4-with-turbo"; 19 | 20 | function getClient(): AzureOpenAI { 21 | const scope = "https://cognitiveservices.azure.com/.default"; 22 | const azureADTokenProvider = getBearerTokenProvider( 23 | new DefaultAzureCredential(), 24 | scope 25 | ); 26 | return new AzureOpenAI({ 27 | endpoint, 28 | azureADTokenProvider, 29 | deployment: deploymentName, 30 | apiVersion, 31 | }); 32 | } 33 | function createMessages(): ChatCompletionCreateParamsNonStreaming { 34 | return { 35 | messages: [ 36 | { role: "system", content: "You are a helpful assistant." }, 37 | { 38 | role: "user", 39 | content: [ 40 | { 41 | type: "text", 42 | text: "Describe this picture:", 43 | }, 44 | { 45 | type: "image_url", 46 | image_url: { 47 | url: imageUrl, 48 | }, 49 | }, 50 | ], 51 | }, 52 | ], 53 | model: "", 54 | max_tokens: 2000, 55 | }; 56 | } 57 | async function printChoices(completion: ChatCompletion): Promise { 58 | for (const choice of completion.choices) { 59 | console.log(choice.message); 60 | } 61 | } 62 | export async function main() { 63 | console.log("== Get GPT-4 Turbo with vision Sample =="); 64 | 65 | const client = getClient(); 66 | const messages = createMessages(); 67 | const completion = await client.chat.completions.create(messages); 68 | await printChoices(completion); 69 | } 70 | 71 | main().catch((err) => { 72 | console.error("Error occurred:", err); 73 | }); 74 | -------------------------------------------------------------------------------- /quickstarts/openai/src/whisper-key.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { createReadStream } from "fs"; 3 | import { AzureOpenAI } from "openai"; 4 | 5 | // You will need to set these environment variables or edit the following values 6 | const audioFilePath = process.env["AUDIO_FILE_PATH"] || "