@microsoft/rayfin-guide 1.36.0-alpha.1601 → 1.36.0-alpha.1663
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 +57 -11
- package/assets/docs/auth/direct-entra-auth.md +139 -0
- package/assets/docs/auth/external-embed-host.md +131 -0
- package/assets/docs/auth/fabric.md +13 -5
- package/assets/docs/auth/index.md +6 -0
- package/assets/docs/{experimental/cli → cli}/connectors/add.md +2 -0
- package/assets/docs/{experimental/cli → cli}/connectors/category-a-entities.md +1 -1
- package/assets/docs/{experimental/cli → cli}/connectors/category-b-function-bridge.md +38 -12
- package/assets/docs/cli/connectors/eventhouse.md +21 -0
- package/assets/docs/{experimental/cli → cli}/connectors/index.md +10 -21
- package/assets/docs/{experimental/cli → cli}/connectors/invoke.md +32 -0
- package/assets/docs/{experimental/cli → cli}/connectors/search.md +4 -2
- package/assets/docs/cli/environment-variables.md +2 -2
- package/assets/docs/cli/index.md +36 -0
- package/assets/docs/cli/templates.md +6 -0
- package/assets/docs/getting-started/project-structure.md +91 -2
- package/package.json +1 -1
- /package/assets/docs/{experimental/cli → cli}/connectors/inspect.md +0 -0
|
@@ -62,6 +62,30 @@ npx rayfin up
|
|
|
62
62
|
|
|
63
63
|
If you are not signed in, the CLI launches an interactive login flow automatically.
|
|
64
64
|
|
|
65
|
+
### Choose a unique Fabric item name
|
|
66
|
+
|
|
67
|
+
By default, `rayfin up` uses the project ID from `rayfin.yml` as the Fabric item name.
|
|
68
|
+
Pass `--item-name` to deploy a template under a different name without editing its configuration:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx rayfin up --item-name my-team-todo-app
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The override changes only the Fabric item display name.
|
|
75
|
+
Runtime settings and service configuration continue to come from `rayfin.yml`.
|
|
76
|
+
Rayfin records the effective item name and item ID in `rayfin/.deployments.json`, so later deployments continue targeting the same item.
|
|
77
|
+
|
|
78
|
+
For an agent or CI pipeline, provide explicit workspace targeting and structured output:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx rayfin up \
|
|
82
|
+
--item-name my-team-todo-app \
|
|
83
|
+
--workspace-id <workspace-guid> \
|
|
84
|
+
--output json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Do not pass `--yes` unless reusing an existing same-named item is intentional.
|
|
88
|
+
|
|
65
89
|
### What `rayfin up` does
|
|
66
90
|
|
|
67
91
|
The command performs these steps in order:
|
|
@@ -91,6 +115,7 @@ For frontend frameworks, the CLI also runs `rayfin env` to emit a framework-spec
|
|
|
91
115
|
"deployments": {
|
|
92
116
|
"myworkspace": {
|
|
93
117
|
"fabricItemId": "7db00cb9-f630-4ecf-8fc9-942e60af5d78",
|
|
118
|
+
"itemName": "my-team-todo-app",
|
|
94
119
|
"fabricApiUrl": "https://...",
|
|
95
120
|
"fabricWorkspaceId": "8b17cf64-3c12-46ac-a572-192732c32641",
|
|
96
121
|
"fabricTenantId": "...",
|
|
@@ -113,13 +138,13 @@ VITE_RAYFIN_PUBLISHABLE_KEY=pk-nua-EHihY2jz71V65YB4
|
|
|
113
138
|
VITE_FABRIC_PORTAL_URL=https://dxt.fabric.microsoft.com/
|
|
114
139
|
```
|
|
115
140
|
|
|
116
|
-
| Variable
|
|
117
|
-
|
|
|
118
|
-
| `VITE_FABRIC_ITEM_ID`
|
|
119
|
-
| `VITE_RAYFIN_API_URL`
|
|
120
|
-
| `VITE_FABRIC_WORKSPACE_ID`
|
|
141
|
+
| Variable | Description |
|
|
142
|
+
| ----------------------------- | ------------------------------------------------------------- |
|
|
143
|
+
| `VITE_FABRIC_ITEM_ID` | The Fabric item ID for this deployment. |
|
|
144
|
+
| `VITE_RAYFIN_API_URL` | Full URL to the deployed Rayfin backend API. |
|
|
145
|
+
| `VITE_FABRIC_WORKSPACE_ID` | The Fabric workspace ID containing the deployment. |
|
|
121
146
|
| `VITE_RAYFIN_PUBLISHABLE_KEY` | Publishable key used by the Rayfin client for authentication. |
|
|
122
|
-
| `VITE_FABRIC_PORTAL_URL`
|
|
147
|
+
| `VITE_FABRIC_PORTAL_URL` | URL to the Fabric portal for managing the deployment. |
|
|
123
148
|
|
|
124
149
|
### Authentication after deployment
|
|
125
150
|
|
|
@@ -203,6 +228,27 @@ Add `--json` for machine-readable output:
|
|
|
203
228
|
npx rayfin up status --json
|
|
204
229
|
```
|
|
205
230
|
|
|
231
|
+
To inspect a specific registered deployment instead of the active one, pass its name to `up`:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npx rayfin up --env-file staging status
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
If `RAYFIN_WORKSPACE_ID` is also set, the selected deployment must belong to that workspace.
|
|
238
|
+
|
|
239
|
+
The management endpoint check verifies authenticated access to the deployed Fabric item and retrieves its publishable key.
|
|
240
|
+
It does not verify that every application route or function is working; validate those with application-specific requests.
|
|
241
|
+
|
|
242
|
+
In JSON output, `endpointHealth.scope` is `management` and `endpointHealth.url` identifies the endpoint checked.
|
|
243
|
+
`endpointHealth.reachable` records whether an HTTP response arrived, while `httpStatus` and `authenticated` distinguish HTTP success from authentication or authorization failures.
|
|
244
|
+
The top-level `authenticated` field indicates that the CLI acquired a token, not that the endpoint accepted it.
|
|
245
|
+
`endpointHealth.errorCode` is `null` on success, or a stable code such as `http`, `redirect`, `timeout`, `connection-refused`, or `network`; `error` and `hint` provide human-readable details.
|
|
246
|
+
Optional key-retrieval problems appear separately in `endpointHealth.metadata.error`, which is `null` on success or `unexpected-format` for an unsupported response body; the saved deployment key is not changed.
|
|
247
|
+
|
|
248
|
+
The command exits with `0` when the management request succeeds, `1` when deployment configuration is missing or another command error occurs, or `2` when the check fails, cannot authenticate, or is cancelled.
|
|
249
|
+
HTTP errors, timeouts, and connection failures return `2`, even when the server is reachable.
|
|
250
|
+
An unexpected metadata format alone does not fail a successful management request.
|
|
251
|
+
|
|
206
252
|
When static content is deployed, the human-readable output includes its public URL:
|
|
207
253
|
|
|
208
254
|
```text
|
|
@@ -236,11 +282,11 @@ Running `npx rayfin up` again updates the same deployment rather than creating a
|
|
|
236
282
|
|
|
237
283
|
For targeted updates, use the subcommands:
|
|
238
284
|
|
|
239
|
-
| Command
|
|
240
|
-
|
|
|
241
|
-
| `npx rayfin up`
|
|
242
|
-
| `npx rayfin up db apply`
|
|
243
|
-
| `npx rayfin up staticapp deploy` | Static content only.
|
|
285
|
+
| Command | What it updates |
|
|
286
|
+
| -------------------------------- | --------------------------------------------------- |
|
|
287
|
+
| `npx rayfin up` | Everything: settings, database, and static content. |
|
|
288
|
+
| `npx rayfin up db apply` | Database schema only. |
|
|
289
|
+
| `npx rayfin up staticapp deploy` | Static content only. |
|
|
244
290
|
|
|
245
291
|
## Troubleshooting
|
|
246
292
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 4
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Direct Entra token sign-in
|
|
6
|
+
|
|
7
|
+
Use `signInWithEntraToken()` when your application already has a delegated Microsoft Entra access token and wants to call a Rayfin app as that user.
|
|
8
|
+
The helper exchanges it for a Rayfin session on your existing `Auth` instance, so attached SDK clients can make authenticated requests.
|
|
9
|
+
It works in browsers and Node.js without a popup, iframe, handoff code, or redirect.
|
|
10
|
+
|
|
11
|
+
For a portal signing in an embedded app rather than itself, use the [external embed host](./external-embed-host.md).
|
|
12
|
+
For a browser app that needs Fabric to perform interactive sign-in, use the [Fabric broker flow](./fabric.md).
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Enable external Entra exchange in the target app's `rayfin/rayfin.yml` and deploy the updated configuration:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
services:
|
|
20
|
+
auth:
|
|
21
|
+
enabled: true
|
|
22
|
+
fabric:
|
|
23
|
+
enabled: true
|
|
24
|
+
externalEntraExchange: true
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The direct exchange must also be available in the target Fabric environment.
|
|
28
|
+
Your Entra token must:
|
|
29
|
+
|
|
30
|
+
- Be a delegated user token, not an app-only service principal token.
|
|
31
|
+
- Target the Fabric/Power BI audience accepted by the deployment.
|
|
32
|
+
- Include the delegated `Item.Execute.All` scope.
|
|
33
|
+
- Be issued in the target item's owning Fabric tenant.
|
|
34
|
+
|
|
35
|
+
The user must have Execute permission on that item.
|
|
36
|
+
For production Power BI, request the `https://analysis.windows.net/powerbi/api/Item.Execute.All` scope through your identity library.
|
|
37
|
+
Development environments may use a different resource.
|
|
38
|
+
The SDK does not acquire the Entra token or handle consent.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
For an app using `RayfinClient`:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install @microsoft/rayfin-client @microsoft/rayfin-auth-provider-fabric
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Sign in an existing client
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { RayfinClient } from '@microsoft/rayfin-client';
|
|
52
|
+
import { signInWithEntraToken } from '@microsoft/rayfin-auth-provider-fabric';
|
|
53
|
+
|
|
54
|
+
const client = new RayfinClient({
|
|
55
|
+
baseUrl: rayfinEndpoint,
|
|
56
|
+
publishableKey,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const session = await signInWithEntraToken(client.auth, {
|
|
60
|
+
entraToken,
|
|
61
|
+
});
|
|
62
|
+
console.log('Authenticated', session.isAuthenticated);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`rayfinEndpoint` is your trusted HTTPS AppBackend workload API base URL, including the deployment's capacity/workspace/artifact path.
|
|
66
|
+
Use the same backend base URL as your data client, not the app's static-hosting URL or the full token endpoint.
|
|
67
|
+
The helper preserves that path and appends `/api/auth/v1/brokered/token`; there is no separate endpoint option to keep in sync.
|
|
68
|
+
The base must be absolute HTTPS, including for localhost; relative proxy URLs and URLs containing credentials, query strings, or fragments are not accepted.
|
|
69
|
+
`entraToken` is the raw access token string without the `Bearer` scheme prefix.
|
|
70
|
+
Never accept the endpoint from an untrusted caller.
|
|
71
|
+
|
|
72
|
+
The helper establishes the session on `client.auth`.
|
|
73
|
+
Data and function operations on that client then use the Rayfin access token automatically.
|
|
74
|
+
The returned `OpaqueSession` exposes user and session metadata without exposing tokens.
|
|
75
|
+
Each call explicitly exchanges the supplied token; it does not skip the exchange just because a previous session exists.
|
|
76
|
+
Concurrent direct sign-ins on the same `Auth` instance run in invocation order.
|
|
77
|
+
|
|
78
|
+
## Node.js and standalone SDK clients
|
|
79
|
+
|
|
80
|
+
You can construct `Auth` and `ApiClient` directly without `RayfinClient`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install @microsoft/rayfin-auth @microsoft/rayfin-lib @microsoft/rayfin-auth-provider-fabric
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { Auth } from '@microsoft/rayfin-auth';
|
|
88
|
+
import { ApiClient } from '@microsoft/rayfin-lib';
|
|
89
|
+
import { signInWithEntraToken } from '@microsoft/rayfin-auth-provider-fabric';
|
|
90
|
+
|
|
91
|
+
const apiClient = new ApiClient({
|
|
92
|
+
baseUrl: rayfinEndpoint,
|
|
93
|
+
publishableKey,
|
|
94
|
+
});
|
|
95
|
+
const auth = new Auth(apiClient, { storage: false });
|
|
96
|
+
auth.attachToClient(apiClient);
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const session = await signInWithEntraToken(auth, { entraToken });
|
|
100
|
+
console.log('Authenticated', session.isAuthenticated);
|
|
101
|
+
// Use data or other SDK clients configured with apiClient here.
|
|
102
|
+
} finally {
|
|
103
|
+
auth.destroy();
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Neither the import nor this direct sign-in requires `window`, `document`, or `localStorage`.
|
|
108
|
+
`storage: false` keeps the Rayfin session in memory.
|
|
109
|
+
Use separate instances per user in server applications; do not share mutable user sessions across requests from different users.
|
|
110
|
+
Call `auth.destroy()` when the instance is no longer needed to release its timers and listeners.
|
|
111
|
+
`RayfinServerClient` uses an access-token configuration instead of exposing `auth`, so it is not passed directly to this helper.
|
|
112
|
+
|
|
113
|
+
## Session lifetime
|
|
114
|
+
|
|
115
|
+
Persistence follows your `Auth` configuration.
|
|
116
|
+
The SDK does not persist the supplied Entra token in the Rayfin session.
|
|
117
|
+
Subsequent refresh uses the Rayfin refresh token through the ordinary auth flow rather than repeating the external exchange.
|
|
118
|
+
If the session can no longer refresh, obtain another Entra token and explicitly sign in again.
|
|
119
|
+
|
|
120
|
+
## Errors and browser considerations
|
|
121
|
+
|
|
122
|
+
The helper rejects with `AuthError` rather than returning a previous session as a successful sign-in.
|
|
123
|
+
On failure, an existing unexpired session remains in memory; successful sign-in replaces it without revoking the previous server session.
|
|
124
|
+
Do not publish authenticated UI or perform actions for a newly selected account until its sign-in succeeds.
|
|
125
|
+
|
|
126
|
+
| Error code | Meaning |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| `INVALID_REQUEST` | Invalid local token or endpoint configuration. |
|
|
129
|
+
| `EXCHANGE_NOT_ENABLED` | External Entra exchange is disabled for the project. |
|
|
130
|
+
| `AUTH_FAILED` | The Entra token was rejected; check audience, tenant, scope, and expiry. |
|
|
131
|
+
| `INSUFFICIENT_PERMISSIONS` | The user lacks Execute permission on the item. |
|
|
132
|
+
| `NOT_AVAILABLE` | The endpoint is unavailable in the target environment or the URL is wrong. |
|
|
133
|
+
| `TOKEN_EXCHANGE_FAILED` | A network or other HTTP failure prevented the exchange. |
|
|
134
|
+
| `INVALID_TOKEN_RESPONSE` | The service returned an invalid token response. |
|
|
135
|
+
|
|
136
|
+
The exchange does not follow redirects or automatically retry session issuance.
|
|
137
|
+
Errors do not include the Entra token or raw server response.
|
|
138
|
+
In browsers, the service must allow your origin and authorization header through its CORS policy.
|
|
139
|
+
The direct helper does not require a user gesture, but your identity library may require one when obtaining the Entra token interactively.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 3
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# External embed host
|
|
6
|
+
|
|
7
|
+
The external embed host lets a **third-party portal** embed a Rayfin app in an iframe and sign the user in with the portal's own Microsoft Entra identity.
|
|
8
|
+
Use it when your app is hosted outside the Fabric Portal — a standalone web app, an internal tool, or any page that already holds a delegated Entra token — and you want to broker authentication for an embedded Rayfin app without a popup or redirect.
|
|
9
|
+
|
|
10
|
+
This is the parent-page counterpart to [Fabric brokered auth](./fabric.md).
|
|
11
|
+
Fabric auth signs a Rayfin app in when Fabric hosts it; the external embed host signs it in when *your* page hosts it.
|
|
12
|
+
|
|
13
|
+
The parent page holds a delegated Entra token and answers the embedded app's handoff request.
|
|
14
|
+
The embedded app never sees the token — it receives only a single-use handoff code that it exchanges for a Rayfin session.
|
|
15
|
+
|
|
16
|
+
## When to use it
|
|
17
|
+
|
|
18
|
+
Use `@microsoft/rayfin-embed-host` when **all** of these are true:
|
|
19
|
+
|
|
20
|
+
- Your page embeds a Rayfin app in an iframe.
|
|
21
|
+
- Your page is not the Fabric Portal, so the in-Fabric embed host is unavailable.
|
|
22
|
+
- Your page can obtain a delegated Entra access token for the signed-in user.
|
|
23
|
+
|
|
24
|
+
If your app runs inside the Fabric Portal iframe, use [Fabric brokered auth](./fabric.md) instead — you do not need this package.
|
|
25
|
+
|
|
26
|
+
## How it works
|
|
27
|
+
|
|
28
|
+
1. Your page calls `createEmbedHost()` and then mounts the Rayfin app in an iframe.
|
|
29
|
+
2. The embedded app calls `initEmbeddedAuth()` on startup and posts a one-shot readiness signal to the parent window.
|
|
30
|
+
3. The host checks the iframe's origin against `allowedOrigins` and replies with an acknowledgement, classifying the scenario as an external embed.
|
|
31
|
+
4. The embedded app signs out, then sends a correlated handoff request carrying its brokered-authorize endpoint URL, its Fabric artifact id, the return origin, and a PKCE challenge.
|
|
32
|
+
5. The host validates the return origin against `allowedOrigins`, calls `getAccessToken()` to obtain your delegated Entra token, and posts it to the app's `brokered/authorize/external` endpoint.
|
|
33
|
+
6. The endpoint returns a single-use handoff code, which the host sends back to the iframe in the correlated response.
|
|
34
|
+
7. The embedded app exchanges the handoff code for a Rayfin session — the user is signed in with no popup, redirect, or user click.
|
|
35
|
+
|
|
36
|
+
The readiness signal is sent **once** with no retry.
|
|
37
|
+
Register the host before you mount the iframe so the listener is live when the signal arrives.
|
|
38
|
+
|
|
39
|
+
The external embed scenario is detected from this acknowledgement alone — the embedded Rayfin app needs no special query flag (such as `fabricEmbedded`) to enter external embed mode.
|
|
40
|
+
The embedded app must await `initEmbeddedAuth()` before restoring a stored user or rendering authenticated content.
|
|
41
|
+
Do not skip this call when `auth.getSession()` already reports an authenticated session: that session may belong to a different user than the parent portal's current user.
|
|
42
|
+
|
|
43
|
+
If no host acknowledges the readiness signal, the embedded app falls back to its normal Fabric login waterfall, so a page that never calls `createEmbedHost()` is unaffected.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @microsoft/rayfin-embed-host
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Register the host before mounting the iframe
|
|
52
|
+
|
|
53
|
+
Call `createEmbedHost()` before the Rayfin iframe loads.
|
|
54
|
+
The embedded app emits its readiness signal once, immediately on startup, and there is no retry — if the listener is not yet registered, the handshake is missed and the app falls back to its normal login flow.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { createEmbedHost } from '@microsoft/rayfin-embed-host';
|
|
58
|
+
|
|
59
|
+
// Register BEFORE mounting the Rayfin iframe.
|
|
60
|
+
const host = createEmbedHost({
|
|
61
|
+
allowedOrigins: ['https://my-rayfin-app.example.com'],
|
|
62
|
+
getAccessToken: () => acquireDelegatedEntraToken(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Now mount the iframe pointing at the embedded Rayfin app.
|
|
66
|
+
const iframe = document.createElement('iframe');
|
|
67
|
+
iframe.src = 'https://my-rayfin-app.example.com';
|
|
68
|
+
document.querySelector('#app-embed')?.append(iframe);
|
|
69
|
+
|
|
70
|
+
// When the embed is torn down:
|
|
71
|
+
host.dispose();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Options
|
|
75
|
+
|
|
76
|
+
`createEmbedHost()` takes an `EmbedHostOptions` object.
|
|
77
|
+
|
|
78
|
+
| Property | Type | Description |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `allowedOrigins` | `string[]` | Origins of the embedded Rayfin app(s) this host brokers for. Set it to your app's URL origin(s), for example `https://my-rayfin-app.example.com`. The same list gates both the iframe that sends the handshake and the return origin the handoff code is bound to. |
|
|
81
|
+
| `getAccessToken` | `() => string \| Promise<string>` | Yields your page's delegated Entra access token. Invoked once per handoff request; the returned token is attached only to the outbound authorization call and is never cached across requests. |
|
|
82
|
+
|
|
83
|
+
## Providing the access token
|
|
84
|
+
|
|
85
|
+
`getAccessToken` is your integration point with your page's identity stack.
|
|
86
|
+
Return the delegated Entra access token for the currently signed-in user — for example, from MSAL's `acquireTokenSilent`, a server-side session endpoint, or whatever token cache your portal already uses.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const host = createEmbedHost({
|
|
90
|
+
allowedOrigins: ['https://my-rayfin-app.example.com'],
|
|
91
|
+
getAccessToken: async () => {
|
|
92
|
+
const result = await msalInstance.acquireTokenSilent({
|
|
93
|
+
scopes: ['<your-api-scope>'],
|
|
94
|
+
account: msalInstance.getActiveAccount()!,
|
|
95
|
+
});
|
|
96
|
+
return result.accessToken;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The host calls `getAccessToken()` fresh for every handoff request, so returning a short-lived token is fine — you do not need to cache one yourself.
|
|
102
|
+
|
|
103
|
+
## Cleanup
|
|
104
|
+
|
|
105
|
+
`createEmbedHost()` registers a `message` listener on the parent window.
|
|
106
|
+
Call `dispose()` when you remove the iframe (for example, on route change or component unmount) to remove the listener and stop brokering handoffs.
|
|
107
|
+
`dispose()` is idempotent.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
host.dispose();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Security
|
|
114
|
+
|
|
115
|
+
- **Single origin allowlist** — `allowedOrigins` gates both the browser-attested `event.origin` of the iframe that posts the handshake and handoff request, and the `returnOrigin` the handoff code is bound to.
|
|
116
|
+
Messages from any other origin are ignored, and a request naming a return origin outside the list is rejected before any network call.
|
|
117
|
+
- **Token never leaves the parent** — The delegated Entra token is attached only to the outbound `brokered/authorize/external` call.
|
|
118
|
+
It is never sent over the `postMessage` bridge and never returned to the iframe.
|
|
119
|
+
- **PKCE S256** — The embedded app generates the PKCE challenge; the handoff code is bound to it and is single-use.
|
|
120
|
+
- **Correlated responses** — Each handoff response is matched to its request by a correlation id, so a response is only delivered to the request that asked for it.
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
- **The app keeps its stored session without signing out or calling the external endpoint** — Check the embedded app's startup ordering.
|
|
125
|
+
Call and await `initEmbeddedAuth()` before checking for a stored user; importing the provider package alone does not start authentication.
|
|
126
|
+
- **The app falls back to a popup or normal Fabric login** — The readiness signal was missed.
|
|
127
|
+
Confirm `createEmbedHost()` runs before the iframe is mounted, and that the iframe's origin is listed in `allowedOrigins`.
|
|
128
|
+
- **Handoff request rejected before any network call** — The request's return origin is not in `allowedOrigins`.
|
|
129
|
+
Add the embedded app's exact origin (scheme, host, and port) to the list.
|
|
130
|
+
- **Authorization call fails** — Verify `getAccessToken()` returns a valid delegated Entra token with the scope your app's `brokered/authorize/external` endpoint expects.
|
|
131
|
+
- **Nothing happens after mounting the iframe** — Confirm the embedded Rayfin app is built with an external-Entra-enabled auth provider (see [Fabric brokered auth](./fabric.md) for the iframe side).
|
|
@@ -7,12 +7,18 @@ sidebar_position: 2
|
|
|
7
7
|
Fabric authentication lets users sign in to your Rayfin application with their existing Microsoft Entra identity through the Fabric Portal.
|
|
8
8
|
No separate login form is needed — users authenticate once in Fabric and your app inherits that session automatically.
|
|
9
9
|
|
|
10
|
-
The SDK supports
|
|
10
|
+
The SDK supports three modes:
|
|
11
11
|
|
|
12
12
|
- **Popup flow** — your app opens the Fabric Portal in a new browser tab, the user authenticates, and the tab closes automatically.
|
|
13
13
|
- **Embedded flow** — your app runs inside a Fabric iframe and inherits the session via `postMessage` with no popup, redirect, or user interaction.
|
|
14
|
+
- **Direct token flow** — your browser or Node.js app supplies an existing delegated Entra token and establishes a Rayfin session without a browser broker.
|
|
15
|
+
See [Direct Entra token sign-in](./direct-entra-auth.md).
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
The popup and embedded flows use PKCE S256, `postMessage` origin validation, and state nonces.
|
|
18
|
+
The direct flow uses an HTTPS token exchange with delegated-token validation and item-level Execute permission checks.
|
|
19
|
+
|
|
20
|
+
> **Embedding outside Fabric?** If your app runs inside an iframe on your own third-party portal rather than the Fabric Portal, the portal brokers sign-in with its own Entra token via the parent-page [external embed host](./external-embed-host.md).
|
|
21
|
+
> On startup the embedded app posts a one-shot readiness signal and briefly waits for the parent to acknowledge it; if no external embed host answers, the app falls back to the standard Fabric login waterfall described below with no added user-visible delay.
|
|
16
22
|
|
|
17
23
|
## How it works
|
|
18
24
|
|
|
@@ -103,7 +109,9 @@ async function handleSignIn() {
|
|
|
103
109
|
### Embedded flow: automatic authentication on startup
|
|
104
110
|
|
|
105
111
|
Call `initEmbeddedAuth()` once at app startup (for example, in a React `useEffect` or initialization routine).
|
|
106
|
-
|
|
112
|
+
Await it before restoring a stored user or rendering authenticated content, even when a persisted session exists.
|
|
113
|
+
It is safe to call on every page load: standalone pages return `null` immediately, while framed pages briefly wait for an external embed acknowledgement before choosing the login path.
|
|
114
|
+
Keep session-change observers from publishing a stored user while initialization is pending.
|
|
107
115
|
|
|
108
116
|
```typescript
|
|
109
117
|
import { RayfinClient } from '@microsoft/rayfin-client';
|
|
@@ -130,7 +138,7 @@ if (session) {
|
|
|
130
138
|
|
|
131
139
|
Import `@microsoft/rayfin-auth-provider-fabric` statically in your app entry module rather than only via dynamic `import()`.
|
|
132
140
|
The package captures the `?fabricEmbedded=true` URL flag into `sessionStorage` as a side effect at module load, and that must happen on the initial page load before any client-side navigation strips the query string (for example, a post-logout redirect to `/login`).
|
|
133
|
-
|
|
141
|
+
Do not condition the startup call on the absence of a stored session; that bypasses the SDK's identity check and external embed handshake.
|
|
134
142
|
|
|
135
143
|
### Detecting embedded mode
|
|
136
144
|
|
|
@@ -262,7 +270,7 @@ Most apps should use `ensureSignedInWithFabric` instead.
|
|
|
262
270
|
|
|
263
271
|
## Security
|
|
264
272
|
|
|
265
|
-
- **PKCE S256** —
|
|
273
|
+
- **PKCE S256** — The popup and embedded flows generate a cryptographic code verifier and challenge to prevent authorization code interception.
|
|
266
274
|
- **State nonce** — A random nonce ties the postMessage response to the originating flow, preventing CSRF.
|
|
267
275
|
- **In-closure code verifier** — The PKCE `code_verifier` is held in memory (closure) and never persisted to localStorage.
|
|
268
276
|
- **Origin validation** — The SDK validates `event.origin` on incoming messages against `fabricPortalUrl`.
|
|
@@ -26,8 +26,14 @@ Rayfin supports multiple authentication methods that you can enable independentl
|
|
|
26
26
|
- **Magic link** — Passwordless sign-in via email links.
|
|
27
27
|
- **Fabric brokered auth** — Single sign-on through the Microsoft Fabric Portal using the user's Entra identity.
|
|
28
28
|
See [Fabric Brokered Auth](./fabric.md) for setup and usage.
|
|
29
|
+
- **Direct Entra token sign-in** — Exchange an existing delegated Entra token for a Rayfin session from a browser or Node.js app.
|
|
30
|
+
See [Direct Entra token sign-in](./direct-entra-auth.md).
|
|
31
|
+
- **External embed host** — Broker sign-in for a Rayfin app embedded in your own third-party portal, using the portal's Entra token.
|
|
32
|
+
See [External embed host](./external-embed-host.md).
|
|
29
33
|
|
|
30
34
|
## Next steps
|
|
31
35
|
|
|
32
36
|
- [How to configure auth](./overview.md)
|
|
33
37
|
- [Fabric brokered auth](./fabric.md)
|
|
38
|
+
- [Direct Entra token sign-in](./direct-entra-auth.md)
|
|
39
|
+
- [External embed host](./external-embed-host.md)
|
|
@@ -8,6 +8,8 @@ sidebar_position: 2
|
|
|
8
8
|
npx rayfin connector add --type <type> --workspace-id <ws-id> --item-id <item-id> [--name <name>] [--operations <ops>]
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
> **`kusto` authoring is held in this release**, so `connector add --type kusto` refuses before writing anything. Kusto examples below describe the authoring path for when it ships. See [Connectors](./index.md) for what a project that already declares Kusto can still do.
|
|
12
|
+
|
|
11
13
|
`connector add` declares a connector in `rayfin/rayfin.yml` and scaffolds its supporting files.
|
|
12
14
|
|
|
13
15
|
The CLI verifies the Fabric item, derives a connector `name` from the item's display name (override with `--name`), writes the entry to `rayfin.yml`, and scaffolds `rayfin/connectors/<name>/schema.ts`. For Category A connectors it also runs schema discovery and writes `rayfin/connectors/<name>/metadata.json` so a subset of entities can be generated later.
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
sidebar_position:
|
|
2
|
+
sidebar_position: 6
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Category B — function-bridge connectors
|
|
6
6
|
|
|
7
|
-
Reference for `
|
|
7
|
+
Reference for `fabric-semanticmodel` (Power BI semantic model) and the experimental `kusto` (the **Eventhouse** connector — a Fabric Eventhouse KQL Database).
|
|
8
|
+
Eventhouse is the Fabric product name; `kusto` is the type id you pass to `--type`, and KQL is its query language.
|
|
9
|
+
|
|
10
|
+
> **`kusto` authoring is held in this release**, so `connector add --type kusto` refuses and search omits KQL databases. Everything below about `kusto` stays accurate for a project that **already declares** one — which still validates, deploys and invokes — and describes the authoring path for when it ships. Only `fabric-semanticmodel` can be added today. See [Connectors](./index.md).
|
|
11
|
+
|
|
8
12
|
A Category B connector is a named-operation surface backed by a small, platform-owned function (UDF).
|
|
9
13
|
The Builder never writes or sees the function code.
|
|
10
14
|
|
|
@@ -17,8 +21,8 @@ For the entity-generating types (`fabric-sqlanalytics`, `fabric-warehouse`, `fab
|
|
|
17
21
|
|
|
18
22
|
| Type | Operations | Query language | Auth |
|
|
19
23
|
| --- | --- | --- | --- |
|
|
20
|
-
| `kusto` | `executeQuery`, `executeCommand` | KQL | `delegated` only |
|
|
21
24
|
| `fabric-semanticmodel` | `executeQuery` | DAX | `delegated` only |
|
|
25
|
+
| `kusto` (**experimental**) | `executeQuery`, `executeCommand` | KQL | `delegated` only |
|
|
22
26
|
|
|
23
27
|
Both are pinned to an adapter version (`version: '1'` today).
|
|
24
28
|
Delegated authentication runs every call as the signed-in user through the on-behalf-of flow.
|
|
@@ -78,7 +82,7 @@ export const connectorConfig = {
|
|
|
78
82
|
} as const satisfies ConnectorConfig;
|
|
79
83
|
```
|
|
80
84
|
|
|
81
|
-
###
|
|
85
|
+
### The Eventhouse scaffold bakes cluster routing into the generated file
|
|
82
86
|
|
|
83
87
|
`connector add --type kusto` resolves the KQL Database's cluster query endpoint and database name from `(workspaceId, itemId)` at add time and writes both into the generated `connectorConfig`:
|
|
84
88
|
|
|
@@ -100,11 +104,11 @@ Three names appear here and nowhere else:
|
|
|
100
104
|
- `databaseName` — the resolved KQL database name.
|
|
101
105
|
- `KustoConnectorConfig` — the Kusto-specific config type these two keys satisfy, exported from `@microsoft/rayfin-connector-kusto` rather than `@microsoft/rayfin-connectors`.
|
|
102
106
|
|
|
103
|
-
These keys live only in the file the
|
|
107
|
+
These keys live only in the file the Eventhouse scaffold writes.
|
|
104
108
|
They are **not** part of the shared `rayfin.yml` schema — never write a cluster URI or database name into `rayfin.yml`, and never send either value from app code.
|
|
105
109
|
If the resolved values look wrong, re-add the connector rather than editing the generated file; the values come from Fabric, not from anything you can fix by hand.
|
|
106
110
|
|
|
107
|
-
The
|
|
111
|
+
The Eventhouse scaffold imports both its marker and `KustoConnectorConfig` from `@microsoft/rayfin-connector-kusto`, so it does not import `@microsoft/rayfin-connectors` at all.
|
|
108
112
|
|
|
109
113
|
## Install the packages the generated file imports
|
|
110
114
|
|
|
@@ -113,7 +117,7 @@ The Kusto scaffold imports both its marker and `KustoConnectorConfig` from `@mic
|
|
|
113
117
|
```bash
|
|
114
118
|
# Shape only. Use the version connector add printed, not this one.
|
|
115
119
|
|
|
116
|
-
# kusto — marker and config type both come from this one package
|
|
120
|
+
# kusto (experimental) — marker and config type both come from this one package
|
|
117
121
|
npm install @microsoft/rayfin-connector-kusto@1.35.0-alpha
|
|
118
122
|
|
|
119
123
|
# fabric-semanticmodel
|
|
@@ -136,7 +140,7 @@ This is not optional: the runtime is what injects the generated routing and deco
|
|
|
136
140
|
Key the runtime map by the same connector name, and call the factory once per connector:
|
|
137
141
|
|
|
138
142
|
```ts
|
|
139
|
-
import { ConnectorsRayfinClient } from '@microsoft/rayfin-client
|
|
143
|
+
import { ConnectorsRayfinClient } from '@microsoft/rayfin-client';
|
|
140
144
|
import { kusto } from '@microsoft/rayfin-connector-kusto';
|
|
141
145
|
import { fabricSemanticModel } from '@microsoft/rayfin-connector-fabric-semanticmodel';
|
|
142
146
|
import {
|
|
@@ -174,11 +178,11 @@ const client = new ConnectorsRayfinClient<
|
|
|
174
178
|
);
|
|
175
179
|
```
|
|
176
180
|
|
|
177
|
-
`ConnectorsRayfinClient` is
|
|
181
|
+
`ConnectorsRayfinClient` is stable — import it from the main `@microsoft/rayfin-client` entry.
|
|
178
182
|
|
|
179
183
|
The connector key must be identical in four places: the `name` in `rayfin.yml`, the property in `AppConnectorsSchema`, the property in the `connectors` option, and the property in the runtime map.
|
|
180
184
|
|
|
181
|
-
## Calling
|
|
185
|
+
## Calling an Eventhouse connector
|
|
182
186
|
|
|
183
187
|
Correlation ids are not part of the response body — the connector function relays the Kusto bytes untouched — so generate the `clientRequestId` yourself and pass the same value to both `executeQuery` and `toQueryResult`:
|
|
184
188
|
|
|
@@ -208,6 +212,28 @@ Successful results contain `tables` plus the `clientRequestId` you passed in (em
|
|
|
208
212
|
Each table contains named typed `columns` and row-major `rows`.
|
|
209
213
|
Error results contain `error.message` and an optional `error.code`.
|
|
210
214
|
|
|
215
|
+
### Building queries safely
|
|
216
|
+
|
|
217
|
+
`executeQuery` takes its KQL in `query` and `executeCommand` takes its command in `command`; neither operation binds parameters — `ExecuteQueryInput` exposes only `query` and `clientRequestId`, and `ExecuteCommandInput` only `command` and `clientRequestId`. Every user value you place in that text runs as KQL, so treat all user input as unsafe and never interpolate it raw.
|
|
218
|
+
|
|
219
|
+
- **Identifiers** (table, column, function names): map the user's choice through a fixed allow-list to a known-good constant. Never build an identifier from user text.
|
|
220
|
+
- **Values**: serialize each as a typed KQL literal. Validate numbers (for example with `Number.isFinite`), parse datetimes to ISO 8601 and wrap them in `todatetime(...)`, and for strings escape `\` and `"` and reject control characters. This repo ships no KQL encoder; generic SQL or JSON escaping does not make KQL safe.
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const TABLES = { events: 'Events', logs: 'Logs' } as const;
|
|
224
|
+
const table = TABLES[userTable];
|
|
225
|
+
if (!table) throw new Error('unknown table');
|
|
226
|
+
|
|
227
|
+
// Typed KQL string literal: escape backslash and double-quote, reject control chars.
|
|
228
|
+
function kqlString(value: string): string {
|
|
229
|
+
if (/[\u0000-\u001F]/.test(value)) throw new Error('control character in value');
|
|
230
|
+
return '"' + value.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
231
|
+
}
|
|
232
|
+
// kqlString('contoso "42"') -> "contoso \"42\""
|
|
233
|
+
|
|
234
|
+
const query = `${table} | where DeviceId == ${kqlString(userDeviceId)} | take 200`;
|
|
235
|
+
```
|
|
236
|
+
|
|
211
237
|
### Management commands
|
|
212
238
|
|
|
213
239
|
`executeCommand` runs a Kusto management (control) command — the command text starts with a leading dot.
|
|
@@ -240,10 +266,10 @@ Run `rayfin docs search "resultSetRowCountLimit"` for version-locked details, si
|
|
|
240
266
|
`rayfin connector invoke <name> <operation>` is the loop for Category B.
|
|
241
267
|
See [`connector invoke`](./invoke.md) for payload input, transports, token handling, and the output contract.
|
|
242
268
|
|
|
243
|
-
- `connector inspect` supports `fabric-semanticmodel` but **not** `kusto` — a `kusto` connector errors with `Unsupported connector type: kusto`.
|
|
269
|
+
- `connector inspect` supports `fabric-semanticmodel` but **not** experimental `kusto` — a `kusto` connector errors with `Unsupported connector type: kusto`.
|
|
244
270
|
There is no ad-hoc query path for Kusto connectors today.
|
|
245
271
|
- `connector invoke` on `fabric-semanticmodel` calls Fabric/Power BI directly under the developer's identity, so it works with or without `rayfin up`.
|
|
246
|
-
Every other type, `kusto
|
|
272
|
+
Every other type, including experimental `kusto`, POSTs to the deployed item and requires a prior `rayfin up`.
|
|
247
273
|
- `connector invoke` on `fabric-semanticmodel` returns an already-normalized result, because that connector normalizes inside its `invoke` middleware.
|
|
248
274
|
Do not apply `toQueryResult` to it again.
|
|
249
275
|
- A resolved `connector invoke` call is not automatically a success.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 9
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Eventhouse (`kusto`) usage guide
|
|
6
|
+
|
|
7
|
+
> **Moved.** This usage guide now ships **inside the connector package**,
|
|
8
|
+
> version-locked to the `kusto` connector the Builder actually installed — so the
|
|
9
|
+
> streaming model, KQL shaping, safe query construction, and result handling can
|
|
10
|
+
> never drift from the CLI. It is fetched on demand with `packageVersion`
|
|
11
|
+
> provenance.
|
|
12
|
+
>
|
|
13
|
+
> Read it from `@microsoft/rayfin-connector-kusto`:
|
|
14
|
+
>
|
|
15
|
+
> - MCP: `search_docs` / `discover_packages`
|
|
16
|
+
> - CLI: `rayfin docs search "<term>"` (module `rayfin-connector-kusto`)
|
|
17
|
+
> - Source: `@microsoft/rayfin-connector-kusto/assets/docs/`
|
|
18
|
+
>
|
|
19
|
+
> The shared function-bridge mechanics — `connector add`, the generated
|
|
20
|
+
> `rayfin.yml` and `schema.ts`, and the `client.connectors.<name>` call — stay in
|
|
21
|
+
> the [Category B guide](./category-b-function-bridge.md).
|
|
@@ -6,25 +6,13 @@ sidebar_position: 6
|
|
|
6
6
|
|
|
7
7
|
Connectors let a Rayfin app read from — and, for some types, write to — Microsoft Fabric data sources: warehouses, SQL databases, Lakehouse SQL analytics endpoints, semantic models, and KQL databases.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The `connector` command group is always available.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**Lakehouse scope:** `fabric-sqlanalytics` connects only to a Lakehouse's SQL analytics endpoint.
|
|
12
|
+
It can read SQL-visible tables and views, but it cannot directly open files from the Lakehouse `Files` area, such as PDFs or images.
|
|
13
|
+
This connector is read-only; the Warehouse and SQL Database connectors also support write operations.
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
services:
|
|
15
|
-
connectors:
|
|
16
|
-
enabled: true
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
With that setting present the command group is available from the very first `connector add`, with nothing to configure in the shell — the path generated apps and agents should use.
|
|
20
|
-
|
|
21
|
-
The flag also activates automatically once `rayfin.yml` has a `connectors:` block (written by `connector add`), and it can still be turned on for a single command with the environment variable:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
RAYFIN_FEATURE_FLAGS=connectors npx rayfin connector search --help
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Without any of the three the commands do not exist and the CLI reports an unknown command.
|
|
15
|
+
> **`kusto` authoring is held in this release.** `connector types` and `connector search` omit it, and `connector add --type kusto` refuses it. A project that **already declares** a Kusto connector is unaffected: it still validates, deploys through `rayfin up`, and answers `connector invoke`. Kusto material in these docs describes that preserved runtime contract and the authoring path for when it ships.
|
|
28
16
|
|
|
29
17
|
Each command has its own reference page:
|
|
30
18
|
|
|
@@ -36,7 +24,8 @@ Each command has its own reference page:
|
|
|
36
24
|
Each category has its own contract page — read the one that matches your connector type, not both:
|
|
37
25
|
|
|
38
26
|
- [Category A — GraphQL entity connectors](./category-a-entities.md) — now **package-owned**; the full reference (entity generation, `@role` policies, the aggregate schema, and the per-dialect read/write matrix) ships in `@microsoft/rayfin-connector-fabric-graphql` (`rayfin docs search` / `search_docs`).
|
|
39
|
-
- [Category B — function-bridge connectors](./category-b-function-bridge.md) — the `
|
|
27
|
+
- [Category B — function-bridge connectors](./category-b-function-bridge.md) — the `fabric-semanticmodel` and experimental `kusto` contract, including the Kusto cluster routing baked into the generated `schema.ts`.
|
|
28
|
+
- [Eventhouse (`kusto`) usage guide](./eventhouse.md) — the experimental `kusto` supplement, now **package-owned**; when to reach for the type, its streaming model, shaping KQL, safe query construction, and reading results all ship in `@microsoft/rayfin-connector-kusto` (`rayfin docs search` / `search_docs`).
|
|
40
29
|
|
|
41
30
|
A typical loop is search → add → inspect (Category A) or search → add → invoke (Category B).
|
|
42
31
|
|
|
@@ -46,13 +35,13 @@ The commands available to a connector, and the code you write against it, depend
|
|
|
46
35
|
|
|
47
36
|
| | Category A — GraphQL entity connectors | Category B — function-bridge connectors |
|
|
48
37
|
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
49
|
-
| **Types** | `fabric-sqlanalytics`, `fabric-warehouse`, `fabric-sqldatabase`
|
|
50
|
-
| **App surface** | Generated entity files with typed CRUD through the data client |
|
|
38
|
+
| **Types** | `fabric-sqlanalytics`, `fabric-warehouse`, `fabric-sqldatabase`, `fabric-graphql` | `fabric-semanticmodel`; `kusto` (**experimental**) |
|
|
39
|
+
| **App surface** | Generated entity files with typed CRUD through the data client | Named operations carrying raw queries |
|
|
51
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 |
|
|
52
41
|
| **Auth** | `delegated` or configured per project | Must be `delegated` |
|
|
53
42
|
| **Entity files and `@role` policies** | Yes | No |
|
|
54
43
|
| **`metadata.json` entities** | Yes | No |
|
|
55
|
-
| **`connector inspect`** | Supported | `fabric-semanticmodel` only — `kusto` is not supported |
|
|
44
|
+
| **`connector inspect`** | Supported | `fabric-semanticmodel` only — experimental `kusto` is not supported |
|
|
56
45
|
| **`connector invoke`** | Rarely needed | The main way to exercise the connector |
|
|
57
46
|
|
|
58
47
|
Category B connectors are pinned to an adapter version and expose no GraphQL entities, so there is nothing to generate and no row-level security to author.
|
|
@@ -32,6 +32,10 @@ Two transports, chosen by connector type:
|
|
|
32
32
|
- **`fabric-semanticmodel`** — the CLI calls Fabric/Power BI **directly under the developer's own identity**, so this works whether or not `npx rayfin up` has been run. It requires `workspaceId` **and** `itemId` under the connector's `config:` block; without both, it fails up front rather than falling through to the deployed transport. The Power BI scope and audience are derived from the configured Fabric API base URL, so an INT ring mints an INT-audience token.
|
|
33
33
|
- **Every other type, including `kusto`** — POSTs to the deployed item at `<remote-endpoint>/__private/connectors/<name>/invoke`, so it requires a prior `npx rayfin up`.
|
|
34
34
|
|
|
35
|
+
> `kusto` authoring is held in this release, but invocation is deliberately preserved: a project that already declares a Kusto connector can still invoke it. Only `connector add`, `types` and `search` withdraw the type. See [Connectors](./index.md).
|
|
36
|
+
|
|
37
|
+
`--transport deployed` overrides the type-based choice and forces the deployed route. That route authenticates the **app**, not the developer, so it needs an app-session token in `RAYFIN_TOKEN`; `npx rayfin login` cannot mint one.
|
|
38
|
+
|
|
35
39
|
## Token handling (semantic model path)
|
|
36
40
|
|
|
37
41
|
`npx rayfin login` only consents to the Fabric scope, not the Power BI scope this path needs. Consequences:
|
|
@@ -50,6 +54,34 @@ What `output` holds depends on the connector. `fabric-semanticmodel` normalises
|
|
|
50
54
|
|
|
51
55
|
A resolved call is **not** automatically a success, and the failure signal depends on the same distinction. A connector that normalises reports Power BI failures — expired token, missing Build permission, throttling — as `{status: 'error', error, requestId}`, where `error` carries `category`, `message`, and optional `code` and `details`. A connector that returns the raw envelope reports failure as `status: 'Failed'` instead. The CLI reads both, converts either into a non-zero exit, and surfaces the service-supplied request id for tracing.
|
|
52
56
|
|
|
57
|
+
In JSON mode, failures keep the top-level `error` as a human-readable **string**, with `recovery` and `requestId` when available.
|
|
58
|
+
Connector failures additionally expose a `connectorError` object containing the available `message`, `category`, `code`, and `details` fields.
|
|
59
|
+
Scalar values are stringified and structured values are JSON-encoded, so a numeric `code` or object `details` survives; empty and unavailable fields are omitted, and unrelated CLI failures do not acquire connector metadata.
|
|
60
|
+
The remediation hint stays on the top-level `recovery` string only, so `connectorError` never carries a CLI-fabricated hint.
|
|
61
|
+
This applies to both direct and deployed invocation, including DAX errors returned inside an HTTP 200 Arrow stream.
|
|
62
|
+
The semantic-model SDK also preserves the Arrow error code and description as `error.code` and `error.details` in its normalized result.
|
|
63
|
+
Existing engine-markup cleanup still applies to normalized messages and details.
|
|
64
|
+
|
|
65
|
+
For example, an invalid DAX query exits with code `1` and can emit:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"status": "error",
|
|
70
|
+
"error": "Connector invoke failed (DAX_ERROR): Column not found",
|
|
71
|
+
"recovery": "The service ran the operation and reported an error. Fix the query and retry.",
|
|
72
|
+
"requestId": "service-request-id",
|
|
73
|
+
"connectorError": {
|
|
74
|
+
"message": "Column not found",
|
|
75
|
+
"category": "query",
|
|
76
|
+
"code": "DAX_ERROR",
|
|
77
|
+
"details": "The column Foo does not exist"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Read `connectorError.code` and `connectorError.details` rather than parsing the display string.
|
|
83
|
+
Service diagnostics may contain query or model content; review them before sharing or recording them in logs.
|
|
84
|
+
|
|
53
85
|
## Examples
|
|
54
86
|
|
|
55
87
|
```bash
|
|
@@ -8,7 +8,9 @@ sidebar_position: 1
|
|
|
8
8
|
npx rayfin connector search [query] [--workspace-id <id> --type <types> | --all-workspaces --type <types>] [--limit <n>] [--json]
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
> **`kusto` authoring is held in this release**, so search does not return KQL databases and `--type kusto` is not accepted. Search exists to feed `connector add`, which would refuse the type — surfacing a source the Builder could not then attach. See [Connectors](./index.md).
|
|
12
|
+
|
|
13
|
+
`connector search` finds Fabric data sources — warehouses, SQL databases, Lakehouses, and semantic models — that the signed-in identity can add as connectors, before you know exact workspace or item IDs.
|
|
12
14
|
|
|
13
15
|
Use it to find candidates for [`connector add`](./add.md). It never touches app data itself.
|
|
14
16
|
|
|
@@ -38,7 +40,7 @@ Only one of `--workspace-id` and `--all-workspaces` may be given. Outside a Rayf
|
|
|
38
40
|
|
|
39
41
|
Duplicate-looking entries — for example a SQL Database and its SQL-analytics-endpoint twin sharing a workspace and display name — are grouped visually next to each other in interactive and plain output only. They are never deduplicated, and `--json` always returns the canonical, ungrouped order.
|
|
40
42
|
|
|
41
|
-
The SQL-endpoint-permissions note ("Schema discovery for SQL-based connectors requires SQL endpoint permissions") only prints when at least one result is a SQL-dialect connector type — never for a semantic-model-only
|
|
43
|
+
The SQL-endpoint-permissions note ("Schema discovery for SQL-based connectors requires SQL endpoint permissions") only prints when at least one result is a SQL-dialect connector type — never for a semantic-model-only result set. (It would also not print for a Kusto-only set, once Kusto authoring ships.)
|
|
42
44
|
|
|
43
45
|
## Examples
|
|
44
46
|
|
|
@@ -189,7 +189,7 @@ These variables are read from the shell environment and are never written to fil
|
|
|
189
189
|
| `RAYFIN_WORKSPACE_ID` | Fabric workspace ID for non-interactive setup. Used with `RAYFIN_TOKEN`. |
|
|
190
190
|
| `RAYFIN_TENANT_ID` | Entra ID tenant used by `rayfin up` for portal URLs and the `ctid` query parameter. Equivalent to the `-t, --tenant <id>` flag (precedence: flag > env var > signed-in tenant). |
|
|
191
191
|
| `RAYFIN_ENCRYPTION_FALLBACK_ENABLED` | Set to `true` to allow plaintext token cache on systems without OS credential storage. Development only. |
|
|
192
|
-
| `RAYFIN_FEATURE_FLAGS` | Comma-separated list of experimental feature names to enable (case-insensitive). Recognized values include `docker-local-dev`, `
|
|
192
|
+
| `RAYFIN_FEATURE_FLAGS` | Comma-separated list of experimental feature names to enable (case-insensitive). Recognized public values include `docker-local-dev`, `postgresql`, and `storage`. |
|
|
193
193
|
| `RAYFIN_WEBSERVICE_IMAGE_NAME` | **Experimental.** Override the webservice container image used by `rayfin dev --provider docker` and Docker Compose. Defaults to `ghcr.io/microsoft/project-rayfin/webservice:cli-<version>`. |
|
|
194
194
|
| `RAYFIN_APPINSIGHTS_CONNECTION_STRING` | Override the telemetry endpoint for the CLI and VS Code extension. |
|
|
195
195
|
| `RAYFIN_TELEMETRY_ENV` | Override the CLI and `create-rayfin` telemetry environment label. Values are trimmed and lowercased. Known labels include `github-actions`, `azure-pipelines`, `gitlab-ci`, `jenkins`, `codespaces`, `devcontainer`, `local`, and `other`; custom labels may contain 1–64 ASCII letters, digits, hyphens, or underscores. Invalid non-empty values map to `other`, while an empty value uses automatic detection. Do not include identifying or sensitive values. |
|
|
@@ -199,8 +199,8 @@ These variables are read from the shell environment and are never written to fil
|
|
|
199
199
|
| Flag | Effect |
|
|
200
200
|
| --- | --- |
|
|
201
201
|
| `docker-local-dev` | Allows `rayfin dev --provider docker` and the Docker maintenance commands. Bare `rayfin dev` remains available without this flag and defaults to Fabric. |
|
|
202
|
-
| `functions` | Exposes Functions service prompts during `rayfin init`. |
|
|
203
202
|
| `postgresql` | Adds PostgreSQL as a selectable dialect during `rayfin init` and `rayfin init` with bundled templates. |
|
|
203
|
+
| `storage` | Enables the preview Storage service when declared in `rayfin.yml` or opted in from the shell. |
|
|
204
204
|
|
|
205
205
|
## File locations
|
|
206
206
|
|
package/assets/docs/cli/index.md
CHANGED
|
@@ -73,6 +73,20 @@ Functions are server-side user-defined functions (UDFs) that run in the Fabric r
|
|
|
73
73
|
| `npx rayfin dev functions apply` | Run the local function host with a live typegen watcher and debugger support. See [dev functions apply](./functions/dev-apply.md). |
|
|
74
74
|
| `npx rayfin up functions deploy` | Build, package, and deploy functions to the remote Rayfin item. `rayfin up` runs this automatically. See [up functions deploy](./functions/deploy.md). |
|
|
75
75
|
|
|
76
|
+
### Connectors
|
|
77
|
+
|
|
78
|
+
Connectors let a Rayfin app read from — and, for some types, write to — Microsoft Fabric data sources. See [Connectors](./connectors/index.md) for the full guide.
|
|
79
|
+
|
|
80
|
+
| Command | Description |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `npx rayfin connector search [query]` | Discover Fabric sources the signed-in identity can add before you know exact workspace or item IDs. See [connector search](./connectors/search.md). |
|
|
83
|
+
| `npx rayfin connector add --type <type> --workspace-id <ws-id> --item-id <item-id>` | Declare a connector in `rayfin.yml` and scaffold `rayfin/connectors/<name>/`. See [connector add](./connectors/add.md). |
|
|
84
|
+
| `npx rayfin connector inspect` | Explore a connector's underlying source in read-only mode by listing entity names, sampling one entity, or running a `.sql` / `.dax` query file. See [connector inspect](./connectors/inspect.md). |
|
|
85
|
+
| `npx rayfin connector invoke <connector-name> <operation>` | Run a single named operation against a configured connector. See [connector invoke](./connectors/invoke.md). |
|
|
86
|
+
| `npx rayfin connector list` | Print the configured connectors. See [Connectors](./connectors/index.md#where-connector-state-lives). |
|
|
87
|
+
| `npx rayfin connector remove <name>` | Delete both the `rayfin.yml` entry and the `rayfin/connectors/<name>/` directory. See [Connectors](./connectors/index.md#where-connector-state-lives). |
|
|
88
|
+
| `npx rayfin up connector apply [--name <name>]` | Re-apply DAB config only. See [Deploying connectors](./connectors/index.md#deploying-connectors). |
|
|
89
|
+
|
|
76
90
|
### Secrets
|
|
77
91
|
|
|
78
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.
|
|
@@ -112,3 +126,25 @@ To disable telemetry, set the following environment variable:
|
|
|
112
126
|
```bash
|
|
113
127
|
export RAYFIN_TELEMETRY_OPTOUT=1
|
|
114
128
|
```
|
|
129
|
+
|
|
130
|
+
## Diagnostic logs
|
|
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`.
|
|
133
|
+
After a failure, open the file identified by `Diagnostic log:` to inspect the original invocation without rerunning it.
|
|
134
|
+
JSON failures include the same path in the `diagnosticLog` field of the single result object.
|
|
135
|
+
`dev` JSON failures also include a `hint` with recovery guidance, including provider/configuration preflight errors and unexpected failures.
|
|
136
|
+
|
|
137
|
+
Adding `--verbose` also mirrors diagnostic records to stderr while `up` or `dev` runs.
|
|
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.
|
|
142
|
+
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.
|
|
144
|
+
|
|
145
|
+
Logs stay on your machine and are independent of telemetry opt-out.
|
|
146
|
+
The log directory is shared across projects on your machine, so the retention limits below apply across all projects using it.
|
|
147
|
+
Known credential patterns are redacted, and build output is bounded, but review logs before sharing them because project tools can emit their own content.
|
|
148
|
+
Retention is best-effort: logs older than 14 days are pruned, with targets of 20 invocation files and 100 MiB total; each file is limited to 10 MiB.
|
|
149
|
+
If `RAYFIN_CONFIG_DIR` is set, logs use its `logs/` subdirectory instead.
|
|
150
|
+
An unavailable or full log directory does not change the command result.
|
|
@@ -20,6 +20,12 @@ Every `npm create @microsoft/rayfin@latest` or `npx rayfin init` invocation can
|
|
|
20
20
|
External and local template sources are discovered through `rayfin-template.yml` manifests inside the selected source directory.
|
|
21
21
|
Built-in templates are packaged with the CLI and appear in `--list-templates` automatically.
|
|
22
22
|
|
|
23
|
+
> **Universal App is available as the built-in `blankapp` template.**
|
|
24
|
+
> The visible `blankapp` entry appears in `--list-templates` and is available in the CLI and VS Code.
|
|
25
|
+
> Its canonical `universal-app` name remains hidden to avoid a duplicate listing, but plugin automation can still select it explicitly with `--template universal-app`.
|
|
26
|
+
> Both names scaffold the same committed workspace template.
|
|
27
|
+
> This does not change support for ordinary local directories, git repositories, or registered templates.
|
|
28
|
+
|
|
23
29
|
## List available templates
|
|
24
30
|
|
|
25
31
|
Use `--list-templates` to see every template the CLI can scaffold from in your current directory:
|
|
@@ -24,6 +24,92 @@ your-project/
|
|
|
24
24
|
└── README.md
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## Universal App workspace
|
|
28
|
+
|
|
29
|
+
Universal Apps generated by the Rayfin Copilot plugin use an npm workspace while preserving the same root workflow:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
your-universal-app/
|
|
33
|
+
├── package.json
|
|
34
|
+
├── tsconfig.base.json
|
|
35
|
+
├── tsconfig.json
|
|
36
|
+
├── rayfin/
|
|
37
|
+
│ └── rayfin.yml
|
|
38
|
+
└── packages/
|
|
39
|
+
├── frontend/
|
|
40
|
+
│ ├── src/
|
|
41
|
+
│ ├── package.json
|
|
42
|
+
│ └── vite.config.ts
|
|
43
|
+
├── data/
|
|
44
|
+
│ ├── src/index.ts
|
|
45
|
+
│ └── package.json
|
|
46
|
+
└── shared/
|
|
47
|
+
├── src/index.ts
|
|
48
|
+
└── package.json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The workspace root owns the application identity, npm workspace declaration, orchestration scripts, applied capability-pack record, TypeScript project references, and `rayfin/rayfin.yml`.
|
|
52
|
+
It coordinates the packages but does not own application runtime code.
|
|
53
|
+
|
|
54
|
+
| Package | Stable name | Ownership |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `packages/frontend` | `@rayfin-app/frontend` | React, Vite, Fabric authentication, browser UI, and static output |
|
|
57
|
+
| `packages/data` | `@rayfin-app/data` | Rayfin entity registration and data schema exports |
|
|
58
|
+
| `packages/shared` | `@rayfin-app/shared` | Isomorphic contracts shared across runtime boundaries |
|
|
59
|
+
| `packages/functions` | `@rayfin-app/functions` | Opt-in trusted server workflows created by the functions capability pack |
|
|
60
|
+
|
|
61
|
+
Only the generated root package name is personalized.
|
|
62
|
+
The stable member names, cross-package dependency keys, and import specifiers are not renamed.
|
|
63
|
+
|
|
64
|
+
Use root commands for the complete app workflow:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm run build
|
|
68
|
+
npm run typecheck
|
|
69
|
+
npm run lint
|
|
70
|
+
npm test
|
|
71
|
+
npm run preview
|
|
72
|
+
npm run pack:add -- <pack>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The root build orders shared, data, and frontend work.
|
|
76
|
+
Focused package commands use npm's workspace selector, such as `npm run -w @rayfin-app/frontend test`.
|
|
77
|
+
|
|
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.
|
|
80
|
+
Capability packs do not use a nested functions lockfile or nested install.
|
|
81
|
+
|
|
82
|
+
### Universal App service paths
|
|
83
|
+
|
|
84
|
+
Universal App service paths point to the package that owns each deployable surface:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
services:
|
|
88
|
+
data:
|
|
89
|
+
enabled: false
|
|
90
|
+
path: packages/data
|
|
91
|
+
buildCommand: npm run build
|
|
92
|
+
staticHosting:
|
|
93
|
+
enabled: true
|
|
94
|
+
path: packages/frontend
|
|
95
|
+
folder: dist
|
|
96
|
+
buildCommand: npm run build:fabric
|
|
97
|
+
assetAccess: protected
|
|
98
|
+
functions:
|
|
99
|
+
enabled: false
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Rayfin resolves each `path` from the application root, then runs that service's `buildCommand` with the service directory as its working directory.
|
|
103
|
+
The static-hosting folder is therefore `packages/frontend/dist`, not a root `dist` directory.
|
|
104
|
+
After the functions pack is applied, functions uses `path: packages/functions` with its package-local `npm run build`.
|
|
105
|
+
|
|
106
|
+
The Project Rayfin repository keeps this Builder-facing workspace under `samples/universal-app/template`.
|
|
107
|
+
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.
|
|
108
|
+
The Copilot plugin bundles the inner template only; the harness and generated target are not distributed.
|
|
109
|
+
|
|
110
|
+
Existing flat Universal Apps remain supported by plugin validation and do not need to adopt this layout.
|
|
111
|
+
This workspace template does not add automatic workspace discovery, a migration command, support for package managers other than npm, or functions by default.
|
|
112
|
+
|
|
27
113
|
## Key files
|
|
28
114
|
|
|
29
115
|
### rayfin/rayfin.yml
|
|
@@ -103,6 +189,8 @@ services:
|
|
|
103
189
|
| --- | --- | --- | --- |
|
|
104
190
|
| `enabled` | `boolean` | `false` | Enable the data service. |
|
|
105
191
|
| `dialect` | `"mssql"` \| `"postgresql"` | `"mssql"` | Database dialect. Fabric deployments support MSSQL only. |
|
|
192
|
+
| `path` | `string` | Project root | Data project directory relative to the application root. |
|
|
193
|
+
| `buildCommand` | `string` | — | Command run from the resolved data service path before packaging. |
|
|
106
194
|
|
|
107
195
|
#### `services.auth`
|
|
108
196
|
|
|
@@ -171,9 +259,10 @@ Configure an email provider for magic links, password resets, and email verifica
|
|
|
171
259
|
| Field | Type | Default | Description |
|
|
172
260
|
| --- | --- | --- | --- |
|
|
173
261
|
| `enabled` | `boolean` | `false` | Enable static content hosting. |
|
|
262
|
+
| `path` | `string` | — | Frontend project directory relative to the application root. |
|
|
174
263
|
| `root` | `string` | — | Root directory of the frontend project (relative to the project root). |
|
|
175
|
-
| `folder` | `string` | `"dist"` | Directory containing built static assets
|
|
176
|
-
| `buildCommand` | `string` | — | Shell command
|
|
264
|
+
| `folder` | `string` | `"dist"` | Directory containing built static assets, relative to `path` or legacy `root`. |
|
|
265
|
+
| `buildCommand` | `string` | — | Shell command run from the resolved static-hosting path before packaging (for example, `npm run build`). |
|
|
177
266
|
| `indexDocument` | `string` | — | Default document served for the root path (e.g. `index.html`). |
|
|
178
267
|
|
|
179
268
|
> **Tip:** All string values support environment variable interpolation with `${VAR}` and `${VAR:-default}` syntax.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/rayfin-guide",
|
|
3
|
-
"version": "1.36.0-alpha.
|
|
3
|
+
"version": "1.36.0-alpha.1663",
|
|
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": [
|
|
File without changes
|