@microsoft/rayfin-guide 1.36.0-alpha.1756 → 1.36.0-alpha.1818

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.
@@ -62,6 +62,41 @@ npx rayfin up
62
62
 
63
63
  If you are not signed in, the CLI launches an interactive login flow automatically.
64
64
 
65
+ ### Prepare Fabric capacity
66
+
67
+ Before creating the Rayfin item, `rayfin up` checks whether the target workspace already has Fabric capacity.
68
+ If the workspace reports an assigned capacity, Rayfin uses it without changing or reevaluating the assignment.
69
+
70
+ On a first interactive deployment without a workspace target or `--capacity-id`, Rayfin asks you to choose:
71
+
72
+ 1. `Use new workspace [Recommended]` runs workspace and capacity readiness.
73
+ 2. `Select existing workspace` skips capacity readiness and opens the accessible-workspace picker.
74
+
75
+ Explicit workspace options and recorded deployments continue directly to their existing targeting flow without showing this choice.
76
+ Dry-run invocations do not show the choice.
77
+ An interactive invocation with `--capacity-id <id>` automatically prepares a new workspace and assigns that capacity without showing the workspace choice.
78
+ An untargeted non-interactive invocation automatically prepares a new workspace without prompting.
79
+ Pass `--capacity-id <id>` to use a specific capacity for that new workspace.
80
+ Pass an existing workspace target to deploy there instead.
81
+
82
+ When the workspace needs capacity, an interactive deployment asks for confirmation before assigning the selected or trial capacity.
83
+ Pass `--yes` to approve a deterministic capacity assignment without the prompt:
84
+
85
+ ```bash
86
+ npx rayfin up --yes
87
+ ```
88
+
89
+ To select a specific existing capacity, pass its Fabric capacity ID.
90
+ This explicitly approves assigning that capacity:
91
+
92
+ ```bash
93
+ npx rayfin up --capacity-id <capacity-guid>
94
+ ```
95
+
96
+ Do not combine `--capacity-id` with `--workspace`, `--workspace-id`, or `--workspace-uri`.
97
+ If multiple premium capacities are available, select one explicitly with `--capacity-id`.
98
+ An existing recorded deployment keeps its current workspace capacity and ignores a newly supplied capacity ID.
99
+
65
100
  ### Choose a unique Fabric item name
66
101
 
67
102
  By default, `rayfin up` uses the project ID from `rayfin.yml` as the Fabric item name.
@@ -84,7 +119,7 @@ npx rayfin up \
84
119
  --output json
