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

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.
Files changed (27) hide show
  1. package/assets/docs/app-backend/deploy.md +36 -1
  2. package/assets/docs/cli/connectors/add.md +18 -3
  3. package/assets/docs/cli/connectors/category-b-function-bridge.md +111 -11
  4. package/assets/docs/cli/connectors/index.md +8 -4
  5. package/assets/docs/cli/connectors/inspect.md +34 -1
  6. package/assets/docs/cli/connectors/invoke.md +4 -0
  7. package/assets/docs/cli/connectors/search.md +4 -0
  8. package/assets/docs/cli/environment-variables.md +2 -1
  9. package/assets/docs/cli/functions/deploy.md +13 -1
  10. package/assets/docs/cli/functions/dev-apply.md +8 -2
  11. package/assets/docs/cli/functions/index.md +4 -2
  12. package/assets/docs/cli/functions/init.md +7 -1
  13. package/assets/docs/cli/index.md +20 -7
  14. package/assets/docs/cli/secrets.md +18 -8
  15. package/assets/docs/functions/connections/add-ado.md +8 -4
  16. package/assets/docs/functions/connections/add-azure-resource.md +17 -131
  17. package/assets/docs/functions/connections/add-fabric-resource.md +31 -61
  18. package/assets/docs/functions/connections/add-foundry.md +11 -4
  19. package/assets/docs/functions/connections/get-fabric-info.md +7 -25
  20. package/assets/docs/functions/connections/index.md +127 -22
  21. package/assets/docs/functions/index.md +39 -1
  22. package/assets/docs/functions/secrets.md +39 -11
  23. package/assets/docs/functions/writing-functions.md +27 -23
  24. package/assets/docs/getting-started/project-structure.md +3 -1
  25. package/assets/docs/preview/local-dev-docker.md +2 -1
  26. package/package.json +1 -1
  27. package/assets/docs/functions/connections/add-work-iq.md +0 -39
@@ -4,12 +4,15 @@ sidebar_position: 5
4
4
 
5
5
  # Connecting to external resources
6
6
 
7
- Functions can call external Azure and Fabric resources **as the calling user** using delegated authentication.
8
- You declare a connection on the function, and at invocation time the runtime exchanges the user's identity for a resource-scoped on-behalf-of (OBO) token.
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 an audience-scoped connection in the third argument of `udf.func()`, then read its token with `ctx.getToken()`:
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
- "myFunction",
25
- async (ctx: RayfinContext): Promise<string> => {
26
- const token = ctx.getToken(AudienceType.KeyVault);
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
- [udf.connection({ audienceType: AudienceType.KeyVault })],
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
- - `udf.connection({ audienceType })` declares the delegated connection.
35
- - `ctx.getToken(audienceType)` returns the OBO access token as a `string`. It throws if no connection was declared for that audience.
36
- - The connection declaration is what makes the token available — declaring the audience and calling `getToken` with the same audience always go together.
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.getToken(AudienceType.X))` wherever an Azure SDK client asks for a credential.
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 pass to `udf.connection()` and `ctx.getToken()`. A single audience can back more than one use case (for example `Storage` covers both Fabric OneLake and Azure Blob).
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, OneLake path, Kusto query URI), see [Get Fabric info](./get-fabric-info.md).
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
- - Declare every connection in the third argument to `udf.func()`.
83
- - Use `ctx.getToken(AudienceType.X)` — never acquire tokens manually.
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
- When you run `npx rayfin dev functions apply`, the local host acquires delegated tokens interactively for debugging, so `ctx.getToken()` works against your declared audiences without a deployment.
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) — delegated access to SQL, Storage, Key Vault, and more.
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 through `ctx.getSecret(name)` on [`RayfinContext`](./writing-functions.md#rayfincontext-api).
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
- const apiKey = ctx.getSecret("THIRD_PARTY_API_KEY");
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.getSecret(name)` returns `string | undefined`. It resolves in this order:
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[name]` as a fallback.
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 `getSecret` fallback:
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
- - Prefer secrets set with `npx rayfin secret set <NAME>` as the source of truth for deployed functions.
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.
@@ -26,11 +26,11 @@ udf.func(
26
26
 
27
27
  `udf.func()` takes three arguments:
28
28
 
29
- | Argument | Description |
30
- | ------------- | --------------------------------------------------------------------------------------------- |
31
- | `name` | The function name. Becomes the invocation route and the key in your generated schema. |
32
- | `fn` | The handler. Its parameter and return types are read by [typegen](./typegen.md). |
33
- | `connections` | Optional array of connection bindings. Pass `[]` when the function does not use a connection. |
29
+ | Argument | Description |
30
+ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
31
+ | `name` | The function name. Becomes the invocation route and the key in your generated schema. |
32
+ | `fn` | The handler. Its parameter and return types are read by [typegen](./typegen.md). |
33
+ | `connections` | Optional array of connection bindings. Pass `[]` — audience-scoped connections are declared in the context annotation instead. |
34
34
 
35
35
  The handler's typed parameters and return type are extracted into `types.ts` so the frontend can call the function type-safely.
36
36
  `Promise<T>` return types are unwrapped to `T` in the generated schema.
@@ -38,7 +38,8 @@ The handler's typed parameters and return type are extracted into `types.ts` so
38
38
  ## Accessing data and request context
39
39
 
40
40
  To read your data, tokens, or logging from inside a function, declare a `RayfinContext` parameter.
41
- Pass your app schema as a generic (`RayfinContext<AppSchema>`) — the same schema you use with `RayfinClient<AppSchema>` — for a fully typed data client:
41
+ Pass your app schema as the first generic (`RayfinContext<AppSchema>`) — the same schema you use with `RayfinClient<AppSchema>` — for a fully typed data client.
42
+ A second, optional generic declares the external audiences the function may use; see [Connecting to external resources](./connections/index.md).
42
43
 
43
44
  ```ts
