├── .documentation
├── toc.yml
├── index.md
├── .gitignore
└── docfx.json
├── .release-please-manifest.json
├── .github
├── icon.png
├── supabase-functions.png
└── workflows
│ ├── build-documentation.yaml
│ ├── build-and-test.yml
│ └── release.yml
├── docker-compose.yml
├── release-please-config.json
├── Functions
├── Responses
│ └── BaseResponse.cs
├── Exceptions
│ ├── FunctionsException.cs
│ └── FailureHint.cs
├── Interfaces
│ └── IFunctionsClient.cs
├── Functions.csproj
├── Client.cs
└── InvokeFunctionOptions.cs
├── FunctionsTests
├── FunctionsTests.csproj
└── ClientTests.cs
├── LICENSE
├── supabase
└── functions
│ ├── hello
│ └── index.ts
│ └── main
│ └── index.ts
├── README.md
├── CHANGELOG.md
├── Supabase.Functions.sln
└── .gitignore
/.documentation/toc.yml:
--------------------------------------------------------------------------------
1 | - name: API
2 | href: api/
3 |
--------------------------------------------------------------------------------
/.release-please-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | ".": "2.1.0"
3 | }
4 |
--------------------------------------------------------------------------------
/.documentation/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | _layout: landing
3 | ---
4 |
5 | # functions-csharp
6 |
--------------------------------------------------------------------------------
/.github/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/functions-csharp/HEAD/.github/icon.png
--------------------------------------------------------------------------------
/.github/supabase-functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/functions-csharp/HEAD/.github/supabase-functions.png
--------------------------------------------------------------------------------
/.documentation/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # folder #
3 | ###############
4 | /**/DROP/
5 | /**/TEMP/
6 | /**/packages/
7 | /**/bin/
8 | /**/obj/
9 | /_site
10 | /api
11 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | functions:
5 | image: supabase/edge-runtime:v1.30.0
6 | ports:
7 | - "9000:9000"
8 | environment:
9 | JWT_SECRET: "37c304f8-51aa-419a-a1af-06154e63707a"
10 | VERIFY_JWT: "true"
11 | volumes:
12 | - ./supabase/functions:/home/deno/functions:Z
13 | command:
14 | - start
15 | - --main-service
16 | - /home/deno/functions/main
17 | restart: unless-stopped
18 |
--------------------------------------------------------------------------------
/release-please-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": {
3 | ".": {
4 | "changelog-path": "CHANGELOG.md",
5 | "bump-minor-pre-major": false,
6 | "bump-patch-for-minor-pre-major": false,
7 | "draft": false,
8 | "prerelease": false,
9 | "release-type": "simple",
10 | "extra-files": [
11 | "Functions/Functions.csproj"
12 | ]
13 | }
14 | },
15 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
16 | }
17 |
--------------------------------------------------------------------------------
/Functions/Responses/BaseResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using Newtonsoft.Json;
4 |
5 | namespace Supabase.Functions.Responses
6 | {
7 | ///
8 | /// A wrapper class from which all Responses derive.
9 | ///
10 | public class BaseResponse
11 | {
12 | ///
13 | /// The response message
14 | ///
15 | [JsonIgnore]
16 | public HttpResponseMessage? ResponseMessage { get; set; }
17 |
18 | ///
19 | /// The response content.
20 | ///
21 | [JsonIgnore]
22 | public string? Content { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.github/workflows/build-documentation.yaml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy Documentation
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - release/* # Default release branch
8 |
9 | jobs:
10 | docs:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | with:
15 | persist-credentials: false
16 |
17 | - name: Setup .NET
18 | uses: actions/setup-dotnet@v3
19 | with:
20 | dotnet-version: 8.x
21 |
22 | - name: Install docfx
23 | run: dotnet tool update -g docfx
24 |
25 | - name: Build documentation
26 | run: docfx .documentation/docfx.json
27 |
28 | - name: Deploy 🚀
29 | uses: JamesIves/github-pages-deploy-action@v4
30 | with:
31 | folder: .documentation/_site
32 | token: ${{ secrets.GITHUB_TOKEN }}
33 |
--------------------------------------------------------------------------------
/.documentation/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": [
3 | {
4 | "src": [
5 | {
6 | "src": "../Functions",
7 | "files": [
8 | "**/*.csproj"
9 | ]
10 | }
11 | ],
12 | "dest": "api"
13 | }
14 | ],
15 | "build": {
16 | "content": [
17 | {
18 | "files": [
19 | "**/*.{md,yml}"
20 | ],
21 | "exclude": [
22 | "_site/**"
23 | ]
24 | }
25 | ],
26 | "resource": [
27 | {
28 | "files": [
29 | "images/**"
30 | ]
31 | }
32 | ],
33 | "output": "_site",
34 | "template": [
35 | "default",
36 | "modern"
37 | ],
38 | "globalMetadata": {
39 | "_appName": "functions-csharp",
40 | "_appTitle": "functions-csharp",
41 | "_enableSearch": true
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/.github/workflows/build-and-test.yml:
--------------------------------------------------------------------------------
1 | name: Build and Test
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build-and-test:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v3
18 | with:
19 | dotnet-version: 8.x
20 |
21 | - name: Restore dependencies
22 | run: dotnet restore
23 |
24 | - name: Build
25 | run: dotnet build --configuration Release --no-restore
26 |
27 | - uses: supabase/setup-cli@v1
28 | with:
29 | version: latest
30 |
31 | - name: Start supabase
32 | run: supabase start
33 |
34 | # - name: Initialize Testing Stack
35 | # run: docker-compose up -d
36 |
37 | - name: Test
38 | run: dotnet test --no-restore
39 |
--------------------------------------------------------------------------------
/FunctionsTests/FunctionsTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | false
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | runtime; build; native; contentfiles; analyzers; buildtransitive
16 | all
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Supabase
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.
22 |
--------------------------------------------------------------------------------
/supabase/functions/hello/index.ts:
--------------------------------------------------------------------------------
1 | // Follow this setup guide to integrate the Deno language server with your editor:
2 | // https://deno.land/manual/getting_started/setup_your_environment
3 | // This enables autocomplete, go to definition, etc.
4 |
5 | import { serve } from "https://deno.land/std@0.131.0/http/server.ts"
6 |
7 | console.log("Hello from Functions!")
8 |
9 | serve(async (req: Request) => {
10 | let value = req.url.substring(req.url.lastIndexOf("/") + 1)
11 | if (req.body != null) {
12 | const { name } = await req.json()
13 | value = name
14 | }
15 |
16 | const data = {
17 | message: `Hello ${value}!`,
18 | }
19 |
20 | console.log("response", JSON.stringify(data))
21 |
22 | return new Response(
23 | JSON.stringify(data),
24 | { headers: { "Content-Type": "application/json" } },
25 | )
26 | })
27 |
28 | // To invoke:
29 | // curl -i --location --request POST 'http://localhost:54321/functions/v1/' \
30 | // --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs' \
31 | // --header 'Content-Type: application/json' \
32 | // --data '{"name":"Functions"}'
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Supabase.Functions
2 |
3 | [](https://github.com/supabase-community/functions-csharp/actions/workflows/build-and-test.yml)
4 | [](https://www.nuget.com/packages/Supabase.Functions/)
5 |
6 | ---
7 |
8 | ## [Notice]: v2.0.0 renames this package from `functions-csharp` to `Supabase.Functions`. The depreciation notice has been set in NuGet. The API remains the same.
9 |
10 | C# Client library to interact with Supabase Functions.
11 |
12 | ## Package made possible through the efforts of:
13 |
14 | Join the ranks! See a problem? Help fix it!
15 |
16 |
17 |
18 |
19 |
20 | Made with [contrib.rocks](https://contrib.rocks).
21 |
22 | ## Contributing
23 |
24 | We are more than happy to have contributions! Please submit a PR.
25 |
26 | ### Testing
27 |
28 | To run the tests locally you must have docker and docker-compose installed. Then in the root of the repository run:
29 |
30 | - `docker-compose up -d`
31 | - `dotnet test`
32 |
--------------------------------------------------------------------------------
/Functions/Exceptions/FunctionsException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 |
4 | namespace Supabase.Functions.Exceptions
5 | {
6 | ///
7 | /// An Exception thrown within
8 | ///
9 | public class FunctionsException : Exception
10 | {
11 | ///
12 | public FunctionsException(string? message) : base(message) { }
13 |
14 | ///
15 | public FunctionsException(string? message, Exception? innerException) : base(message, innerException) { }
16 |
17 | ///
18 | /// The Http Response
19 | ///
20 | public HttpResponseMessage? Response { get; internal set; }
21 |
22 | ///
23 | /// The Http response content
24 | ///
25 | public string? Content { get; internal set; }
26 |
27 | ///
28 | /// The Http Status code
29 | ///
30 | public int StatusCode { get; internal set; }
31 |
32 | ///
33 | /// A parsed reason for a given failure
34 | ///
35 | public FailureHint.Reason Reason { get; internal set; }
36 |
37 | ///
38 | /// Attempts to detect a reason for this exception
39 | ///
40 | public void AddReason()
41 | {
42 | Reason = FailureHint.DetectReason(this);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/Functions/Exceptions/FailureHint.cs:
--------------------------------------------------------------------------------
1 | using static Supabase.Functions.Exceptions.FailureHint.Reason;
2 |
3 | namespace Supabase.Functions.Exceptions
4 | {
5 | ///
6 | /// A hint as to why a request failed.
7 | ///
8 | public static class FailureHint
9 | {
10 | ///
11 | /// A failure reason
12 | ///
13 | public enum Reason
14 | {
15 | ///
16 | /// An unknown reason
17 | ///
18 | Unknown,
19 | ///
20 | /// Request was not authorized
21 | ///
22 | NotAuthorized,
23 | ///
24 | /// An internal error occurred, check your supabase logs.
25 | ///
26 | Internal,
27 | }
28 |
29 | ///
30 | /// Attempts to detect a reason given an exception.
31 | ///
32 | ///
33 | ///
34 | public static Reason DetectReason(FunctionsException ex)
35 | {
36 | if (ex.Content == null)
37 | return Unknown;
38 |
39 | return ex.StatusCode switch
40 | {
41 | 401 => NotAuthorized,
42 | 403 when ex.Content.Contains("apikey") => NotAuthorized,
43 | 500 => Internal,
44 | _ => Unknown
45 | };
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/Functions/Interfaces/IFunctionsClient.cs:
--------------------------------------------------------------------------------
1 | using Supabase.Core.Interfaces;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 |
7 | namespace Supabase.Functions.Interfaces
8 | {
9 | ///
10 | /// Represents a contract for a Supabase Functions Client
11 | ///
12 | public interface IFunctionsClient : IGettableHeaders
13 | {
14 | ///
15 | /// Invokes a function given a URL and access token. Returns the string content.
16 | ///
17 | ///
18 | ///
19 | ///
20 | ///
21 | Task Invoke(string url, string? token = null, Client.InvokeFunctionOptions? options = null);
22 |
23 | ///
24 | /// Invokes a function given a URL and access token. Returns a typed response (should be a JSON.net parsable object)
25 | ///
26 | ///
27 | ///
28 | ///
29 | ///
30 | ///
31 | Task Invoke(string url, string? token = null, Client.InvokeFunctionOptions? options = null) where T : class;
32 |
33 | ///
34 | /// Invokes a function given a URL and access token. Returns the raw HTTP response.
35 | ///
36 | ///
37 | ///
38 | ///
39 | ///
40 | Task RawInvoke(string url, string? token = null, Client.InvokeFunctionOptions? options = null);
41 | }
42 | }
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release - Publish NuGet Package
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | release-please:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: write
13 | pull-requests: write
14 | issues: write
15 | steps:
16 | - uses: googleapis/release-please-action@v4
17 | with:
18 | target-branch: ${{ github.ref_name }}
19 | manifest-file: .release-please-manifest.json
20 | config-file: release-please-config.json
21 |
22 | publish:
23 | needs: release-please
24 | if: ${{ github.repository_owner == 'supabase-community' && startsWith(github.event.head_commit.message, 'chore(master)') && github.ref == 'refs/heads/master' && github.event_name == 'push' }}
25 | name: build, pack & publish
26 | runs-on: ubuntu-latest
27 | steps:
28 | - uses: actions/checkout@v3
29 |
30 | - name: Setup .NET
31 | uses: actions/setup-dotnet@v3
32 | with:
33 | dotnet-version: 8.x
34 |
35 | - name: Wait for tests to succeed
36 | uses: lewagon/wait-on-check-action@v1.3.1
37 | with:
38 | ref: ${{ github.ref }}
39 | check-name: build-and-test
40 | repo-token: ${{ secrets.GITHUB_TOKEN }}
41 | wait-interval: 10
42 |
43 | - name: Restore dependencies
44 | run: dotnet restore
45 |
46 | - name: Build
47 | run: dotnet build --configuration Release --no-restore
48 |
49 | - name: Generate package
50 | run: dotnet pack ./Functions/Functions.csproj --configuration Release
51 |
52 | - name: Publish on version change
53 | run: dotnet nuget push "**/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
54 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [2.1.0](https://github.com/supabase-community/functions-csharp/compare/v2.0.0...v2.1.0) (2025-05-13)
4 |
5 |
6 | ### Miscellaneous Chores
7 |
8 | * release 2.1.0 ([6f2d78d](https://github.com/supabase-community/functions-csharp/commit/6f2d78df68e91d3457fa54e3ff28f179edb95ab1))
9 |
10 | ## 2.0.0 - 04-21-2024
11 |
12 | - v2.0.0 renames this package from `functions-csharp` to `Supabase.Functions`. The depreciation notice has been set in NuGet. The API remains the same.
13 | - Re: [#135](https://github.com/supabase-community/supabase-csharp/issues/135) Update nuget package
14 | name `functions-csharp` to `Supabase.Functions`
15 |
16 | ## 1.3.2 - 03-12-2024
17 |
18 | - Re: [#5](https://github.com/supabase-community/functions-csharp/issues/5) Add support for specifying Http Timeout on a function call by adding `HttpTimeout` to `InvokeFunctionOptions`
19 |
20 | ## 1.3.1 - 06-10-2023
21 |
22 | - Updates usage of `Supabase.Core` assembly.
23 |
24 | ## 1.3.0 - 06-10-2023
25 |
26 | - Rename assembly to `Supabase.Functions`
27 | - Uses `FunctionsException` instead of `RequestException`
28 |
29 | ## 1.2.1 - 11-12-2022
30 |
31 | - Use `supabase-core` and implement `IGettableHeaders` on `Client`
32 |
33 | ## 1.2.0 - 2022-11-10
34 |
35 | - [MINOR] `Client` now initializes with a `baseUrl` and method calls arguments are only the `functionName`.
36 | - Included `GetHeaders` property.
37 |
38 | ## 1.1.0 - 2022-11-04
39 |
40 | - `Client` is no longer a Singleton class, it should be initialized using a default constructor.
41 | - [#1](https://github.com/supabase-community/functions-csharp/issues/1) Restructures library to support DI.
42 |
43 | ## 1.0.1 - 2022-04-15
44 |
45 | - Default `token` to be `null` in `Invoke` calls to allow `Authorization` to be passed solely via Headers.
46 |
47 | ## 1.0.0 - 2022-04-14
48 |
49 | - Initial Release
50 |
--------------------------------------------------------------------------------
/Functions/Functions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | true
5 | Supabase.Functions
6 | Supabase.Functions
7 | Supabase.Functions
8 | Joseph Schultz <joseph@acupofjose.com>
9 | MIT
10 | en
11 | MIT
12 | Joseph Schultz <joseph@acupofjose.com>
13 | A C# client for Supabase Functions
14 | Function
15 | A C# client for Supabase Functions
16 | https://avatars.githubusercontent.com/u/54469796?s=200&v=4
17 | https://github.com/supabase-community/functions-csharp
18 | supabase, functions
19 |
20 | 2.1.0
21 | 2.1.0
22 |
23 | true
24 | icon.png
25 | README.md
26 | https://github.com/supabase-community/functions-csharp
27 | true
28 | snupkg
29 | true
30 | enable
31 | 8.0
32 | CS8600;CS8602;CS8603
33 |
34 |
35 |
36 | 2.1.0
37 |
38 | $(VersionPrefix)-$(VersionSuffix)
39 | $(VersionPrefix)
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/supabase/functions/main/index.ts:
--------------------------------------------------------------------------------
1 | import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
2 | import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts'
3 |
4 | console.log('main function started')
5 |
6 | const JWT_SECRET = Deno.env.get('JWT_SECRET')
7 | const VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true'
8 |
9 | function getAuthToken(req: Request) {
10 | const authHeader = req.headers.get('authorization')
11 | if (!authHeader) {
12 | throw new Error('Missing authorization header')
13 | }
14 | const [bearer, token] = authHeader.split(' ')
15 | if (bearer !== 'Bearer') {
16 | throw new Error(`Auth header is not 'Bearer {token}'`)
17 | }
18 | return token
19 | }
20 |
21 | async function verifyJWT(jwt: string): Promise {
22 | const encoder = new TextEncoder()
23 | const secretKey = encoder.encode(JWT_SECRET)
24 | try {
25 | await jose.jwtVerify(jwt, secretKey)
26 | } catch (err) {
27 | console.error(err)
28 | return false
29 | }
30 | return true
31 | }
32 |
33 | serve(async (req: Request) => {
34 | if (req.method !== 'OPTIONS' && VERIFY_JWT) {
35 | try {
36 | const token = getAuthToken(req)
37 | const isValidJWT = await verifyJWT(token)
38 |
39 | if (!isValidJWT) {
40 | return new Response(JSON.stringify({ msg: 'Invalid JWT' }), {
41 | status: 401,
42 | headers: { 'Content-Type': 'application/json' },
43 | })
44 | }
45 | } catch (e) {
46 | console.error(e)
47 | return new Response(JSON.stringify({ msg: e.toString() }), {
48 | status: 401,
49 | headers: { 'Content-Type': 'application/json' },
50 | })
51 | }
52 | }
53 |
54 | const url = new URL(req.url)
55 | const { pathname } = url
56 | const path_parts = pathname.split('/')
57 | const service_name = path_parts[1]
58 |
59 | if (!service_name || service_name === '') {
60 | const error = { msg: 'missing function name in request' }
61 | return new Response(JSON.stringify(error), {
62 | status: 400,
63 | headers: { 'Content-Type': 'application/json' },
64 | })
65 | }
66 |
67 | const servicePath = `/home/deno/functions/${service_name}`
68 | console.error(`serving the request with ${servicePath}`)
69 |
70 | const memoryLimitMb = 150
71 | const workerTimeoutMs = 1 * 60 * 1000
72 | const noModuleCache = false
73 | const importMapPath = null
74 | const envVarsObj = Deno.env.toObject()
75 | const envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]])
76 |
77 | try {
78 | const worker = await EdgeRuntime.userWorkers.create({
79 | servicePath,
80 | memoryLimitMb,
81 | workerTimeoutMs,
82 | noModuleCache,
83 | importMapPath,
84 | envVars,
85 | })
86 | return await worker.fetch(req)
87 | } catch (e) {
88 | const error = { msg: e.toString() }
89 | return new Response(JSON.stringify(error), {
90 | status: 500,
91 | headers: { 'Content-Type': 'application/json' },
92 | })
93 | }
94 | })
--------------------------------------------------------------------------------
/Supabase.Functions.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32319.34
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{228693BB-A395-4123-93E8-5299FF875615}"
7 | ProjectSection(SolutionItems) = preProject
8 | CHANGELOG.md = CHANGELOG.md
9 | README.md = README.md
10 | EndProjectSection
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Functions", "Functions\Functions.csproj", "{889543F7-1F08-4032-A3D7-F7425ED03D9B}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionsTests", "FunctionsTests\FunctionsTests.csproj", "{B427628C-D057-45E9-982F-552748894A94}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{D6201965-1A00-435E-965B-B0D66E74F33B}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{11445079-7FD7-4A84-972D-328B82AF1238}"
19 | ProjectSection(SolutionItems) = preProject
20 | .github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml
21 | .github\workflows\build-documentation.yaml = .github\workflows\build-documentation.yaml
22 | .github\workflows\release.yml = .github\workflows\release.yml
23 | EndProjectSection
24 | EndProject
25 | Global
26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
27 | Debug|Any CPU = Debug|Any CPU
28 | Release|Any CPU = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 | {889543F7-1F08-4032-A3D7-F7425ED03D9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {889543F7-1F08-4032-A3D7-F7425ED03D9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {889543F7-1F08-4032-A3D7-F7425ED03D9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {889543F7-1F08-4032-A3D7-F7425ED03D9B}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {B427628C-D057-45E9-982F-552748894A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {B427628C-D057-45E9-982F-552748894A94}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {B427628C-D057-45E9-982F-552748894A94}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {B427628C-D057-45E9-982F-552748894A94}.Release|Any CPU.Build.0 = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | GlobalSection(NestedProjects) = preSolution
44 | {D6201965-1A00-435E-965B-B0D66E74F33B} = {228693BB-A395-4123-93E8-5299FF875615}
45 | {11445079-7FD7-4A84-972D-328B82AF1238} = {D6201965-1A00-435E-965B-B0D66E74F33B}
46 | EndGlobalSection
47 | GlobalSection(ExtensibilityGlobals) = postSolution
48 | SolutionGuid = {3CB8EBAC-5D93-461A-8D2D-B83A69E49B4B}
49 | EndGlobalSection
50 | GlobalSection(MonoDevelopProperties) = preSolution
51 | Policies = $0
52 | $0.DotNetNamingPolicy = $1
53 | $1.DirectoryNamespaceAssociation = PrefixedHierarchical
54 | $0.VersionControlPolicy = $2
55 | version = 2.4.0
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/FunctionsTests/ClientTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IdentityModel.Tokens.Jwt;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Microsoft.IdentityModel.Tokens;
8 | using Microsoft.VisualStudio.TestTools.UnitTesting;
9 | using Supabase.Functions;
10 | using static Supabase.Functions.Client;
11 |
12 | namespace FunctionsTests
13 | {
14 | [TestClass]
15 | public class ClientTests
16 | {
17 | private Client _client = null!;
18 | private string _token = null!;
19 |
20 | [TestInitialize]
21 | public void Initialize()
22 | {
23 | _token = GenerateToken("super-secret-jwt-token-with-at-least-32-characters-long");
24 | _client = new Client("http://localhost:54321/functions/v1");
25 | }
26 |
27 | [TestMethod("Invokes a function.")]
28 | public async Task Invokes()
29 | {
30 | const string function = "hello";
31 |
32 | var result = await _client.Invoke(
33 | function,
34 | _token,
35 | new InvokeFunctionOptions
36 | {
37 | Body = new Dictionary { { "name", "supabase" } },
38 | HttpMethod = HttpMethod.Post,
39 | }
40 | );
41 |
42 | Assert.IsTrue(result.Contains("supabase"));
43 |
44 | var result2 = await _client.Invoke>(
45 | function,
46 | _token,
47 | new InvokeFunctionOptions
48 | {
49 | Body = new Dictionary { { "name", "functions" } },
50 | HttpMethod = HttpMethod.Post,
51 | }
52 | );
53 |
54 | Assert.IsInstanceOfType(result2, typeof(Dictionary));
55 | Assert.IsTrue(result2.ContainsKey("message"));
56 | Assert.IsTrue(result2["message"].Contains("functions"));
57 |
58 | var result3 = await _client.RawInvoke(
59 | function,
60 | _token,
61 | new InvokeFunctionOptions
62 | {
63 | Body = new Dictionary { { "name", "functions" } },
64 | HttpMethod = HttpMethod.Post,
65 | }
66 | );
67 |
68 | var bytes = await result3.ReadAsByteArrayAsync();
69 |
70 | Assert.IsInstanceOfType(bytes, typeof(byte[]));
71 |
72 | var result4 = await _client.Invoke(
73 | function,
74 | _token,
75 | new InvokeFunctionOptions
76 | {
77 | Body = [],
78 | HttpMethod = HttpMethod.Get,
79 | }
80 | );
81 |
82 | Assert.IsTrue(result4.Contains(function));
83 | }
84 |
85 | private static string GenerateToken(string secret)
86 | {
87 | var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
88 |
89 | var tokenDescriptor = new SecurityTokenDescriptor
90 | {
91 | SigningCredentials = new SigningCredentials(
92 | signingKey,
93 | SecurityAlgorithms.HmacSha256Signature
94 | ),
95 | };
96 |
97 | var tokenHandler = new JwtSecurityTokenHandler();
98 | var securityToken = tokenHandler.CreateToken(tokenDescriptor);
99 | return tokenHandler.WriteToken(securityToken);
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/Functions/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.Http;
4 | using System.Runtime.CompilerServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Web;
8 | using Newtonsoft.Json;
9 | using Supabase.Core;
10 | using Supabase.Core.Extensions;
11 | using Supabase.Functions.Exceptions;
12 | using Supabase.Functions.Interfaces;
13 |
14 | [assembly: InternalsVisibleTo("FunctionsTests")]
15 |
16 | namespace Supabase.Functions
17 | {
18 | ///
19 | public partial class Client : IFunctionsClient
20 | {
21 | private HttpClient _httpClient = new HttpClient();
22 | private readonly string _baseUrl;
23 | private readonly FunctionRegion _region;
24 |
25 | ///
26 | /// Function that can be set to return dynamic headers.
27 | ///
28 | /// Headers specified in the method parameters will ALWAYS take precedence over headers returned by this function.
29 | ///
30 | public Func>? GetHeaders { get; set; }
31 |
32 | ///
33 | /// Initializes a functions client
34 | ///
35 | ///
36 | ///
37 | public Client(string baseUrl, FunctionRegion? region = null)
38 | {
39 | _baseUrl = baseUrl;
40 | _region = region ?? FunctionRegion.Any;
41 | }
42 |
43 | ///
44 | /// Returns an response, allowing for coersion into Streams, Strings, and byte[]
45 | ///
46 | /// Function Name, will be appended to BaseUrl
47 | /// Anon Key.
48 | /// Options
49 | ///
50 | public async Task RawInvoke(
51 | string functionName,
52 | string? token = null,
53 | InvokeFunctionOptions? options = null
54 | )
55 | {
56 | var url = $"{_baseUrl}/{functionName}";
57 |
58 | return (await HandleRequest(url, token, options)).Content;
59 | }
60 |
61 | ///
62 | /// Invokes a function and returns the Text content of the response.
63 | ///
64 | /// Function Name, will be appended to BaseUrl
65 | /// Anon Key.
66 | /// Options
67 | ///
68 | public async Task Invoke(
69 | string functionName,
70 | string? token = null,
71 | InvokeFunctionOptions? options = null
72 | )
73 | {
74 | var url = $"{_baseUrl}/{functionName}";
75 | var response = await HandleRequest(url, token, options);
76 |
77 | return await response.Content.ReadAsStringAsync();
78 | }
79 |
80 | ///
81 | /// Invokes a function and returns a JSON Deserialized object according to the supplied generic Type
82 | ///
83 | ///
84 | /// Function Name, will be appended to BaseUrl
85 | /// Anon Key.
86 | /// Options
87 | ///
88 | public async Task Invoke(
89 | string functionName,
90 | string? token = null,
91 | InvokeFunctionOptions? options = null
92 | )
93 | where T : class
94 | {
95 | var url = $"{_baseUrl}/{functionName}";
96 | var response = await HandleRequest(url, token, options);
97 |
98 | var content = await response.Content.ReadAsStringAsync();
99 |
100 | return JsonConvert.DeserializeObject(content);
101 | }
102 |
103 | ///
104 | /// Internal request handling
105 | ///
106 | ///
107 | ///
108 | ///
109 | ///
110 | ///
111 | private async Task HandleRequest(
112 | string url,
113 | string? token = null,
114 | InvokeFunctionOptions? options = null
115 | )
116 | {
117 | options ??= new InvokeFunctionOptions();
118 |
119 | if (GetHeaders != null)
120 | {
121 | options.Headers = GetHeaders().MergeLeft(options.Headers);
122 | }
123 |
124 | if (!string.IsNullOrEmpty(token))
125 | {
126 | options.Headers["Authorization"] = $"Bearer {token}";
127 | }
128 |
129 | options.Headers["X-Client-Info"] = Util.GetAssemblyVersion(typeof(Client));
130 |
131 | var region = options.FunctionRegion;
132 | if (region == null)
133 | {
134 | region = _region;
135 | }
136 |
137 | if (region != FunctionRegion.Any)
138 | {
139 | options.Headers["x-region"] = region.ToString();
140 | }
141 |
142 | var builder = new UriBuilder(url);
143 | var query = HttpUtility.ParseQueryString(builder.Query);
144 |
145 | builder.Query = query.ToString();
146 |
147 | using var requestMessage = new HttpRequestMessage(options.HttpMethod, builder.Uri);
148 | requestMessage.Content = new StringContent(
149 | JsonConvert.SerializeObject(options.Body),
150 | Encoding.UTF8,
151 | "application/json"
152 | );
153 |
154 | foreach (var kvp in options.Headers)
155 | {
156 | requestMessage.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value);
157 | }
158 |
159 | if (_httpClient.Timeout != options.HttpTimeout)
160 | {
161 | _httpClient = new HttpClient();
162 | _httpClient.Timeout = options.HttpTimeout;
163 | }
164 |
165 | var response = await _httpClient.SendAsync(requestMessage);
166 |
167 | if (response.IsSuccessStatusCode && !response.Headers.Contains("x-relay-error"))
168 | return response;
169 |
170 | var content = await response.Content.ReadAsStringAsync();
171 | var exception = new FunctionsException(content)
172 | {
173 | Content = content,
174 | Response = response,
175 | StatusCode = (int)response.StatusCode,
176 | };
177 | exception.AddReason();
178 | throw exception;
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/Functions/InvokeFunctionOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.Http;
4 | using Newtonsoft.Json;
5 |
6 | namespace Supabase.Functions
7 | {
8 | public partial class Client
9 | {
10 | ///
11 | /// Options that can be supplied to a function invocation.
12 | ///
13 | /// Note: If Headers.Authorization is set, it can be later overriden if a token is supplied in the method call.
14 | ///
15 | public class InvokeFunctionOptions
16 | {
17 | ///
18 | /// Headers to be included on the request.
19 | ///
20 | public Dictionary Headers { get; set; } =
21 | new Dictionary();
22 |
23 | ///
24 | /// Body of the Request
25 | ///
26 | [JsonProperty("body")]
27 | public Dictionary Body { get; set; } = new Dictionary();
28 |
29 | ///
30 | /// Timout value for HttpClient Requests, defaults to 100s.
31 | /// https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=net-8.0#remarks
32 | ///
33 | public TimeSpan HttpTimeout { get; set; } = TimeSpan.FromSeconds(100);
34 |
35 | ///
36 | /// Http method of the Request
37 | ///
38 | public HttpMethod HttpMethod { get; set; } = HttpMethod.Post;
39 |
40 | ///
41 | /// Region of the request
42 | ///
43 | public FunctionRegion? FunctionRegion { get; set; } = null;
44 | }
45 |
46 | ///
47 | /// Define the region for requests
48 | ///
49 | public class FunctionRegion : IEquatable
50 | {
51 | private readonly string _region;
52 |
53 | ///
54 | /// Empty region
55 | ///
56 | public static FunctionRegion Any { get; } = new FunctionRegion("any");
57 |
58 | ///
59 | /// Represents the region "ap-northeast-1" for function requests.
60 | ///
61 | public static FunctionRegion ApNortheast1 { get; } =
62 | new FunctionRegion("ap-northeast-1");
63 |
64 | ///
65 | /// Represents the "ap-northeast-2" region for function invocation.
66 | ///
67 | public static FunctionRegion ApNortheast2 { get; } =
68 | new FunctionRegion("ap-northeast-2");
69 |
70 | ///
71 | /// Represents the "ap-south-1" region used for requests.
72 | ///
73 | public static FunctionRegion ApSouth1 { get; } = new FunctionRegion("ap-south-1");
74 |
75 | ///
76 | /// Represents the region "ap-southeast-1" for function invocation.
77 | ///
78 | public static FunctionRegion ApSoutheast1 { get; } =
79 | new FunctionRegion("ap-southeast-1");
80 |
81 | ///
82 | /// Represents the "ap-southeast-2" region for requests.
83 | ///
84 | public static FunctionRegion ApSoutheast2 { get; } =
85 | new FunctionRegion("ap-southeast-2");
86 |
87 | ///
88 | /// Represents the Canada (Central) region for requests.
89 | ///
90 | public static FunctionRegion CaCentral1 { get; } = new FunctionRegion("ca-central-1");
91 |
92 | ///
93 | /// Represents the "eu-central-1" region for function invocation.
94 | ///
95 | public static FunctionRegion EuCentral1 { get; } = new FunctionRegion("eu-central-1");
96 |
97 | ///
98 | /// Represents the "eu-west-1" function region for requests.
99 | ///
100 | public static FunctionRegion EuWest1 { get; } = new FunctionRegion("eu-west-1");
101 |
102 | ///
103 | /// Represents the "eu-west-2" region for function invocation requests.
104 | ///
105 | public static FunctionRegion EuWest2 { get; } = new FunctionRegion("eu-west-2");
106 |
107 | ///
108 | /// Represents the AWS region 'eu-west-3'.
109 | ///
110 | public static FunctionRegion EuWest3 { get; } = new FunctionRegion("eu-west-3");
111 |
112 | ///
113 | /// Represents the South America (São Paulo) region for requests.
114 | ///
115 | public static FunctionRegion SaEast1 { get; } = new FunctionRegion("sa-east-1");
116 |
117 | ///
118 | /// Represents the "us-east-1" region for function requests.
119 | ///
120 | public static FunctionRegion UsEast1 { get; } = new FunctionRegion("us-east-1");
121 |
122 | ///
123 | /// Represents the us-west-1 region for function requests.
124 | ///
125 | public static FunctionRegion UsWest1 { get; } = new FunctionRegion("us-west-1");
126 |
127 | ///
128 | /// Represents the "us-west-2" region for requests.
129 | ///
130 | public static FunctionRegion UsWest2 { get; } = new FunctionRegion("us-west-2");
131 |
132 | ///
133 | /// Define the region for requests
134 | ///
135 | public FunctionRegion(string region)
136 | {
137 | _region = region;
138 | }
139 |
140 | ///
141 | /// Check if the object is identical to the reference passed
142 | ///
143 | public override bool Equals(object obj)
144 | {
145 | return obj is FunctionRegion r && Equals(r);
146 | }
147 |
148 | ///
149 | /// Generate Hash code
150 | ///
151 | public override int GetHashCode()
152 | {
153 | return _region.GetHashCode();
154 | }
155 |
156 | ///
157 | /// Check if the object is identical to the reference passed
158 | ///
159 | public bool Equals(FunctionRegion other)
160 | {
161 | return _region == other._region;
162 | }
163 |
164 | ///
165 | /// Overloading the operator ==
166 | ///
167 | public static bool operator ==(FunctionRegion? left, FunctionRegion? right) =>
168 | Equals(left, right);
169 |
170 | ///
171 | /// Overloading the operator !=
172 | ///
173 | public static bool operator !=(FunctionRegion? left, FunctionRegion? right) =>
174 | !Equals(left, right);
175 |
176 | ///
177 | /// Overloads the explicit cast operator to convert a FunctionRegion object to a string.
178 | ///
179 | public static explicit operator string(FunctionRegion region) => region.ToString();
180 |
181 | ///
182 | /// Overloads the explicit cast operator to convert a string to a FunctionRegion object.
183 | ///
184 | public static explicit operator FunctionRegion(string region) =>
185 | new FunctionRegion(region);
186 |
187 | ///
188 | /// Returns a string representation of the FunctionRegion instance.
189 | ///
190 | /// A string that represents the current FunctionRegion instance.
191 | public override string ToString() => _region;
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # globs
2 | Makefile.in
3 | *.userprefs
4 | *.usertasks
5 | config.make
6 | config.status
7 | aclocal.m4
8 | install-sh
9 | autom4te.cache/
10 | *.tar.gz
11 | tarballs/
12 | test-results/
13 |
14 | # Mac bundle stuff
15 | *.dmg
16 | *.app
17 |
18 | # content below from: https://github.com/github/gitignore/blob/main/Global/macOS.gitignore
19 | # General
20 | .DS_Store
21 | .AppleDouble
22 | .LSOverride
23 |
24 | # Icon must end with two \r
25 | Icon
26 |
27 |
28 | # Thumbnails
29 | ._*
30 |
31 | # Files that might appear in the root of a volume
32 | .DocumentRevisions-V100
33 | .fseventsd
34 | .Spotlight-V100
35 | .TemporaryItems
36 | .Trashes
37 | .VolumeIcon.icns
38 | .com.apple.timemachine.donotpresent
39 |
40 | # Directories potentially created on remote AFP share
41 | .AppleDB
42 | .AppleDesktop
43 | Network Trash Folder
44 | Temporary Items
45 | .apdisk
46 |
47 | # content below from: https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
48 | # Windows thumbnail cache files
49 | Thumbs.db
50 | ehthumbs.db
51 | ehthumbs_vista.db
52 |
53 | # Dump file
54 | *.stackdump
55 |
56 | # Folder config file
57 | [Dd]esktop.ini
58 |
59 | # Recycle Bin used on file shares
60 | $RECYCLE.BIN/
61 |
62 | # Windows Installer files
63 | *.cab
64 | *.msi
65 | *.msix
66 | *.msm
67 | *.msp
68 |
69 | # Windows shortcuts
70 | *.lnk
71 |
72 | # content below from: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
73 | ## Ignore Visual Studio temporary files, build results, and
74 | ## files generated by popular Visual Studio add-ons.
75 | ##
76 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
77 |
78 | # User-specific files
79 | *.suo
80 | *.user
81 | *.userosscache
82 | *.sln.docstates
83 |
84 | # User-specific files (MonoDevelop/Xamarin Studio)
85 | *.userprefs
86 |
87 | # Build results
88 | [Dd]ebug/
89 | [Dd]ebugPublic/
90 | [Rr]elease/
91 | [Rr]eleases/
92 | x64/
93 | x86/
94 | bld/
95 | [Bb]in/
96 | [Oo]bj/
97 | [Ll]og/
98 |
99 | # Visual Studio 2015/2017 cache/options directory
100 | .vs/
101 | # Uncomment if you have tasks that create the project's static files in wwwroot
102 | #wwwroot/
103 |
104 | # Visual Studio 2017 auto generated files
105 | Generated\ Files/
106 |
107 | # MSTest test Results
108 | [Tt]est[Rr]esult*/
109 | [Bb]uild[Ll]og.*
110 |
111 | # NUNIT
112 | *.VisualState.xml
113 | TestResult.xml
114 |
115 | # Build Results of an ATL Project
116 | [Dd]ebugPS/
117 | [Rr]eleasePS/
118 | dlldata.c
119 |
120 | # Benchmark Results
121 | BenchmarkDotNet.Artifacts/
122 |
123 | # .NET Core
124 | project.lock.json
125 | project.fragment.lock.json
126 | artifacts/
127 |
128 | # StyleCop
129 | StyleCopReport.xml
130 |
131 | # Files built by Visual Studio
132 | *_i.c
133 | *_p.c
134 | *_h.h
135 | *.ilk
136 | *.meta
137 | *.obj
138 | *.iobj
139 | *.pch
140 | *.pdb
141 | *.ipdb
142 | *.pgc
143 | *.pgd
144 | *.rsp
145 | *.sbr
146 | *.tlb
147 | *.tli
148 | *.tlh
149 | *.tmp
150 | *.tmp_proj
151 | *_wpftmp.csproj
152 | *.log
153 | *.vspscc
154 | *.vssscc
155 | .builds
156 | *.pidb
157 | *.svclog
158 | *.scc
159 |
160 | # Chutzpah Test files
161 | _Chutzpah*
162 |
163 | # Visual C++ cache files
164 | ipch/
165 | *.aps
166 | *.ncb
167 | *.opendb
168 | *.opensdf
169 | *.sdf
170 | *.cachefile
171 | *.VC.db
172 | *.VC.VC.opendb
173 |
174 | # Visual Studio profiler
175 | *.psess
176 | *.vsp
177 | *.vspx
178 | *.sap
179 |
180 | # Visual Studio Trace Files
181 | *.e2e
182 |
183 | # TFS 2012 Local Workspace
184 | $tf/
185 |
186 | # Guidance Automation Toolkit
187 | *.gpState
188 |
189 | # ReSharper is a .NET coding add-in
190 | _ReSharper*/
191 | *.[Rr]e[Ss]harper
192 | *.DotSettings.user
193 |
194 | # JustCode is a .NET coding add-in
195 | .JustCode
196 |
197 | # TeamCity is a build add-in
198 | _TeamCity*
199 |
200 | # DotCover is a Code Coverage Tool
201 | *.dotCover
202 |
203 | # AxoCover is a Code Coverage Tool
204 | .axoCover/*
205 | !.axoCover/settings.json
206 |
207 | # Visual Studio code coverage results
208 | *.coverage
209 | *.coveragexml
210 |
211 | # NCrunch
212 | _NCrunch_*
213 | .*crunch*.local.xml
214 | nCrunchTemp_*
215 |
216 | # MightyMoose
217 | *.mm.*
218 | AutoTest.Net/
219 |
220 | # Web workbench (sass)
221 | .sass-cache/
222 |
223 | # Installshield output folder
224 | [Ee]xpress/
225 |
226 | # DocProject is a documentation generator add-in
227 | DocProject/buildhelp/
228 | DocProject/Help/*.HxT
229 | DocProject/Help/*.HxC
230 | DocProject/Help/*.hhc
231 | DocProject/Help/*.hhk
232 | DocProject/Help/*.hhp
233 | DocProject/Help/Html2
234 | DocProject/Help/html
235 |
236 | # Click-Once directory
237 | publish/
238 |
239 | # Publish Web Output
240 | *.[Pp]ublish.xml
241 | *.azurePubxml
242 | # Note: Comment the next line if you want to checkin your web deploy settings,
243 | # but database connection strings (with potential passwords) will be unencrypted
244 | *.pubxml
245 | *.publishproj
246 |
247 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
248 | # checkin your Azure Web App publish settings, but sensitive information contained
249 | # in these scripts will be unencrypted
250 | PublishScripts/
251 |
252 | # NuGet Packages
253 | *.nupkg
254 | # The packages folder can be ignored because of Package Restore
255 | **/[Pp]ackages/*
256 | # except build/, which is used as an MSBuild target.
257 | !**/[Pp]ackages/build/
258 | # Uncomment if necessary however generally it will be regenerated when needed
259 | #!**/[Pp]ackages/repositories.config
260 | # NuGet v3's project.json files produces more ignorable files
261 | *.nuget.props
262 | *.nuget.targets
263 |
264 | # Microsoft Azure Build Output
265 | csx/
266 | *.build.csdef
267 |
268 | # Microsoft Azure Emulator
269 | ecf/
270 | rcf/
271 |
272 | # Windows Store app package directories and files
273 | AppPackages/
274 | BundleArtifacts/
275 | Package.StoreAssociation.xml
276 | _pkginfo.txt
277 | *.appx
278 |
279 | # Visual Studio cache files
280 | # files ending in .cache can be ignored
281 | *.[Cc]ache
282 | # but keep track of directories ending in .cache
283 | !*.[Cc]ache/
284 |
285 | # Others
286 | ClientBin/
287 | ~$*
288 | *~
289 | *.dbmdl
290 | *.dbproj.schemaview
291 | *.jfm
292 | *.pfx
293 | *.publishsettings
294 | orleans.codegen.cs
295 |
296 | # Including strong name files can present a security risk
297 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
298 | #*.snk
299 |
300 | # Since there are multiple workflows, uncomment next line to ignore bower_components
301 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
302 | #bower_components/
303 |
304 | # RIA/Silverlight projects
305 | Generated_Code/
306 |
307 | # Backup & report files from converting an old project file
308 | # to a newer Visual Studio version. Backup files are not needed,
309 | # because we have git ;-)
310 | _UpgradeReport_Files/
311 | Backup*/
312 | UpgradeLog*.XML
313 | UpgradeLog*.htm
314 | ServiceFabricBackup/
315 | *.rptproj.bak
316 |
317 | # SQL Server files
318 | *.mdf
319 | *.ldf
320 | *.ndf
321 |
322 | # Business Intelligence projects
323 | *.rdl.data
324 | *.bim.layout
325 | *.bim_*.settings
326 | *.rptproj.rsuser
327 |
328 | # Microsoft Fakes
329 | FakesAssemblies/
330 |
331 | # GhostDoc plugin setting file
332 | *.GhostDoc.xml
333 |
334 | # Node.js Tools for Visual Studio
335 | .ntvs_analysis.dat
336 | node_modules/
337 |
338 | # Visual Studio 6 build log
339 | *.plg
340 |
341 | # Visual Studio 6 workspace options file
342 | *.opt
343 |
344 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
345 | *.vbw
346 |
347 | # Visual Studio LightSwitch build output
348 | **/*.HTMLClient/GeneratedArtifacts
349 | **/*.DesktopClient/GeneratedArtifacts
350 | **/*.DesktopClient/ModelManifest.xml
351 | **/*.Server/GeneratedArtifacts
352 | **/*.Server/ModelManifest.xml
353 | _Pvt_Extensions
354 |
355 | # Paket dependency manager
356 | .paket/paket.exe
357 | paket-files/
358 |
359 | # FAKE - F# Make
360 | .fake/
361 |
362 | # JetBrains Rider
363 | .idea/
364 | *.sln.iml
365 |
366 | # CodeRush personal settings
367 | .cr/personal
368 |
369 | # Python Tools for Visual Studio (PTVS)
370 | __pycache__/
371 | *.pyc
372 |
373 | # Cake - Uncomment if you are using it
374 | # tools/**
375 | # !tools/packages.config
376 |
377 | # Tabs Studio
378 | *.tss
379 |
380 | # Telerik's JustMock configuration file
381 | *.jmconfig
382 |
383 | # BizTalk build output
384 | *.btp.cs
385 | *.btm.cs
386 | *.odx.cs
387 | *.xsd.cs
388 |
389 | # OpenCover UI analysis results
390 | OpenCover/
391 |
392 | # Azure Stream Analytics local run output
393 | ASALocalRun/
394 |
395 | # MSBuild Binary and Structured Log
396 | *.binlog
397 |
398 | # NVidia Nsight GPU debugger configuration file
399 | *.nvuser
400 |
401 | # MFractors (Xamarin productivity tool) working folder
402 | .mfractor/
403 |
404 | # Local History for Visual Studio
405 | .localhistory/
406 |
407 | # Supabase
408 | .supabase
409 | .temp
410 |
411 | launchSettings.json
--------------------------------------------------------------------------------