85
120
  ```
86
121
 
87
- Do not pass `--yes` unless reusing an existing same-named item is intentional.
122
+ The `--yes` option also approves reuse of an existing same-named item, so use it only when both automatic capacity assignment and item reuse are acceptable.
88
123
 
89
124
  ### What `rayfin up` does
90
125
 
@@ -28,6 +28,15 @@ If you do not already know the workspace and item IDs, run [`connector search`](
28
28
  | `-y, --yes` | no | Auto-accept overwrite and confirmation prompts (non-interactive). |
29
29
  | `-v, --verbose` | no | Verbose diagnostics. |
30
30
 
31
+ ## Authentication
32
+
33
+ `connector add` writes `auth.type: application` for Category A connectors: `fabric-sqlanalytics`, `fabric-warehouse`, and `fabric-sqldatabase`.
34
+ The connector accesses the data source with the app's identity rather than the signed-in end user's identity.
35
+ For per-user data-source access, explicitly set `auth.type: delegated` in `rayfin.yml` before deploying.
36
+
37
+ Category B connectors continue to require `auth.type: delegated`.
38
+ Existing declarations are not migrated, and omitting `auth.type` remains a validation error.
39
+
31
40
  ## Scoping operations
32
41
 
33
42
  Without `--operations`, `connector add` writes **every** operation the catalog allows for the type. Prefer scoping at add time over hand-editing YAML afterwards:
@@ -46,7 +55,7 @@ connectors:
46
55
  workspaceId: ${WS_ID}
47
56
  itemId: ${ITEM_ID}
48
57
  auth:
49
- type: delegated
58
+ type: application
50
59
  operations:
51
60
  - name: read
52
61
  - name: update
@@ -97,6 +106,7 @@ With `--json`, the same information is available under `install`:
97
106
 
98
107
  Running `connector add` against a name already in `rayfin.yml` refreshes the declaration.
99
108
  It prompts before overwriting, or requires `--yes` when non-interactive.
109
+ This rewrites `auth.type` to the catalog default, so reapply an explicit `delegated` setting for a Category A connector after re-adding it if needed.
100
110
 
101
111
  Your generated entity files under `rayfin/connectors/<name>/` are **preserved**.
102
112
  Only `metadata.json` is rewritten, by schema discovery.
@@ -35,7 +35,7 @@ The commands available to a connector, and the code you write against it, depend
35
35
 
36
36
  | | Category A — GraphQL entity connectors | Category B — function-bridge connectors |
37
37
  | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
38
- | **Types** | `fabric-sqlanalytics`, `fabric-warehouse`, `fabric-sqldatabase`, `fabric-graphql` | `fabric-semanticmodel`; `kusto` (**experimental**) |
38
+ | **Types** | `fabric-sqlanalytics`, `fabric-warehouse`, `fabric-sqldatabase` | `fabric-semanticmodel`; `kusto` (**experimental**) |
39
39
  | **App surface** | Generated entity files with typed CRUD through the data client | Named operations carrying raw queries |
40
40
  | **Operations** | `read` only for `fabric-sqlanalytics` (Lakehouse SQL endpoints are read-only); `read`, `create`, `update`, `delete` for `fabric-warehouse` and `fabric-sqldatabase` (narrowable) | `executeQuery` only |
41
41
  | **Auth** | `delegated` or configured per project | Must be `delegated` |
@@ -54,11 +54,44 @@ Applies to `--entity` mode only.
54
54
 
55
55
  Applies to `--entity` and `--query` modes.
56
56
 
57
- - **SQL** — must start with `SELECT` or `WITH`; must be a single statement (a trailing `;` is fine, an embedded one is not); rejects `INSERT`, `UPDATE`, `DELETE`, `MERGE`, `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `EXEC`/`EXECUTE`, and `INTO` anywhere outside a string literal.
57
+ - **SQL** — must start with `SELECT` or `WITH`; an embedded `;` is rejected while a trailing `;` is allowed; rejects `INSERT`, `UPDATE`, `DELETE`, `MERGE`, `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `EXEC`/`EXECUTE`, and `INTO` anywhere outside a string literal.
58
+ - **SQL result contract** — the query must produce one result set. If Tedious emits a second result set, inspection rejects the query instead of combining rows with a different column contract.
58
59
  - **DAX** — must start with `EVALUATE`.
59
60
  - `--query <path>` must resolve to a `.sql` or `.dax` file inside the project root; paths outside it are rejected. The project root is the directory containing `rayfin/rayfin.yml` when one is found. Direct mode (no `--name`) falls back to the current working directory if no `rayfin.yml` exists, so `--query` never requires a Rayfin project.
60
61
  - `--rows <n>` caps the sample size — maximum 100. The default is mode-specific: entity listing (neither `--entity` nor `--query`) defaults to **100**, while `--entity` and `--query` sampling default to **10**. The result reports `truncated: true` when the source had more rows than the cap; inspect fetches one row beyond the cap to detect that, then discards it.
61
62
 
63
+ ## SQL column types and values
64
+
65
+ SQL inspection reads column types from Tedious result metadata, including when a query returns zero rows.
66
+ It never guesses a column type from row values.
67
+ Plain output lists each column as `name (type)` before populated or empty results.
68
+ If the contract exceeds the terminal width, it folds between column entries.
69
+
70
+ The `columns[].type` field in JSON uses this normalized vocabulary:
71
+
72
+ | Normalized type | Tedious metadata types |
73
+ | ------------------ | ------------------------------------------------------------------------ |
74
+ | `integer` | `TinyInt`, `SmallInt`, `Int`, `BigInt`, `IntN` |
75
+ | `decimal` | `Decimal`, `Numeric`, money types, and their nullable forms |
76
+ | `floating-point` | `Real`, `Float`, `FloatN` |
77
+ | `text` | Character and Unicode text types, plus `Xml` |
78
+ | `boolean` | `Bit`, `BitN` |
79
+ | `date` | `Date` |
80
+ | `time` | `Time` |
81
+ | `datetime` | `SmallDateTime`, `DateTime`, `DateTimeN`, `DateTime2`, `DateTimeOffset` |
82
+ | `uniqueidentifier` | `UniqueIdentifier` |
83
+ | `binary` | `Binary`, `VarBinary`, `Image` |
84
+ | `unknown` | `Null`, `Variant`, `UDT`, `TVP`, and unrecognized or custom types |
85
+
86
+ Plain output renders SQL `date` values as `YYYY-MM-DD`, so the calendar value does not shift with the local time zone.
87
+ SQL `time` values render as the UTC time portion `HH:mm:ss.sss`, without Tedious' internal 1970 date anchor.
88
+ SQL `datetime` and `datetime2` are timezone-naive values that Tedious represents using a JavaScript `Date`; plain and JSON output therefore use an ISO value with `Z` by driver convention.
89
+ SQL `datetimeoffset` is also returned as a JavaScript `Date`, so its original offset is not preserved.
90
+ SQL `bigint` row values are strings, while decimal and numeric row values are JavaScript numbers and can carry JavaScript precision limitations.
91
+ Binary and buffer-backed custom values render as terminal-safe `0x` hexadecimal in plain output and use the existing column-width truncation marker when needed.
92
+ JSON row serialization is unchanged: JavaScript `Date` values remain ISO strings, while `columns[].type` now reports the metadata-derived normalized type instead of `unknown`.
93
+ Queries that produce a second SQL result set are rejected when the driver emits its second column contract, including newline-separated batches without semicolons.
94
+
62
95
  ## Examples
63
96
 
64
97
  ```bash