44
45
  import {
@@ -67,14 +68,16 @@ udf.func(
67
68
 
68
69
  ### `RayfinContext` API
69
70
 
70
- | Member | Description |
71
- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
72
- | `ctx.getDataClient()` | Returns the typed entity data client. Query with `.select([...]).where(...).execute()`, the same chain as `client.data.<Entity>` on the frontend. Typed when a generic is supplied; untyped (`Record<string, any>`) otherwise. |
73
- | `ctx.getSecret(name)` | Returns a secret value, or `undefined` when unset. See [Secrets](./secrets.md). |
74
- | `ctx.getToken(audienceType)` | Returns the delegated OBO access token (a `string`) for an external resource. Only works for an audience you declared with `udf.connection({ audienceType })` in the third argument — throws otherwise. See [Connecting to external resources](./connections/index.md). |
75
- | `ctx.baseUrl` | The Rayfin endpoint URL (readonly). |
76
- | `ctx.accessToken` | The auth token for the current request (readonly). |
77
- | `ctx.publishableKey` | The Rayfin publishable key (readonly). |
71
+ | Member | Description |
72
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
73
+ | `ctx.getDataClient()` | Returns the Rayfin DB entity data client using the invocation's Rayfin token and the caller's identity and database permissions. Query with `.select([...]).where(...).execute()`, as with `client.data.<Entity>` on the frontend. Typed when a schema generic is supplied; otherwise untyped. |
74
+ | `ctx.Secrets` | Secret values keyed by the names declared in `rayfin.yml`, each typed `string`. Reading an undeclared name is a compile error. See [Secrets](./secrets.md). |
75
+ | `ctx.Tokens` | Resource access tokens keyed by audience, each typed `string`. Narrowed to the declared audiences; deployed Functions use the app identity. See [Connecting to external resources](./connections/index.md), including local development. |
76
+ | `ctx.baseUrl` | The Rayfin endpoint URL (readonly). |
77
+ | `ctx.accessToken` | The invocation's Rayfin token, used for caller-scoped Rayfin DB access (readonly). Not an external resource token from `ctx.Tokens`. |
78
+ | `ctx.publishableKey` | The Rayfin publishable key (readonly). |
79
+
80
+ `ctx.getSecret(name)` and `ctx.getToken(audienceType)` are the deprecated predecessors of `ctx.Secrets` and `ctx.Tokens`. They still work, but are flagged by `@typescript-eslint/no-deprecated`.
78
81
 
79
82
  Use `console.log(...)` / `console.error(...)` for logging.
80
83
 
@@ -100,24 +103,25 @@ udf.func(
100
103
 
101
104
  ## Connecting to external resources
102
105
 
103
- To call external Azure or Fabric resources (SQL, Storage, Key Vault, Cosmos DB, and more) from inside a function, declare a connection in the third argument of `udf.func()` and read a delegated token from the context:
106
+ To call external Azure or Fabric resources (SQL, Storage, the Fabric REST API, and more) from inside a function, declare the audience in the `RayfinContext` annotation and read the token from `ctx.Tokens`:
104
107
 
105
108
  ```ts
106
109
  import { AudienceType } from "@microsoft/fabric-user-data-functions";
107
110
 
108
111
  udf.func(
109
- "readSecret",
110
- async (ctx: RayfinContext, secretName: string): Promise<string> => {
111
- const token = ctx.getToken(AudienceType.KeyVault);
112
+ "accessStorage",
113
+ async (
114
+ ctx: RayfinContext<AppSchema, AudienceType.Storage>,
115
+ ): Promise<void> => {
116
+ const token = ctx.Tokens.Storage;
112
117
  // Use `token` with the resource's SDK or REST API.
113
- return secretName;
114
118
  },
115
- [udf.connection({ audienceType: AudienceType.KeyVault })],
119
+ [],
116
120
  );
117
121
  ```
118
122
 
119
- The runtime exchanges the caller's identity for a resource-scoped token, so the function acts **as the calling user**.
120
- See [Connecting to external resources](./connections/index.md) for the full model, the list of supported audiences, and per-resource guides.
123
+ The annotation is the declaration — listing the audience is what registers the connection binding, so nothing goes in the third argument.
124
+ See [Application authentication](./index.md#application-authentication) for configuration and identities, and [Connecting to external resources](./connections/index.md) for supported audiences and per-resource guides.
121
125
 
122
126
  ## Importing data entities
123
127
 
@@ -135,6 +139,6 @@ import type { Entry } from "../../data/Entry.js";
135
139
 
136
140
  - Always register functions with `udf.func(name, handler, [])` — do not export bare functions.
137
141
  - Use `RayfinContext<AppSchema>` for type-safe data access. Bare `RayfinContext` still works but gives no type safety on `getDataClient()`.
138
- - Only call `ctx.getToken(audienceType)` for an audience you declared with `udf.connection({ audienceType })` in the third argument of `udf.func()` — calling it for an undeclared audience throws.
142
+ - Declare external audiences in the context annotation (`RayfinContext<AppSchema, AudienceType.X>`) and read them with `ctx.Tokens.X` — an audience you did not declare is a compile error.
139
143
  - A function must return a value or `void`. Throwing an error surfaces to the caller as an invocation failure carrying the error message.
140
144
  - Use `import type` for data entity imports; never a runtime `import`.
@@ -76,7 +76,7 @@ The root build orders shared, data, and frontend work.
76
76
  Focused package commands use npm's workspace selector, such as `npm run -w @rayfin-app/frontend test`.
77
77
 
78
78
  The base workspace does not contain `packages/functions`, and `services.functions.enabled` is `false`.
79
- Running `npm run pack:add -- functions` creates the stable functions package, enables its service, composes its build into root orchestration, and installs dependencies from the workspace root.
79
+ Running `npm run pack:add -- functions` creates the stable functions package, enables its service with `auth.type: application`, composes its build into root orchestration, and installs dependencies from the workspace root.
80
80
  Capability packs do not use a nested functions lockfile or nested install.
81
81
 
82
82
  ### Universal App service paths
@@ -102,6 +102,8 @@ services:
102
102
  Rayfin resolves each `path` from the application root, then runs that service's `buildCommand` with the service directory as its working directory.
103
103
  The static-hosting folder is therefore `packages/frontend/dist`, not a root `dist` directory.
104
104
  After the functions pack is applied, functions uses `path: packages/functions` with its package-local `npm run build`.
105
+ Enabled Functions require explicit `services.functions.auth.type: application`; the disabled base configuration above may omit `auth`.
106
+ See [Application authentication](../functions/index.md#application-authentication) for existing-app configuration and downstream permissions.
105
107
 
106
108
  The Project Rayfin repository keeps this Builder-facing workspace under `samples/universal-app/template`.
107
109
  Its parent `samples/universal-app` is only a Rush validation harness that generates an ephemeral target and links that target to repository-local SDK packages.
@@ -28,6 +28,7 @@ This command:
28
28
  - Runs health checks and waits for all services to be healthy.
29
29
  - Applies the project's declared data configuration to the local backend.
30
30
  - Starts the frontend with `npm run dev:frontend` when that script exists, falling back to `npm run dev` for existing projects.
31
+ `rayfin init` sets this up automatically for a from-scratch scaffold, when `@microsoft/rayfin-cli` is installed or already declared as a dependency.
31
32
  - Resolves that script from `services.staticHosting.path` when the frontend lives in a nested package, otherwise from the project root.
32
33
  - Builds and starts the configured local Functions host when `services.functions.enabled` is `true`.
33
34
 
@@ -48,7 +49,7 @@ The command also:
48
49
 
49
50
  - Merges local backend settings into the configured functions package's `local.settings.json`.
50
51
  - Reserves a Node inspector port starting at `9229`.
51
- - Adds `Functions: Attach` to the root `.vscode/launch.json` after the Functions host is ready.
52
+ - Adds `Functions: Attach` to the root `.vscode/launch.json` after the Functions host is ready. If the entry already exists and the inspector moved to another port, only its `port` is updated.
52
53
  - Patches recognized existing `src/services/rayfinClient.ts` and `src/services/bootstrap.ts` files to pass `VITE_RAYFIN_FUNCTIONS_URL` directly only during Vite development.
53
54
 
54
55
  If `.vscode/launch.json` contains JSON with comments, Rayfin leaves it unchanged to avoid losing those comments and asks you to add the attach configuration manually.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/rayfin-guide",
3
- "version": "1.36.0-alpha.1756",
3
+ "version": "1.36.0-alpha.1917",
4
4
  "description": "Cross-cutting Builder guides for the Rayfin platform — discovered by `@microsoft/rayfin-docs` via the `rayfinDocs` package.json field convention.",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,39 +0,0 @@
1
- ---
2
- sidebar_position: 6
3
- ---
4
-
5
- # Add WorkIQ
6
-
7
- Call the **WorkIQ** service from a function **as the signed-in user**, using `AudienceType.WorkIQ`.
8
-
9
- Provide the **WorkIQ endpoint** you are calling. The token is a standard bearer token — send it with `fetch`:
10
-
11
- ```ts
12
- import {
13
- UserDataFunctions,
14
- AudienceType,
15
- type RayfinContext,
16
- } from "@microsoft/fabric-user-data-functions";
17
-
18
- const udf = new UserDataFunctions();
19
-
20
- // Use your real WorkIQ endpoint.
21
- const WORKIQ_ENDPOINT = "https://workiq.svc.cloud.microsoft/...";
22
-
23
- udf.func(
24
- "callWorkIq",
25
- async (ctx: RayfinContext): Promise<unknown> => {
26
- const token = ctx.getToken(AudienceType.WorkIQ);
27
- const res = await fetch(WORKIQ_ENDPOINT, {
28
- headers: { Authorization: `Bearer ${token}` },
29
- });
30
- if (!res.ok) {
31
- throw new Error(`WorkIQ returned ${res.status}`);
32
- }
33
- return res.json();
34
- },
35
- [udf.connection({ audienceType: AudienceType.WorkIQ })],
36
- );
37
- ```
38
-
39
- See [Connecting to external resources](./index.md) for the shared connection model.