@microsoft/rayfin-guide 1.36.0-alpha.1756 → 1.36.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/docs/app-backend/deploy.md +36 -1
- package/assets/docs/cli/connectors/add.md +11 -1
- package/assets/docs/cli/connectors/index.md +1 -1
- package/assets/docs/cli/connectors/inspect.md +34 -1
- package/assets/docs/cli/functions/deploy.md +5 -1
- package/assets/docs/cli/functions/dev-apply.md +7 -1
- package/assets/docs/cli/functions/index.md +4 -2
- package/assets/docs/cli/functions/init.md +7 -1
- package/assets/docs/cli/index.md +19 -7
- package/assets/docs/cli/secrets.md +18 -8
- package/assets/docs/functions/connections/add-ado.md +8 -4
- package/assets/docs/functions/connections/add-azure-resource.md +17 -131
- package/assets/docs/functions/connections/add-fabric-resource.md +31 -61
- package/assets/docs/functions/connections/add-foundry.md +11 -4
- package/assets/docs/functions/connections/get-fabric-info.md +7 -25
- package/assets/docs/functions/connections/index.md +127 -22
- package/assets/docs/functions/index.md +39 -1
- package/assets/docs/functions/secrets.md +39 -11
- package/assets/docs/functions/writing-functions.md +27 -23
- package/assets/docs/getting-started/project-structure.md +3 -1
- package/package.json +1 -1
- package/assets/docs/functions/connections/add-work-iq.md +0 -39
|
@@ -4,11 +4,18 @@ sidebar_position: 2
|
|
|
4
4
|
|
|
5
5
|
# Add a Fabric resource
|
|
6
6
|
|
|
7
|
-
Connect a function to a **Microsoft Fabric item** — a Lakehouse, Warehouse, SQL Database, OneLake files
|
|
7
|
+
Connect a deployed function to a **Microsoft Fabric item** — a Lakehouse, Warehouse, SQL Database, or OneLake files.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
For the app's Rayfin DB, use [`ctx.getDataClient()`](../writing-functions.md#accessing-data-and-request-context) instead.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Grant the [application identity](../index.md#application-authentication) the required access to the workspace, item, or database for the operation you need.
|
|
12
|
+
|
|
13
|
+
**Before you start:** you need the item's coordinates (SQL endpoint or OneLake path).
|
|
14
|
+
See [Get Fabric info](./get-fabric-info.md) for how to pull them from the Fabric REST API.
|
|
15
|
+
|
|
16
|
+
All the patterns below follow the same model: declare the audience in the `RayfinContext` annotation, read the token from `ctx.Tokens`, use it. See [Connecting to external resources](./index.md) for the shared model and the [`ContextTokenCredential`](./index.md#wrapping-the-token-for-azure-sdk-clients) helper referenced here.
|
|
17
|
+
|
|
18
|
+
`AppSchema` below is your app's data schema — the same type you pass to `RayfinClient<AppSchema>`. See [Writing functions](../writing-functions.md#accessing-data-and-request-context).
|
|
12
19
|
|
|
13
20
|
## SQL databases
|
|
14
21
|
|
|
@@ -16,7 +23,7 @@ Covers Fabric **Lakehouse** (SQL analytics endpoint), **Warehouse**, **SQL Datab
|
|
|
16
23
|
|
|
17
24
|
- **Package:** `mssql@^12.6.0` (which pulls `tedious >= 19.2.2`). Older `tedious` (`<= 19.1.2`) has a LOGIN7 FeatureExt bug that causes "socket hang up" errors against Fabric endpoints.
|
|
18
25
|
- **Encryption:** `encrypt: true` (not `'strict'`). This matches ODBC `Encrypt=yes`.
|
|
19
|
-
- **Auth:** `azure-active-directory-access-token` with the token from `ctx.
|
|
26
|
+
- **Auth:** `azure-active-directory-access-token` with the token from `ctx.Tokens.Sql`.
|
|
20
27
|
|
|
21
28
|
Install the driver in the functions project:
|
|
22
29
|
|
|
@@ -52,10 +59,10 @@ const DATABASE = "<item-guid-or-db-name>";
|
|
|
52
59
|
udf.func(
|
|
53
60
|
"queryData",
|
|
54
61
|
async (
|
|
55
|
-
ctx: RayfinContext,
|
|
62
|
+
ctx: RayfinContext<AppSchema, AudienceType.Sql>,
|
|
56
63
|
query: string,
|
|
57
64
|
): Promise<Record<string, unknown>[]> => {
|
|
58
|
-
const token = ctx.
|
|
65
|
+
const token = ctx.Tokens.Sql;
|
|
59
66
|
const pool = await sql.connect({
|
|
60
67
|
server: SQL_SERVER,
|
|
61
68
|
database: DATABASE,
|
|
@@ -69,7 +76,7 @@ udf.func(
|
|
|
69
76
|
await pool.close();
|
|
70
77
|
return result.recordset;
|
|
71
78
|
},
|
|
72
|
-
[
|
|
79
|
+
[],
|
|
73
80
|
);
|
|
74
81
|
```
|
|
75
82
|
|
|
@@ -79,7 +86,7 @@ Read and write files in a Lakehouse's OneLake storage using `AudienceType.Storag
|
|
|
79
86
|
|
|
80
87
|
The OneLake DFS URL has the form `https://onelake.dfs.fabric.microsoft.com/<workspaceId>/<itemId>/Files/<path>` — get it from `oneLakeFilesPath` via [Get Fabric info](./get-fabric-info.md#lakehouse), or construct it from the workspace and item GUIDs.
|
|
81
88
|
|
|
82
|
-
Call the DFS endpoint directly with the
|
|
89
|
+
Call the DFS endpoint directly with the app-identity token — no SDK required:
|
|
83
90
|
|
|
84
91
|
```ts
|
|
85
92
|
import {
|
|
@@ -92,8 +99,11 @@ const udf = new UserDataFunctions();
|
|
|
92
99
|
|
|
93
100
|
udf.func(
|
|
94
101
|
"readFile",
|
|
95
|
-
async (
|
|
96
|
-
|
|
102
|
+
async (
|
|
103
|
+
ctx: RayfinContext<AppSchema, AudienceType.Storage>,
|
|
104
|
+
fileUrl: string,
|
|
105
|
+
): Promise<string> => {
|
|
106
|
+
const token = ctx.Tokens.Storage;
|
|
97
107
|
const res = await fetch(fileUrl, {
|
|
98
108
|
headers: { Authorization: `Bearer ${token}` },
|
|
99
109
|
});
|
|
@@ -102,59 +112,16 @@ udf.func(
|
|
|
102
112
|
}
|
|
103
113
|
return await res.text();
|
|
104
114
|
},
|
|
105
|
-
[
|
|
115
|
+
[],
|
|
106
116
|
);
|
|
107
117
|
```
|
|
108
118
|
|
|
109
|
-
## Eventhouse and KQL
|
|
110
|
-
|
|
111
|
-
Query a Fabric **Eventhouse** (KQL database) or a standalone Azure Data Explorer cluster using `AudienceType.Kusto`.
|
|
112
|
-
|
|
113
|
-
Get the cluster's **query URI** from the Eventhouse's `properties.queryServiceUri` — see [Get Fabric info → Eventhouse](./get-fabric-info.md#eventhouse).
|
|
114
|
-
|
|
115
|
-
`azure-kusto-data` accepts a token provider, so hand it a callback that returns `ctx.getToken`:
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
import {
|
|
119
|
-
UserDataFunctions,
|
|
120
|
-
AudienceType,
|
|
121
|
-
type RayfinContext,
|
|
122
|
-
} from "@microsoft/fabric-user-data-functions";
|
|
123
|
-
import { Client, KustoConnectionStringBuilder } from "azure-kusto-data";
|
|
124
|
-
|
|
125
|
-
const udf = new UserDataFunctions();
|
|
126
|
-
|
|
127
|
-
// Read these from the Eventhouse item — see "Get Fabric info".
|
|
128
|
-
const CLUSTER_URI = "https://<cluster>.z5.kusto.fabric.microsoft.com";
|
|
129
|
-
const DATABASE = "<kql-database-name>";
|
|
130
|
-
|
|
131
|
-
udf.func(
|
|
132
|
-
"queryKusto",
|
|
133
|
-
async (ctx: RayfinContext, query: string): Promise<unknown[]> => {
|
|
134
|
-
const kcsb = KustoConnectionStringBuilder.withTokenProvider(
|
|
135
|
-
CLUSTER_URI,
|
|
136
|
-
async () => ctx.getToken(AudienceType.Kusto),
|
|
137
|
-
);
|
|
138
|
-
const client = new Client(kcsb);
|
|
139
|
-
const response = await client.execute(DATABASE, query);
|
|
140
|
-
return response.primaryResults[0].toJSON().data;
|
|
141
|
-
},
|
|
142
|
-
[udf.connection({ audienceType: AudienceType.Kusto })],
|
|
143
|
-
);
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Install the SDK in the functions project:
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
cd rayfin/functions
|
|
150
|
-
npm install azure-kusto-data
|
|
151
|
-
```
|
|
152
|
-
|
|
153
119
|
## Fabric REST API
|
|
154
120
|
|
|
155
|
-
Call the [Fabric REST API](https://learn.microsoft.com/en-us/rest/api/fabric/) as the
|
|
121
|
+
Call the [Fabric REST API](https://learn.microsoft.com/en-us/rest/api/fabric/) as the app identity — for example to list items or read item metadata from inside a function — using `AudienceType.Fabric`.
|
|
122
|
+
Check that the specific API supports application identities and that the app identity has the required access.
|
|
156
123
|
|
|
157
|
-
The API base is fixed at `https://api.fabric.microsoft.com/v1`; `ctx.
|
|
124
|
+
The API base is fixed at `https://api.fabric.microsoft.com/v1`; `ctx.Tokens.Fabric` returns a token scoped for it. Send it as a bearer token with `fetch`:
|
|
158
125
|
|
|
159
126
|
```ts
|
|
160
127
|
import {
|
|
@@ -169,8 +136,11 @@ const FABRIC_API = "https://api.fabric.microsoft.com/v1";
|
|
|
169
136
|
|
|
170
137
|
udf.func(
|
|
171
138
|
"listWorkspaceItems",
|
|
172
|
-
async (
|
|
173
|
-
|
|
139
|
+
async (
|
|
140
|
+
ctx: RayfinContext<AppSchema, AudienceType.Fabric>,
|
|
141
|
+
workspaceId: string,
|
|
142
|
+
): Promise<unknown> => {
|
|
143
|
+
const token = ctx.Tokens.Fabric;
|
|
174
144
|
const res = await fetch(`${FABRIC_API}/workspaces/${workspaceId}/items`, {
|
|
175
145
|
headers: { Authorization: `Bearer ${token}` },
|
|
176
146
|
});
|
|
@@ -179,8 +149,8 @@ udf.func(
|
|
|
179
149
|
}
|
|
180
150
|
return res.json();
|
|
181
151
|
},
|
|
182
|
-
[
|
|
152
|
+
[],
|
|
183
153
|
);
|
|
184
154
|
```
|
|
185
155
|
|
|
186
|
-
> This is the same API used in [Get Fabric info](./get-fabric-info.md) — the difference is that there you call it at **authoring time** (with an `az` token) to gather endpoints, whereas here the **function** calls it at runtime with the
|
|
156
|
+
> This is the same API used in [Get Fabric info](./get-fabric-info.md) — the difference is that there you call it at **authoring time** (with an `az` token) to gather endpoints, whereas here the **deployed function** calls it at runtime with the app identity's token and resource permissions.
|
|
@@ -4,10 +4,14 @@ sidebar_position: 4
|
|
|
4
4
|
|
|
5
5
|
# Add Azure AI Foundry
|
|
6
6
|
|
|
7
|
-
Call an **Azure AI Foundry** (Azure OpenAI / Azure AI) resource from a function
|
|
7
|
+
Call an **Azure AI Foundry** (Azure OpenAI / Azure AI) resource from a deployed function using `AudienceType.AzureAI`.
|
|
8
|
+
|
|
9
|
+
Grant the [application identity](../index.md#application-authentication) the permissions required by your Azure AI resource and API.
|
|
8
10
|
|
|
9
11
|
Provide the resource **endpoint** (Azure AI Foundry → your resource → _Endpoint_). The token is a standard bearer token — send it with `fetch`, or wrap it with the [`ContextTokenCredential`](./index.md#wrapping-the-token-for-azure-sdk-clients) helper for an Azure AI SDK client.
|
|
10
12
|
|
|
13
|
+
`AppSchema` below is your app's data schema — the same type you pass to `RayfinClient<AppSchema>`. See [Writing functions](../writing-functions.md#accessing-data-and-request-context).
|
|
14
|
+
|
|
11
15
|
```ts
|
|
12
16
|
import {
|
|
13
17
|
UserDataFunctions,
|
|
@@ -22,8 +26,11 @@ const AI_ENDPOINT = "https://<resource>.services.ai.azure.com";
|
|
|
22
26
|
|
|
23
27
|
udf.func(
|
|
24
28
|
"callAzureAi",
|
|
25
|
-
async (
|
|
26
|
-
|
|
29
|
+
async (
|
|
30
|
+
ctx: RayfinContext<AppSchema, AudienceType.AzureAI>,
|
|
31
|
+
prompt: string,
|
|
32
|
+
): Promise<unknown> => {
|
|
33
|
+
const token = ctx.Tokens.AzureAI;
|
|
27
34
|
const res = await fetch(`${AI_ENDPOINT}/...`, {
|
|
28
35
|
method: "POST",
|
|
29
36
|
headers: {
|
|
@@ -37,7 +44,7 @@ udf.func(
|
|
|
37
44
|
}
|
|
38
45
|
return res.json();
|
|
39
46
|
},
|
|
40
|
-
[
|
|
47
|
+
[],
|
|
41
48
|
);
|
|
42
49
|
```
|
|
43
50
|
|
|
@@ -4,12 +4,14 @@ sidebar_position: 1
|
|
|
4
4
|
|
|
5
5
|
# Finding resource coordinates
|
|
6
6
|
|
|
7
|
-
Every connection recipe needs a real endpoint
|
|
7
|
+
Every connection recipe needs a real endpoint, such as the SQL server or the OneLake path.
|
|
8
8
|
This page explains **how to obtain those values from a Fabric item** so you (or an agent authoring a function) can fill them in with real data instead of guessing.
|
|
9
9
|
|
|
10
|
-
**You only need the workspace and item _display names_ to start** — for example, "lakehouseA in workspaceB".
|
|
10
|
+
**You only need the workspace and item _display names_ to start** — for example, "lakehouseA in workspaceB".
|
|
11
|
+
Everything else (the workspace ID, item ID, SQL endpoint, OneLake path) is derivable from here.
|
|
12
|
+
Resolve those values rather than asking for anything you can look up.
|
|
11
13
|
|
|
12
|
-
> **Why this matters:** don't hardcode a guessed endpoint. `ctx.
|
|
14
|
+
> **Why this matters:** don't hardcode a guessed endpoint. `ctx.Tokens` gives you an access token, but you still have to point the SDK at the correct URL — and that URL comes from the Fabric item's metadata, not from `process.env`.
|
|
13
15
|
|
|
14
16
|
## Ways to get coordinates
|
|
15
17
|
|
|
@@ -36,7 +38,7 @@ az account get-access-token \
|
|
|
36
38
|
--query accessToken -o tsv
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
> This is an **authoring-time** lookup — you are gathering coordinates to write into the function. At **runtime** the function itself
|
|
41
|
+
> This is an **authoring-time** lookup — you are gathering coordinates to write into the function. At **runtime** the function itself declares the audience on its `RayfinContext` annotation and reads `ctx.Tokens.<Audience>` (for the Fabric API specifically, `ctx.Tokens.Fabric` — see [Add a Fabric resource → Fabric REST API](./add-fabric-resource.md#fabric-rest-api)).
|
|
40
42
|
|
|
41
43
|
## Step 1 — find the workspace and item ID
|
|
42
44
|
|
|
@@ -52,7 +54,7 @@ List items of a given type in a workspace (to resolve a display name to its ID):
|
|
|
52
54
|
GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items?type=Lakehouse
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
`type` accepts any Fabric item type — `Lakehouse`, `Warehouse`, `SQLDatabase
|
|
57
|
+
`type` accepts any Fabric item type — for these recipes, use `Lakehouse`, `Warehouse`, or `SQLDatabase`.
|
|
56
58
|
Each entry returns `id`, `displayName`, and `type`. Take the `id` of the item you want.
|
|
57
59
|
|
|
58
60
|
## Step 2 — GET the item to read its coordinates
|
|
@@ -120,25 +122,6 @@ GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/sqlDatabases/{s
|
|
|
120
122
|
|
|
121
123
|
- **Server** → `properties.serverFqdn`, **database** → `properties.databaseName`. Both are also embedded in `properties.connectionString`.
|
|
122
124
|
|
|
123
|
-
### Eventhouse
|
|
124
|
-
|
|
125
|
-
```http
|
|
126
|
-
GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/eventhouses/{eventhouseId}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
```json
|
|
130
|
-
{
|
|
131
|
-
"type": "Eventhouse",
|
|
132
|
-
"properties": {
|
|
133
|
-
"queryServiceUri": "https://xxxxx.z5.kusto.fabric.microsoft.com",
|
|
134
|
-
"ingestionServiceUri": "https://ingest-xxxxx.z5.kusto.fabric.microsoft.com",
|
|
135
|
-
"databasesItemIds": ["<kql-database-item-id>"]
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
- **Cluster / query URI** → `properties.queryServiceUri`. Use with [Eventhouse and KQL](./add-fabric-resource.md#eventhouse-and-kql). Each KQL database inside the eventhouse is listed in `databasesItemIds`.
|
|
141
|
-
|
|
142
125
|
## Coordinate lookup table
|
|
143
126
|
|
|
144
127
|
| You need | Item type | Endpoint | Field |
|
|
@@ -147,7 +130,6 @@ GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/eventhouses/{ev
|
|
|
147
130
|
| SQL server (Warehouse) | Warehouse | `.../warehouses/{id}` | `properties.connectionString` |
|
|
148
131
|
| SQL server + database (SQL DB) | SQL Database | `.../sqlDatabases/{id}` | `properties.serverFqdn` / `properties.databaseName` |
|
|
149
132
|
| OneLake Files / Tables URL | Lakehouse | `.../lakehouses/{id}` | `properties.oneLakeFilesPath` / `oneLakeTablesPath` |
|
|
150
|
-
| Kusto query URI | Eventhouse | `.../eventhouses/{id}` | `properties.queryServiceUri` |
|
|
151
133
|
| Item GUID (any item) | any | `.../items?type={Type}` | `id` |
|
|
152
134
|
|
|
153
135
|
For item types not listed here, browse the [Fabric REST API item reference](https://learn.microsoft.com/en-us/rest/api/fabric/) — each item's **Get** operation returns its coordinates under `properties`.
|
|
@@ -4,12 +4,15 @@ sidebar_position: 5
|
|
|
4
4
|
|
|
5
5
|
# Connecting to external resources
|
|
6
6
|
|
|
7
|
-
Functions
|
|
8
|
-
You declare
|
|
7
|
+
Deployed Functions call external Azure and Fabric resources **as the app identity** using application authentication.
|
|
8
|
+
You declare the audiences a function needs and consume platform-provided, resource-scoped tokens through `ctx.Tokens`.
|
|
9
|
+
See [Application authentication](../index.md#application-authentication) for configuration, resource permissions, and the distinction from caller-scoped Rayfin DB access.
|
|
10
|
+
|
|
11
|
+
Developer CLI login and authoring-time endpoint discovery are separate from deployed runtime access; verify the deployed app identity's permissions even when a developer can access the resource.
|
|
9
12
|
|
|
10
13
|
## The pattern
|
|
11
14
|
|
|
12
|
-
Declare
|
|
15
|
+
Declare the audiences in the `RayfinContext` annotation, then read the scoped token off `ctx.Tokens`:
|
|
13
16
|
|
|
14
17
|
```ts
|
|
15
18
|
import {
|
|
@@ -21,19 +24,123 @@ import {
|
|
|
21
24
|
const udf = new UserDataFunctions();
|
|
22
25
|
|
|
23
26
|
udf.func(
|
|
24
|
-
"
|
|
25
|
-
async (
|
|
26
|
-
|
|
27
|
+
"accessStorage",
|
|
28
|
+
async (
|
|
29
|
+
ctx: RayfinContext<AppSchema, AudienceType.Storage>,
|
|
30
|
+
): Promise<string> => {
|
|
31
|
+
const token: string = ctx.Tokens.Storage;
|
|
27
32
|
// Use `token` with the resource's SDK or REST API.
|
|
28
33
|
return "ok";
|
|
29
34
|
},
|
|
30
|
-
[
|
|
35
|
+
[],
|
|
36
|
+
);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**The annotation is the declaration.** Listing an audience in `RayfinContext<Schema, Audiences>` is what registers the connection binding — there is nothing to add to the third argument of `udf.func()`.
|
|
40
|
+
|
|
41
|
+
`ctx.Tokens` is narrowed to exactly the audiences you declared, so an undeclared audience is a compile error rather than a runtime throw:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
async (
|
|
45
|
+
ctx: RayfinContext<AppSchema, AudienceType.Sql | AudienceType.Storage>,
|
|
46
|
+
) => {
|
|
47
|
+
const sqlToken: string = ctx.Tokens.Sql; // ok
|
|
48
|
+
const storageToken: string = ctx.Tokens.Storage; // ok
|
|
49
|
+
ctx.Tokens.Fabric; // compile error — not declared
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Values are typed `string`, not `string | undefined`.
|
|
54
|
+
Declaring an audience registers its binding, but does not guarantee token availability or resource access.
|
|
55
|
+
If the host does not supply a declared token, reading its `ctx.Tokens` property throws.
|
|
56
|
+
|
|
57
|
+
### The schema argument
|
|
58
|
+
|
|
59
|
+
`RayfinContext` takes your app schema first — the same one you pass to `RayfinClient<AppSchema>` — so the data client stays typed while you add audiences:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
async (ctx: RayfinContext<AppSchema, AudienceType.Sql>) => {
|
|
63
|
+
const data = ctx.getDataClient(); // typed by AppSchema
|
|
64
|
+
const token = ctx.Tokens.Sql;
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If a function needs audiences but no data access, pass the default schema explicitly:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
async (ctx: RayfinContext<Record<string, any>, AudienceType.Fabric>) => {
|
|
72
|
+
const token = ctx.Tokens.Fabric;
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## The third argument
|
|
77
|
+
|
|
78
|
+
`udf.func()` still takes a third argument, and it stays `[]`. Audience-scoped connections are declared entirely in the context annotation — there is nothing to add there:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
udf.func(
|
|
82
|
+
"syncWarehouse",
|
|
83
|
+
async (ctx: RayfinContext<AppSchema, AudienceType.Sql>): Promise<void> => {
|
|
84
|
+
const token = ctx.Tokens.Sql;
|
|
85
|
+
},
|
|
86
|
+
[],
|
|
87
|
+
);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Supported audiences
|
|
91
|
+
|
|
92
|
+
`AudienceType` is the source of truth — inventing a member will not compile:
|
|
93
|
+
|
|
94
|
+
`Sql`, `Storage`, `Fabric`, `AzureAI`, `ADO`.
|
|
95
|
+
|
|
96
|
+
A Power BI semantic model is **not** reachable this way; use the `fabric-semanticmodel` connector instead.
|
|
97
|
+
|
|
98
|
+
## How audiences reach the deployment
|
|
99
|
+
|
|
100
|
+
Type arguments are erased before your function runs, so the audiences have to be recovered at build time. `npx rayfin up` resolves them with the TypeScript compiler and writes the resolved union into the deployment metadata, which is what the worker binds against.
|
|
101
|
+
|
|
102
|
+
Because the compiler does the resolving, a type alias works:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
type SqlAccess = AudienceType.Sql;
|
|
106
|
+
|
|
107
|
+
// Resolves to AudienceType.Sql and binds a Sql connection.
|
|
108
|
+
async (ctx: RayfinContext<AppSchema, SqlAccess>) => {
|
|
109
|
+
const token = ctx.Tokens.Sql;
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Writing audiences **literally** is still the clearer default, and there is one case where it is required: if the functions project has no `tsconfig.json`, the CLI has no compiler to ask and falls back to reading the annotation's syntax. An alias then resolves to its own name rather than the audience it stands for. The CLI warns when it is in that mode — treat the warning as a real problem, not noise.
|
|
114
|
+
|
|
115
|
+
The context parameter must also carry an explicit `RayfinContext<...>` annotation. Typegen identifies the context parameter by that annotation; an unannotated parameter is treated as a request-body parameter instead.
|
|
116
|
+
|
|
117
|
+
## Migrating from `ctx.getToken()`
|
|
118
|
+
|
|
119
|
+
`ctx.getToken(audienceType)` is **deprecated**. It is flagged by `@typescript-eslint/no-deprecated`, which the scaffolded ESLint config reports as an error.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
// Before
|
|
123
|
+
udf.func(
|
|
124
|
+
"queryData",
|
|
125
|
+
async (ctx: RayfinContext): Promise<void> => {
|
|
126
|
+
const token = ctx.getToken(AudienceType.Sql);
|
|
127
|
+
},
|
|
128
|
+
[udf.connection({ audienceType: AudienceType.Sql })],
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// After
|
|
132
|
+
udf.func(
|
|
133
|
+
"queryData",
|
|
134
|
+
async (ctx: RayfinContext<AppSchema, AudienceType.Sql>): Promise<void> => {
|
|
135
|
+
const token = ctx.Tokens.Sql;
|
|
136
|
+
},
|
|
137
|
+
[],
|
|
31
138
|
);
|
|
32
139
|
```
|
|
33
140
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
141
|
+
Move the audience from the third argument into the annotation, then replace the call with the property.
|
|
142
|
+
|
|
143
|
+
**Both halves are required.** The array keeps working at *runtime* — array audiences are unioned with the annotated ones, so a deployed function still binds the connection. But it no longer carries any type information: `TokenTypes` defaults to `never`, so a handler left as `ctx: RayfinContext<AppSchema>` stops compiling at `ctx.getToken(AudienceType.Sql)` even with `Sql` declared in the array. Add the audience to the annotation first; the array alone is not enough.
|
|
37
144
|
|
|
38
145
|
## Wrapping the token for Azure SDK clients
|
|
39
146
|
|
|
@@ -51,12 +158,12 @@ class ContextTokenCredential implements TokenCredential {
|
|
|
51
158
|
}
|
|
52
159
|
```
|
|
53
160
|
|
|
54
|
-
Pass `new ContextTokenCredential(ctx.
|
|
161
|
+
Pass `new ContextTokenCredential(ctx.Tokens.X)` wherever an Azure SDK client asks for a credential.
|
|
55
162
|
The per-resource guides below use this helper.
|
|
56
163
|
|
|
57
164
|
## Choose a recipe
|
|
58
165
|
|
|
59
|
-
Find what you want to connect to. Each row links to a task-oriented walkthrough; the `AudienceType` is the value you
|
|
166
|
+
Find what you want to connect to. Each row links to a task-oriented walkthrough; the `AudienceType` is the value you put in the context annotation and the key you read off `ctx.Tokens`. A single audience can back more than one use case (for example `Storage` covers both Fabric OneLake and Azure Blob).
|
|
60
167
|
|
|
61
168
|
| I want to connect to… | `AudienceType` | Recipe |
|
|
62
169
|
| ------------------------------------------------ | -------------- | -------------------------------------------------------------------- |
|
|
@@ -64,26 +171,24 @@ Find what you want to connect to. Each row links to a task-oriented walkthrough;
|
|
|
64
171
|
| Azure SQL Database | `Sql` | [Add a Fabric resource](./add-fabric-resource.md#sql-databases) |
|
|
65
172
|
| Fabric OneLake files | `Storage` | [Add a Fabric resource](./add-fabric-resource.md#onelake-files) |
|
|
66
173
|
| Azure Blob / Table / Queue | `Storage` | [Add an Azure resource](./add-azure-resource.md#blob-storage) |
|
|
67
|
-
| Fabric Eventhouse (KQL) | `Kusto` | [Add a Fabric resource](./add-fabric-resource.md#eventhouse-and-kql) |
|
|
68
|
-
| Azure Data Explorer | `Kusto` | [Add a Fabric resource](./add-fabric-resource.md#eventhouse-and-kql) |
|
|
69
174
|
| Microsoft Fabric REST API | `Fabric` | [Add a Fabric resource](./add-fabric-resource.md#fabric-rest-api) |
|
|
70
|
-
| Azure Key Vault | `KeyVault` | [Add an Azure resource](./add-azure-resource.md#key-vault) |
|
|
71
|
-
| Azure Cosmos DB | `CosmosDB` | [Add an Azure resource](./add-azure-resource.md#cosmos-db) |
|
|
72
|
-
| Azure Event Grid | `EventGrid` | [Add an Azure resource](./add-azure-resource.md#event-grid) |
|
|
73
175
|
| Azure AI Foundry | `AzureAI` | [Add Azure AI Foundry](./add-foundry.md) |
|
|
74
176
|
| Azure DevOps | `ADO` | [Add Azure DevOps](./add-ado.md) |
|
|
75
|
-
| WorkIQ | `WorkIQ` | [Add WorkIQ](./add-work-iq.md) |
|
|
76
177
|
|
|
77
|
-
To look up a Fabric item's connection coordinates (SQL endpoint
|
|
178
|
+
To look up a Fabric item's connection coordinates (SQL endpoint or OneLake path), see [Get Fabric info](./get-fabric-info.md).
|
|
78
179
|
|
|
79
180
|
## Rules
|
|
80
181
|
|
|
182
|
+
- **Declare generic audiences in the annotation** and read them with `ctx.Tokens.<Audience>`. Prefer literal `AudienceType.X`, and keep a `tsconfig.json` in the functions project so the CLI can resolve anything that isn't.
|
|
183
|
+
- **Pass `[]` as the third argument** to `udf.func()`.
|
|
81
184
|
- **Use real endpoint URLs** — don't hardcode a guess or read them from `process.env`. For Fabric items, [Get Fabric info](./get-fabric-info.md) shows how to look them up.
|
|
82
|
-
-
|
|
83
|
-
-
|
|
185
|
+
- Never acquire tokens manually.
|
|
186
|
+
- Grant resource access to the app identity, and keep its tokens server-side; never return them as function results.
|
|
84
187
|
- Install resource SDK packages in `rayfin/functions/package.json`, not the project root.
|
|
85
188
|
|
|
86
189
|
## Local development
|
|
87
190
|
|
|
88
|
-
|
|
191
|
+
`npx rayfin dev` and `npx rayfin dev functions apply` start a local Azure Functions Core Tools host.
|
|
192
|
+
External resource tokens use the identity and permissions of the account the builder signs in with in the local Functions host.
|
|
193
|
+
Deployed Functions instead use the [application identity](../index.md#application-authentication).
|
|
89
194
|
See [`npx rayfin dev functions apply`](../../cli/functions/dev-apply.md).
|
|
@@ -29,6 +29,44 @@ npx rayfin functions init
|
|
|
29
29
|
This creates `rayfin/functions/`, installs dependencies, and generates the initial `types.ts`.
|
|
30
30
|
See [`npx rayfin functions init`](../cli/functions/init.md) for the full command reference.
|
|
31
31
|
|
|
32
|
+
## Application authentication
|
|
33
|
+
|
|
34
|
+
Enabled Functions require explicit application authentication in `rayfin/rayfin.yml`:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
services:
|
|
38
|
+
functions:
|
|
39
|
+
enabled: true
|
|
40
|
+
auth:
|
|
41
|
+
type: application
|
|
42
|
+
buildCommand: npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
New Functions scaffolds set `auth.type: application`.
|
|
46
|
+
For an existing app, set it explicitly; loading the configuration does not add a default or migrate an older auth mode.
|
|
47
|
+
Disabled Functions may omit `auth`, but any supplied `auth` must include `type: application`.
|
|
48
|
+
No feature flag is needed.
|
|
49
|
+
|
|
50
|
+
Full `npx rayfin up` and normal `npx rayfin dev` validate this setting before applying project settings to either the Fabric or Docker backend.
|
|
51
|
+
Run a full `npx rayfin up` to apply the YAML auth mode to an existing remote app.
|
|
52
|
+
Standalone `npx rayfin dev functions apply`, `npx rayfin up functions deploy`, and `npx rayfin up staticapp deploy` do not perform this project-settings validation or change the remote Functions auth mode.
|
|
53
|
+
|
|
54
|
+
Deployed Functions use two separate authentication paths:
|
|
55
|
+
|
|
56
|
+
| Access path | Credential | Identity and permissions |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| External connections through `ctx.Tokens.*` | Platform-provided resource token | Application identity and its permissions on the external resource |
|
|
59
|
+
| Rayfin DB through `ctx.getDataClient()` | The invocation's Rayfin token | The caller's identity and permissions on the Rayfin DB |
|
|
60
|
+
|
|
61
|
+
For current Fabric apps, the app identity is the owner of the Fabric app item.
|
|
62
|
+
External connections therefore use the item owner's permissions, not those of whichever app user invokes the function.
|
|
63
|
+
Grant that identity the permissions required by each external resource and API your functions call.
|
|
64
|
+
Declaring an audience or deploying Functions does not grant those permissions.
|
|
65
|
+
App sign-in and authorization to invoke a function remain separate from the app identity's external resource access.
|
|
66
|
+
Rayfin DB access always uses the Rayfin token and preserves the caller's identity and database permissions.
|
|
67
|
+
Setting `services.functions.auth.type: application` does not switch Rayfin DB access to the application identity.
|
|
68
|
+
See [Connecting to external resources](./connections/index.md) for audience declarations, permissions, and local development.
|
|
69
|
+
|
|
32
70
|
## Project structure
|
|
33
71
|
|
|
34
72
|
After `npx rayfin functions init`, the functions project lives at `rayfin/functions/`:
|
|
@@ -86,6 +124,6 @@ See [`npx rayfin dev functions apply`](../cli/functions/dev-apply.md) for detail
|
|
|
86
124
|
|
|
87
125
|
- [Writing functions](./writing-functions.md) — the `udf.func()` API, `RayfinContext`, and data access.
|
|
88
126
|
- [Type generation](./typegen.md) — how `types.ts` is generated and kept in sync.
|
|
89
|
-
- [Connecting to external resources](./connections/index.md) —
|
|
127
|
+
- [Connecting to external resources](./connections/index.md) — app-identity access to SQL, Storage, the Fabric REST API, and more.
|
|
90
128
|
- [Secrets](./secrets.md) — reading secrets from inside a function.
|
|
91
129
|
- [Invoking functions from the frontend](./invoking-from-frontend.md) — calling functions with `RayfinClient`.
|
|
@@ -4,7 +4,7 @@ sidebar_position: 3
|
|
|
4
4
|
|
|
5
5
|
# Secrets
|
|
6
6
|
|
|
7
|
-
Functions read secret values
|
|
7
|
+
Functions read secret values as typed properties on `ctx.Secrets`, part of [`RayfinContext`](./writing-functions.md#rayfincontext-api).
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import {
|
|
@@ -16,23 +16,34 @@ const udf = new UserDataFunctions();
|
|
|
16
16
|
|
|
17
17
|
udf.func(
|
|
18
18
|
"readApiKey",
|
|
19
|
-
async (ctx: RayfinContext): Promise<string> => {
|
|
20
|
-
|
|
21
|
-
if (!apiKey) {
|
|
22
|
-
throw new Error("Missing THIRD_PARTY_API_KEY secret.");
|
|
23
|
-
}
|
|
24
|
-
return apiKey;
|
|
19
|
+
async (ctx: RayfinContext<AppSchema>): Promise<string> => {
|
|
20
|
+
return ctx.Secrets.THIRD_PARTY_API_KEY;
|
|
25
21
|
},
|
|
26
22
|
[],
|
|
27
23
|
);
|
|
28
24
|
```
|
|
29
25
|
|
|
26
|
+
There is nothing to add to the function's declaration and nothing to add to your data schema — declaring the secret with the CLI is what types it.
|
|
27
|
+
|
|
28
|
+
## How the names are typed
|
|
29
|
+
|
|
30
|
+
`npx rayfin secret set <NAME>` records the name in `rayfin.yml`, and the CLI regenerates `rayfin/functions/src/secrets.generated.ts`. That file augments the SDK's `RayfinSecretRegistry` interface, which is what narrows `ctx.Secrets`:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
ctx.Secrets.THIRD_PARTY_API_KEY; // string
|
|
34
|
+
ctx.Secrets.NOT_DECLARED; // compile error
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- Values are typed `string`, not `string | undefined` — the name was declared, so the value is modelled as present. Reading a declared secret that was not supplied throws a diagnosable error rather than silently yielding `undefined`.
|
|
38
|
+
- Nothing imports `secrets.generated.ts`; it only has to be part of the compilation. **Never hand-edit it** — the CLI overwrites it, and the typegen watcher deliberately ignores it so regenerating doesn't loop.
|
|
39
|
+
- Deleting a secret narrows the type, so stale references stop compiling instead of failing at invocation.
|
|
40
|
+
|
|
30
41
|
## How resolution works
|
|
31
42
|
|
|
32
|
-
`ctx.
|
|
43
|
+
`ctx.Secrets.<NAME>` resolves in this order:
|
|
33
44
|
|
|
34
45
|
1. The host-provided secret bag delivered with the invocation.
|
|
35
|
-
2. `process.env[
|
|
46
|
+
2. `process.env[NAME]` as a fallback.
|
|
36
47
|
|
|
37
48
|
## Setting secrets
|
|
38
49
|
|
|
@@ -48,7 +59,7 @@ See [Managing secrets](../cli/secrets.md) for the full `npx rayfin secret` comma
|
|
|
48
59
|
## Secrets in local development
|
|
49
60
|
|
|
50
61
|
The host-provided secret bag is only present for deployed invocations.
|
|
51
|
-
When you debug locally with `npx rayfin dev functions apply`, add the same key under `Values` in `rayfin/functions/local.settings.json` so it flows into `process.env` and is picked up by the
|
|
62
|
+
When you debug locally with `npx rayfin dev functions apply`, add the same key under `Values` in `rayfin/functions/local.settings.json` so it flows into `process.env` and is picked up by the fallback:
|
|
52
63
|
|
|
53
64
|
```jsonc
|
|
54
65
|
{
|
|
@@ -64,7 +75,24 @@ When you debug locally with `npx rayfin dev functions apply`, add the same key u
|
|
|
64
75
|
`local.settings.json` is git-ignored, so these values stay on your machine.
|
|
65
76
|
See [Secrets in local development](../cli/secrets.md#using-secrets-in-local-development) for more.
|
|
66
77
|
|
|
78
|
+
## The deprecated `ctx.getSecret()`
|
|
79
|
+
|
|
80
|
+
`ctx.getSecret(name)` returns `string | undefined` and is **deprecated** — it is flagged by `@typescript-eslint/no-deprecated`, which the scaffolded ESLint config reports as an error.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// Before
|
|
84
|
+
const apiKey = ctx.getSecret("THIRD_PARTY_API_KEY");
|
|
85
|
+
if (!apiKey) {
|
|
86
|
+
throw new Error("Missing THIRD_PARTY_API_KEY secret.");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// After
|
|
90
|
+
const apiKey = ctx.Secrets.THIRD_PARTY_API_KEY;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
It remains valid for a value deliberately **not** modelled in `rayfin.yml` — a host-injected environment variable, for example. Suppress the lint at that one call site rather than project-wide.
|
|
94
|
+
|
|
67
95
|
## Best practices
|
|
68
96
|
|
|
69
|
-
-
|
|
97
|
+
- Declare every secret with `npx rayfin secret set <NAME>` and read it from `ctx.Secrets` — never hard-code a secret name string.
|
|
70
98
|
- Use the `process.env` fallback only for local debugging — do not make it your primary production secret source.
|