@@ -14,6 +14,10 @@ npx rayfin up functions deploy [-v | --verbose] [--skip-build] [--json]
14
14
 
15
15
  `npx rayfin up` already deploys functions as part of a full deployment. Use `up functions deploy` when you want to run **only** the functions step — for example to retry after a functions deploy failed, or to push a functions-only change without redeploying the rest of the app.
16
16
 
17
+ This standalone command uploads function code; it does not validate or apply `services.functions.auth.type` from YAML or migrate the remote Functions auth mode.
18
+ After setting `services.functions.auth.type: application` for an existing app, run a full `npx rayfin up` to apply project settings.
19
+ See [Application authentication](../../functions/index.md#application-authentication).
20
+
17
21
  ## Prerequisites
18
22
 
19
23
  Run `npx rayfin up` at least once first. This command deploys to an existing remote item, so a remote endpoint must already exist. If there is no active deployment, run a full `npx rayfin up`.
@@ -35,4 +39,4 @@ Run `npx rayfin up` at least once first. This command deploys to an existing rem
35
39
 
36
40
  - [`functions init`](./init.md) — scaffold and enable functions.
37
41
  - [`dev functions apply`](./dev-apply.md) — run and debug functions locally before deploying.
38
- - [Managing Secrets](../secrets.md) — push secrets that deployed functions read via `ctx.getSecret`.
42
+ - [Managing Secrets](../secrets.md) — push secrets that deployed functions read via `ctx.Secrets`.
@@ -42,6 +42,11 @@ This command does not start the frontend.
42
42
  Run the Vite frontend separately to invoke local functions through `/.rayfin/api/<name>`, or use `npx rayfin dev` to start both together.
43
43
  If the local Functions host is unavailable, the Vite adapter returns HTTP 502 instead of invoking deployed function code.
44
44
 
45
+ This standalone command does not validate or apply the project's Functions auth setting.
46
+ Full `npx rayfin up` and normal `npx rayfin dev` perform that validation when applying project settings.
47
+ Run a full `npx rayfin up` to apply [`services.functions.auth.type: application`](../../functions/index.md#application-authentication) to the remote app.
48
+ For local token identity, see [Local development](../../functions/connections/index.md#local-development).
49
+
45
50
  ## Automatic recompilation
46
51
 
47
52
  Both `npx rayfin dev functions apply` and `npx rayfin dev` build the functions package once, then run its `build:watch` script alongside the local Functions host if the script is configured.
@@ -67,7 +72,7 @@ With debugging enabled (default), attach your debugger to the inspector port (`9
67
72
 
68
73
  ## Secrets in local development
69
74
 
70
- Locally there is no deployed secret bag, so `ctx.getSecret(name)` falls back to `process.env`. To provide a secret, add it under `Values` in `rayfin/functions/local.settings.json`; the functions host loads those entries into `process.env`. See [Managing Secrets](../secrets.md#using-secrets-in-local-development).
75
+ Locally there is no deployed secret bag, so `ctx.Secrets.<NAME>` falls back to `process.env`. To provide a secret, add it under `Values` in `rayfin/functions/local.settings.json`; the functions host loads those entries into `process.env`. See [Managing Secrets](../secrets.md#using-secrets-in-local-development).
71
76
 
72
77
  ## Next step
73
78
 
@@ -80,3 +85,4 @@ npx rayfin up functions deploy
80
85
  ```
81
86
 
82
87
  See [`up functions deploy`](./deploy.md).
88
+ The standalone deployment uploads function code; it does not apply YAML auth settings or migrate the remote Functions auth mode.
@@ -7,6 +7,8 @@ sidebar_position: 4
7
7
  Rayfin functions are server-side user-defined functions (UDFs) that run in the Fabric runtime and are invocable from your frontend through `RayfinClient`. Use them for logic that must run on the backend — secrets and API keys, privileged data access, server-side validation, and anything that should not be exposed or tampered with in client code.
8
8
 
9
9
  The functions project lives at `rayfin/functions/` and is enabled by the `services.functions.enabled` flag in `rayfin.yml` (set for you the first time you run [`functions init`](./init.md)).
10
+ Enabled Functions also require explicit `services.functions.auth.type: application`, which new scaffolds set.
11
+ See [Application authentication](../../functions/index.md#application-authentication) for existing-app configuration and downstream resource permissions.
10
12
 
11
13
  Each command has its own reference page:
12
14
 
@@ -34,8 +36,8 @@ functions init → write UDFs in src/function_app.ts → dev functions apply
34
36
  - `rayfin/functions/src/function_app.ts` — where you register UDFs with `udf.func()`.
35
37
  - `rayfin/functions/src/types.ts` — auto-generated `AppFunctionsSchema`; regenerated by `functions init` (one-shot) and by the watcher inside `dev functions apply`.
36
38
  - `rayfin/functions/{package.json,host.json,tsconfig.json,local.settings.json}` — the functions app manifest, host config, TypeScript project references, and local settings.
37
- - `rayfin.yml` — the `services.functions` block (`enabled`, `buildCommand`).
39
+ - `rayfin.yml` — the `services.functions` block (`enabled`, `auth.type`, `buildCommand`).
38
40
 
39
41
  ## Secrets
40
42
 
41
- Functions read secrets at runtime with `ctx.getSecret(name)`, backed by the host secret bag with a `process.env` fallback. Manage remote secrets with `npx rayfin secret set` — or bulk-set them from a file with `npx rayfin secret set --env-file` — see [Managing Secrets](../secrets.md).
43
+ Functions read secrets at runtime as typed properties on `ctx.Secrets`, backed by the host secret bag with a `process.env` fallback. Manage remote secrets with `npx rayfin secret set` — or bulk-set them from a file with `npx rayfin secret set --env-file` — see [Managing Secrets](../secrets.md).
@@ -24,12 +24,15 @@ Run this from a directory that already contains a `rayfin/` project (i.e. you ha
24
24
  ## What it does
25
25
 
26
26
  1. **Scaffolds** `rayfin/functions/` with a starter function app, `host.json`, `tsconfig.json`, `package.json`, and `local.settings.json`.
27
- 2. **Enables the service** in `rayfin.yml` by setting `services.functions.enabled: true` and `services.functions.buildCommand: 'npm run build'`.
27
+ 2. **Enables the scaffolded service** in `rayfin.yml` by setting `services.functions.enabled: true`, `services.functions.auth.type: application`, and `services.functions.buildCommand: 'npm run build'`.
28
28
  3. **Installs dependencies** for the functions project.
29
29
  4. **Builds** the project.
30
30
  5. **Generates types** — runs a one-shot typegen to produce `rayfin/functions/src/types.ts` (the `AppFunctionsSchema`).
31
31
  6. **Installs AI agent files** so assistants understand the functions surface.
32
32
 
33
+ Enabled Functions require explicit application authentication.
34
+ For existing apps, see [Application authentication](../../functions/index.md#application-authentication) for the configuration and full-deployment requirement.
35
+
33
36
  ## Runtime version
34
37
 
35
38
  Fresh and forced scaffolds pin `@microsoft/fabric-user-data-functions` to the exact version of the running Rayfin CLI, matching connector scaffolding.
@@ -60,6 +63,9 @@ rayfin/
60
63
  - **Without `--force`** on an existing project, it preserves your `function_app.ts` and only refreshes dependencies, build, and generated types.
61
64
  - **With `--force`**, it overwrites the scaffold (a warning is shown before your files are replaced).
62
65
 
66
+ Re-running without `--force` does not rewrite the existing Functions auth setting.
67
+ Set `services.functions.auth.type: application` explicitly in an existing app rather than relying on a re-run to migrate it.
68
+
63
69
  ## Next step
64
70
 
65
71
  Start the local host and typegen watcher:
@@ -89,7 +89,7 @@ Connectors let a Rayfin app read from — and, for some types, write to — Micr
89
89
 
90
90
  ### Secrets
91
91
 
92
- Secrets are encrypted values stored on your deployed Rayfin item and read at runtime — for example by [functions](./functions/index.md) via `ctx.getSecret`. See [Managing Secrets](./secrets.md) for the full guide.
92
+ Secrets are encrypted values stored on your deployed Rayfin item and read at runtime — for example by [functions](./functions/index.md) via `ctx.Secrets`. See [Managing Secrets](./secrets.md) for the full guide.
93
93
 
94
94
  | Command | Description |
95
95
  | --- | --- |
@@ -129,18 +129,30 @@ export RAYFIN_TELEMETRY_OPTOUT=1
129
129
 
130
130
  ## Diagnostic logs
131
131
 
132
- `npx rayfin up` and workflow-based `npx rayfin dev` record detailed diagnostics under `~/.rayfin/logs/` even when `--verbose` is absent, including when using `--json` or `--output json`.
132
+ `npx rayfin up`, workflow-based `npx rayfin dev`, and `npx rayfin dev functions apply` record detailed diagnostics under `~/.rayfin/logs/` even when `--verbose` is absent, including when using `--json` or `--output json`.
133
133
  After a failure, open the file identified by `Diagnostic log:` to inspect the original invocation without rerunning it.
134
134
  JSON failures include the same path in the `diagnosticLog` field of the single result object.
135
135
  `dev` JSON failures also include a `hint` with recovery guidance, including provider/configuration preflight errors and unexpected failures.
136
136
 
137
- Adding `--verbose` also mirrors diagnostic records to stderr while `up` or `dev` runs.
137
+ Adding `--verbose` also mirrors diagnostic records to stderr while these commands run.
138
138
  The CLI rejects combining `--verbose` with `--json` or `--output json`; detailed diagnostics are still recorded in the log file without `--verbose`.
139
- This capability applies to workflow-based `up` and `dev` sessions, not standalone subcommands or Docker maintenance flags such as `dev --stop`.
140
-
141
- `dev` preserves normal frontend and Functions terminal output and flushes its log after cleanup on Ctrl-C, runtime failure, or normal completion.
139
+ Other standalone subcommands and Docker maintenance flags such as `dev --stop` do not record these logs.
140
+
141
+ Local Functions sessions show function endpoints, the debugger address, application output, and warnings or errors by default.
142
+ Recognized host startup and configuration detail, HTTP request metadata, and successful initial build output are kept in diagnostics; use `--verbose` to mirror that detail to the terminal.
143
+ When the initial build fails, human output includes a bounded tail of compiler output, and JSON errors include it in `buildOutput`.
144
+ The tail retains up to 100 complete lines and 64 KiB, with an explicit marker when earlier output is omitted.
145
+ Verbose mode does not replay the same compiler output a second time.
146
+ Terminal output preserves stack-frame paths and line numbers, while masking credentials and email addresses.
147
+ Application lines up to 16 KiB are preserved; oversized lines are replaced with an explicit truncation marker.
148
+ Persistent diagnostic logs continue to apply their separate privacy and size limits.
149
+ Failed HTTP responses show their status and, when request metadata is available, the method and path without query strings.
150
+ Unrecognized output remains visible.
151
+ Frontend output is unchanged.
152
+ Both `dev` and `dev functions apply` flush their logs after cleanup on Ctrl-C, runtime failure, or normal completion.
142
153
  Piped runtime and build output is captured with a 1 MiB limit per stream.
143
- Interactive runtimes that inherit the terminal keep their keyboard and TTY behavior; their console output is not captured, and the log records that limitation alongside lifecycle events.
154
+ Interactive Functions sessions keep standard input attached for keyboard interaction, while stdout and stderr are piped for filtering and diagnostic capture.
155
+ Other interactive runtimes that inherit the terminal keep their keyboard and TTY behavior; their console output is not captured, and the log records that limitation alongside lifecycle events.
144
156
 
145
157
  Logs stay on your machine and are independent of telemetry opt-out.
146
158
  The log directory is shared across projects on your machine, so the retention limits below apply across all projects using it.
@@ -4,7 +4,7 @@ sidebar_position: 50
4
4
 
5
5
  # Managing Secrets
6
6
 
7
- Secrets are encrypted values — API keys, connection strings, tokens — that your app needs at runtime but must never ship in client code. They are stored securely on your deployed Rayfin item and read on the server by [functions](./functions/index.md) via `ctx.getSecret(name)`.
7
+ Secrets are encrypted values — API keys, connection strings, tokens — that your app needs at runtime but must never ship in client code. They are stored securely on your deployed Rayfin item and read on the server by [functions](./functions/index.md) via `ctx.Secrets`.
8
8
 
9
9
  Manage secrets with the `npx rayfin secret` command group:
10
10
 
@@ -105,18 +105,28 @@ Deleting a secret that does not exist reports a not-found error — run `npx ray
105
105
 
106
106
  ## Reading secrets from functions
107
107
 
108
- Server-side functions read secrets at runtime with `ctx.getSecret(name)`, which resolves against the deployed item's secret bag and falls back to `process.env`. Set a secret with `npx rayfin secret set <name>`, then read it by the same name inside your handler:
108
+ Server-side functions read secrets at runtime as typed properties on `ctx.Secrets`, which resolve against the deployed item's secret bag and fall back to `process.env`. Set a secret with `npx rayfin secret set <name>`, then read it by the same name inside your handler:
109
109
 
110
110
  ```ts
111
- udf.func("summarize", async (ctx, input: { text: string }) => {
112
- const apiKey = ctx.getSecret("OPENAI_KEY");
113
- // ... call the API with apiKey
114
- });
111
+ import { type RayfinContext } from "@microsoft/fabric-user-data-functions";
112
+
113
+ udf.func(
114
+ "summarize",
115
+ async (ctx: RayfinContext<AppSchema>, input: { text: string }) => {
116
+ const apiKey = ctx.Secrets.OPENAI_KEY;
117
+ // ... call the API with apiKey
118
+ },
119
+ [],
120
+ );
115
121
  ```
116
122
 
123
+ The `RayfinContext<AppSchema>` annotation is what makes this type-safe. An unannotated `ctx` is contextually `any`, so `ctx.Secrets.OPENAI_KEY` compiles whether or not the secret is declared — and the annotation is also how typegen recognises the parameter as the injected context rather than a request-body argument.
124
+
125
+ Setting the secret is what types it: the CLI regenerates `rayfin/functions/src/secrets.generated.ts`, so `ctx.Secrets.OPENAI_KEY` is a `string` and an undeclared name is a compile error. See [Secrets](../functions/secrets.md) for the full model.
126
+
117
127
  ## Using secrets in local development
118
128
 
119
- When you run functions locally with [`npx rayfin dev functions apply`](./functions/dev-apply.md), there is no deployed secret bag, so `ctx.getSecret(name)` falls back to `process.env`. To make a secret available locally, add it under `Values` in `rayfin/functions/local.settings.json` — the Azure Functions host loads those entries into `process.env`:
129
+ When you run functions locally with [`npx rayfin dev functions apply`](./functions/dev-apply.md), there is no deployed secret bag, so `ctx.Secrets.<NAME>` falls back to `process.env`. To make a secret available locally, add it under `Values` in `rayfin/functions/local.settings.json` — the Azure Functions host loads those entries into `process.env`:
120
130
 
121
131
  ```json
122
132
  {
@@ -166,6 +176,6 @@ If `secret delete` reports the secret was not found:
166
176
 
167
177
  ## See also
168
178
 
169
- - [Functions](./functions/index.md) — read secrets from server-side functions with `ctx.getSecret`.
179
+ - [Functions](./functions/index.md) — read secrets from server-side functions with `ctx.Secrets`.
170
180
  - [CLI quickstart](./quickstart.md)
171
181
  - [Environment configuration](./env-interpolation.md)
@@ -4,10 +4,14 @@ sidebar_position: 5
4
4
 
5
5
  # Add Azure DevOps
6
6
 
7
- Call the [Azure DevOps REST API](https://learn.microsoft.com/en-us/rest/api/azure/devops/) from a function **as the signed-in user**, using `AudienceType.ADO`.
7
+ Call the [Azure DevOps REST API](https://learn.microsoft.com/en-us/rest/api/azure/devops/) from a deployed function using `AudienceType.ADO`.
8
+
9
+ Grant the [application identity](../index.md#application-authentication) access to your Azure DevOps organization and the permissions required by the project or resource you call.
8
10
 
9
11
  Provide your Azure DevOps **organization** (and project, if the call needs one) — e.g. `https://dev.azure.com/<org>`. The token is a standard bearer token — send it with `fetch`:
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,8 @@ const ORG = "https://dev.azure.com/<org>";
22
26
 
23
27
  udf.func(
24
28
  "listProjects",
25
- async (ctx: RayfinContext): Promise<unknown> => {
26
- const token = ctx.getToken(AudienceType.ADO);
29
+ async (ctx: RayfinContext<AppSchema, AudienceType.ADO>): Promise<unknown> => {
30
+ const token = ctx.Tokens.ADO;
27
31
  const res = await fetch(`${ORG}/_apis/projects?api-version=7.1`, {
28
32
  headers: { Authorization: `Bearer ${token}` },
29
33
  });
@@ -32,7 +36,7 @@ udf.func(
32
36
  }
33
37
  return res.json();
34
38
  },
35
- [udf.connection({ audienceType: AudienceType.ADO })],
39
+ [],
36
40
  );
37
41
  ```
38
42
 
@@ -4,58 +4,24 @@ sidebar_position: 3
4
4
 
5
5
  # Add an Azure resource
6
6
 
7
- Connect a function to an **Azure service** — Key Vault, Cosmos DB, Blob Storage, or Event Grid — and call it **as the signed-in user**.
7
+ Connect a deployed function to **Azure Blob Storage**.
8
8
 
9
- These are Azure resources, not Fabric items, so their endpoints come from the **Azure portal** (there is no Fabric lookup). Each pattern declares the connection, reads the token with `ctx.getToken()`, and wraps it with the [`ContextTokenCredential`](./index.md#wrapping-the-token-for-azure-sdk-clients) helper for the Azure SDK. See [Connecting to external resources](./index.md) for the shared model.
9
+ Grant the [application identity](../index.md#application-authentication) the storage data permissions required by your operations.
10
10
 
11
- ## Key Vault
11
+ The storage account is an Azure resource, not a Fabric item, so its endpoint comes from the **Azure portal** (there is no Fabric lookup).
12
+ The pattern declares the audience in the `RayfinContext` annotation, reads the token from `ctx.Tokens`, and wraps it with the [`ContextTokenCredential`](./index.md#wrapping-the-token-for-azure-sdk-clients) helper for the Azure SDK.
13
+ See [Connecting to external resources](./index.md) for the shared model.
12
14
 
13
- Read secrets from Azure Key Vault using `AudienceType.KeyVault`.
15
+ `AppSchema` below is your app's data schema — the same type you pass to `RayfinClient<AppSchema>`.
16
+ See [Writing functions](../writing-functions.md#accessing-data-and-request-context).
14
17
 
15
- ```bash
16
- cd rayfin/functions
17
- npm install @azure/keyvault-secrets @azure/identity
18
- ```
19
-
20
- ```ts
21
- import {
22
- UserDataFunctions,
23
- AudienceType,
24
- type RayfinContext,
25
- } from "@microsoft/fabric-user-data-functions";
26
- import { SecretClient } from "@azure/keyvault-secrets";
27
-
28
- const udf = new UserDataFunctions();
29
-
30
- udf.func(
31
- "getVaultSecret",
32
- async (
33
- ctx: RayfinContext,
34
- kvUrl: string,
35
- secretName: string,
36
- ): Promise<string> => {
37
- const credential = new ContextTokenCredential(
38
- ctx.getToken(AudienceType.KeyVault),
39
- );
40
- const client = new SecretClient(kvUrl, credential);
41
- const secret = await client.getSecret(secretName);
42
- return secret.value ?? "";
43
- },
44
- [udf.connection({ audienceType: AudienceType.KeyVault })],
45
- );
46
- ```
47
-
48
- Provide the vault URL (e.g. `https://my-vault.vault.azure.net/`).
49
-
50
- > To read secrets stored with Rayfin itself (rather than an external Key Vault), use [`ctx.getSecret()`](../secrets.md) instead — no connection required.
51
-
52
- ## Cosmos DB
18
+ ## Blob Storage
53
19
 
54
- Connect to Azure Cosmos DB using `AudienceType.CosmosDB`. Pass the credential as `aadCredentials`:
20
+ Connect to Azure Blob / Table / Queue storage using `AudienceType.Storage`:
55
21
 
56
22
  ```bash
57
23
  cd rayfin/functions
58
- npm install @azure/cosmos
24
+ npm install @azure/storage-blob @azure/identity
59
25
  ```
60
26
 
61
27
  ```ts
@@ -64,53 +30,17 @@ import {
64
30
  AudienceType,
65
31
  type RayfinContext,
66
32
  } from "@microsoft/fabric-user-data-functions";
67
- import { CosmosClient } from "@azure/cosmos";
33
+ import { BlobServiceClient } from "@azure/storage-blob";
68
34
 
69
35
  const udf = new UserDataFunctions();
70
36
 
71
- udf.func(
72
- "readItems",
73
- async (
74
- ctx: RayfinContext,
75
- endpoint: string,
76
- databaseId: string,
77
- containerId: string,
78
- ): Promise<unknown[]> => {
79
- const credential = new ContextTokenCredential(
80
- ctx.getToken(AudienceType.CosmosDB),
81
- );
82
- const client = new CosmosClient({ endpoint, aadCredentials: credential });
83
- const { resources } = await client
84
- .database(databaseId)
85
- .container(containerId)
86
- .items.readAll()
87
- .fetchAll();
88
- return resources;
89
- },
90
- [udf.connection({ audienceType: AudienceType.CosmosDB })],
91
- );
92
- ```
93
-
94
- Provide the account endpoint and the database / container names.
95
-
96
- ## Blob Storage
97
-
98
- Connect to Azure Blob / Table / Queue storage using `AudienceType.Storage`:
99
-
100
- ```bash
101
- cd rayfin/functions
102
- npm install @azure/storage-blob
103
- ```
104
-
105
- ```ts
106
- import { BlobServiceClient } from "@azure/storage-blob";
107
-
108
37
  udf.func(
109
38
  "listBlobs",
110
- async (ctx: RayfinContext, accountUrl: string): Promise<string[]> => {
111
- const credential = new ContextTokenCredential(
112
- ctx.getToken(AudienceType.Storage),
113
- );
39
+ async (
40
+ ctx: RayfinContext<AppSchema, AudienceType.Storage>,
41
+ accountUrl: string,
42
+ ): Promise<string[]> => {
43
+ const credential = new ContextTokenCredential(ctx.Tokens.Storage);
114
44
  const service = new BlobServiceClient(accountUrl, credential);
115
45
  const names: string[] = [];
116
46
  for await (const container of service.listContainers()) {
@@ -118,54 +48,10 @@ udf.func(
118
48
  }
119
49
  return names;
120
50
  },
121
- [udf.connection({ audienceType: AudienceType.Storage })],
51
+ [],
122
52
  );
123
53
  ```
124
54
 
125
55
  Provide the storage account URL (e.g. `https://<account>.blob.core.windows.net`).
126
56
 
127
57
  > `AudienceType.Storage` also covers **OneLake** files — that Fabric case is documented in [Add a Fabric resource → OneLake files](./add-fabric-resource.md#onelake-files).
128
-
129
- ## Event Grid
130
-
131
- Publish events to an Azure Event Grid topic using `AudienceType.EventGrid`. The topic endpoint is in the Azure portal → your topic → **Overview** → _Topic Endpoint_.
132
-
133
- ```bash
134
- cd rayfin/functions
135
- npm install @azure/eventgrid
136
- ```
137
-
138
- ```ts
139
- import {
140
- UserDataFunctions,
141
- AudienceType,
142
- type RayfinContext,
143
- } from "@microsoft/fabric-user-data-functions";
144
- import { EventGridPublisherClient } from "@azure/eventgrid";
145
-
146
- const udf = new UserDataFunctions();
147
-
148
- const TOPIC_ENDPOINT =
149
- "https://<topic>.<region>.eventgrid.azure.net/api/events";
150
-
151
- udf.func(
152
- "publishEvent",
153
- async (ctx: RayfinContext, subject: string): Promise<string> => {
154
- const client = new EventGridPublisherClient(
155
- TOPIC_ENDPOINT,
156
- "EventGrid",
157
- new ContextTokenCredential(ctx.getToken(AudienceType.EventGrid)),
158
- );
159
- await client.send([
160
- {
161
- eventType: "Rayfin.Function.Event",
162
- subject,
163
- dataVersion: "1.0",
164
- data: { source: "user-data-function" },
165
- },
166
- ]);
167
- return "published";
168
- },
169
- [udf.connection({ audienceType: AudienceType.EventGrid })],
170
- );
171
- ```