[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M699Y2D9ECAPQVMN9FBVCFNT":3,"skill-same:01M699Y2D9ECAPQVMN9FBVCFNT":60},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":32,"linkOnly":33,"markdownContent":34,"markdownBody":35,"frontMatter":36,"refName":37,"commitSha":38,"skillDirectory":39,"forksCount":40,"repositoryHtmlUrl":41,"repositoryHomepageUrl":6,"ownerHtmlUrl":42,"ownerBlogUrl":43,"ownerDescription":44,"updatedAt":45,"install":46,"resources":59},"01M699Y2D9ECAPQVMN9FBVCFNT","external-api-workflows",null,"Build a Universal App workflow that calls a third-party API or custom model endpoint through a server-side function. Use for API keys, webhooks, Azure OpenAI-compatible endpoints, payment, messaging, or any provider credential that must stay out of the browser.","microsoft\u002Frayfin","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M699VK9NEV8GH0Y5JKT1G8XG",655,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Fexternal-api-workflows\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[29,30,31],"workflows","external api workflows","workflow","2026-11-10 10:12:30",false,"---\nname: external-api-workflows\ndescription: >\n  Build a Universal App workflow that calls a third-party API or custom model\n  endpoint through a server-side function.\n  Use for API keys, webhooks, Azure OpenAI-compatible endpoints, payment,\n  messaging, or any provider credential that must stay out of the browser.\n---\n\n# External API workflows\n\nUse a Rayfin function as the trust boundary between the UI and the external\nprovider.\nRead `functions-capability` and apply its pack before implementing this\nworkflow.\n\n## Secret contract\n\nDeclare only the secret name and a non-sensitive description in\n`rayfin\u002Frayfin.yml`.\nNever put the value in YAML:\n\n```yaml\nsecrets:\n  - name: THIRD_PARTY_API_KEY\n    description: Credential used by the server-side fulfillment request.\n```\n\nDeploy the app once before provisioning the value. Obtain the user's\nconfirmation for the target workspace and remote deployment.\nRead `app-deployment` and complete its version-matched Rayfin CLI workflow.\nThe current secret command requires a deployed AppBackend endpoint.\n\nThen ask the user to run:\n\n```sh\nnpx rayfin secret set THIRD_PARTY_API_KEY\n```\n\nThis command requires an interactive terminal for its masked prompt.\nIf the host can spawn an independent interactive terminal, open it at the app\nroot and start this command there so the masked prompt is immediately waiting.\nDo not claim that a terminal was opened unless the launch succeeded.\nOtherwise, pause and tell the user where to run the exact command.\nDo not pass the value through a non-interactive shell tool.\nThe user enters the value directly into that command's masked prompt.\nDo not ask the user to paste a secret into chat.\nDo not place the value in source, YAML, frontend environment variables,\ncommand arguments, logs, or function output.\nWait for the user to confirm that provisioning completed before invoking the\ndeployed workflow.\n\nAfter the value is provisioned, open the deployed `fabricUrl` and have the user\ninvoke the workflow in the authenticated UI.\nConfirm that the UI receives only the bounded result contract.\nDo not report the workflow complete before this deployed invocation succeeds\nunless the user explicitly defers runtime validation.\n\nRetrieve the production value only inside the function. The secret is declared\nwith `rayfin secret set`, so it is typed — read it as a property:\n\n```ts\nconst apiKey: string = ctx.Secrets.THIRD_PARTY_API_KEY;\n```\n\n`ctx.Secrets.\u003CNAME>` is typed `string`, not `string | undefined`: declaring the\nsecret is what makes it expected, and a name that was never declared is a\ncompile error. If the value was not supplied at invoke time the read throws a\ndiagnosable error rather than silently yielding `undefined`, so no\n`SECRET_NOT_CONFIGURED` branch is needed. Catch it at the function boundary if\nyou want to map it onto the bounded result contract:\n\n```ts\ntry {\n  const apiKey: string = ctx.Secrets.THIRD_PARTY_API_KEY;\n  \u002F\u002F ...call the external service...\n} catch {\n  return {\n    ok: false,\n    code: 'SECRET_NOT_CONFIGURED',\n    message: 'The external service credential is not configured.',\n  };\n}\n```\n\nNever hard-code the secret name anywhere else — it comes from `rayfin.yml` via\nthe generated registry. `ctx.getSecret('NAME')` is deprecated and flagged by\n`@typescript-eslint\u002Fno-deprecated`; it remains valid only for a value\ndeliberately not modelled in `rayfin.yml`.\n\nDo not return `apiKey`, compare it against browser input, or include it in an\nexception.\nAn environment fallback may be used only for local debugging through the\nfunctions project's ignored local settings.\n\n## Provider boundary\n\n- Do not call generic cloud or provider best-practices tools for a\n  provider-neutral request. Use a provider-specific tool only after the user\n  identifies that provider and the tool is needed to establish its contract.\n- Validate and bound every browser-supplied value before making a request.\n- Set an explicit outbound deadline appropriate for the provider.\n- Send only required headers and fields.\n- Treat non-success provider responses as expected domain outcomes when the UI\n  can act on them.\n- Do not return raw provider bodies or stack traces.\n- Select and bound the provider fields returned to the browser.\n- Do not log the request body, response body, authorization header, secret,\n  prompt, or user content.\n\nUse a bounded result rather than exposing provider data directly:\n\n```ts\ntype ExternalCallResult =\n  | { ok: true; value: string }\n  | {\n      ok: false;\n      code:\n        | 'SECRET_NOT_CONFIGURED'\n        | 'AUTHENTICATION_FAILED'\n        | 'PROVIDER_REJECTED'\n        | 'PROVIDER_TIMEOUT';\n      message: string;\n    };\n```\n\nExpected provider failures use the safe result.\nUnexpected failures may still throw, but the thrown message must not contain a\nsecret, request body, raw provider response, or sensitive exception detail.\n\n## UI contract\n\nShow an in-progress state for the complete invocation.\nRender safe, actionable outcomes for missing configuration, invalid\nauthentication, provider rejection, and timeout.\nKeep an unexpected-failure state for failures outside the known domain result.\n\nIf the provider can take longer than the browser client's configured deadline,\ndo not increase the global timeout for unrelated app operations.\nUse a dedicated client only as a documented temporary workaround until the SDK\nsupports a per-invocation timeout.\n","# External API workflows\n\nUse a Rayfin function as the trust boundary between the UI and the external\nprovider.\nRead `functions-capability` and apply its pack before implementing this\nworkflow.\n\n## Secret contract\n\nDeclare only the secret name and a non-sensitive description in\n`rayfin\u002Frayfin.yml`.\nNever put the value in YAML:\n\n```yaml\nsecrets:\n  - name: THIRD_PARTY_API_KEY\n    description: Credential used by the server-side fulfillment request.\n```\n\nDeploy the app once before provisioning the value. Obtain the user's\nconfirmation for the target workspace and remote deployment.\nRead `app-deployment` and complete its version-matched Rayfin CLI workflow.\nThe current secret command requires a deployed AppBackend endpoint.\n\nThen ask the user to run:\n\n```sh\nnpx rayfin secret set THIRD_PARTY_API_KEY\n```\n\nThis command requires an interactive terminal for its masked prompt.\nIf the host can spawn an independent interactive terminal, open it at the app\nroot and start this command there so the masked prompt is immediately waiting.\nDo not claim that a terminal was opened unless the launch succeeded.\nOtherwise, pause and tell the user where to run the exact command.\nDo not pass the value through a non-interactive shell tool.\nThe user enters the value directly into that command's masked prompt.\nDo not ask the user to paste a secret into chat.\nDo not place the value in source, YAML, frontend environment variables,\ncommand arguments, logs, or function output.\nWait for the user to confirm that provisioning completed before invoking the\ndeployed workflow.\n\nAfter the value is provisioned, open the deployed `fabricUrl` and have the user\ninvoke the workflow in the authenticated UI.\nConfirm that the UI receives only the bounded result contract.\nDo not report the workflow complete before this deployed invocation succeeds\nunless the user explicitly defers runtime validation.\n\nRetrieve the production value only inside the function. The secret is declared\nwith `rayfin secret set`, so it is typed — read it as a property:\n\n```ts\nconst apiKey: string = ctx.Secrets.THIRD_PARTY_API_KEY;\n```\n\n`ctx.Secrets.\u003CNAME>` is typed `string`, not `string | undefined`: declaring the\nsecret is what makes it expected, and a name that was never declared is a\ncompile error. If the value was not supplied at invoke time the read throws a\ndiagnosable error rather than silently yielding `undefined`, so no\n`SECRET_NOT_CONFIGURED` branch is needed. Catch it at the function boundary if\nyou want to map it onto the bounded result contract:\n\n```ts\ntry {\n  const apiKey: string = ctx.Secrets.THIRD_PARTY_API_KEY;\n  \u002F\u002F ...call the external service...\n} catch {\n  return {\n    ok: false,\n    code: 'SECRET_NOT_CONFIGURED',\n    message: 'The external service credential is not configured.',\n  };\n}\n```\n\nNever hard-code the secret name anywhere else — it comes from `rayfin.yml` via\nthe generated registry. `ctx.getSecret('NAME')` is deprecated and flagged by\n`@typescript-eslint\u002Fno-deprecated`; it remains valid only for a value\ndeliberately not modelled in `rayfin.yml`.\n\nDo not return `apiKey`, compare it against browser input, or include it in an\nexception.\nAn environment fallback may be used only for local debugging through the\nfunctions project's ignored local settings.\n\n## Provider boundary\n\n- Do not call generic cloud or provider best-practices tools for a\n  provider-neutral request. Use a provider-specific tool only after the user\n  identifies that provider and the tool is needed to establish its contract.\n- Validate and bound every browser-supplied value before making a request.\n- Set an explicit outbound deadline appropriate for the provider.\n- Send only required headers and fields.\n- Treat non-success provider responses as expected domain outcomes when the UI\n  can act on them.\n- Do not return raw provider bodies or stack traces.\n- Select and bound the provider fields returned to the browser.\n- Do not log the request body, response body, authorization header, secret,\n  prompt, or user content.\n\nUse a bounded result rather than exposing provider data directly:\n\n```ts\ntype ExternalCallResult =\n  | { ok: true; value: string }\n  | {\n      ok: false;\n      code:\n        | 'SECRET_NOT_CONFIGURED'\n        | 'AUTHENTICATION_FAILED'\n        | 'PROVIDER_REJECTED'\n        | 'PROVIDER_TIMEOUT';\n      message: string;\n    };\n```\n\nExpected provider failures use the safe result.\nUnexpected failures may still throw, but the thrown message must not contain a\nsecret, request body, raw provider response, or sensitive exception detail.\n\n## UI contract\n\nShow an in-progress state for the complete invocation.\nRender safe, actionable outcomes for missing configuration, invalid\nauthentication, provider rejection, and timeout.\nKeep an unexpected-failure state for failures outside the known domain result.\n\nIf the provider can take longer than the browser client's configured deadline,\ndo not increase the global timeout for unrelated app operations.\nUse a dedicated client only as a documented temporary workaround until the SDK\nsupports a per-invocation timeout.\n",{"name":5,"description":7},"main","0979439a7a0806abd0ee48c2619b37f297ae1324","samples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Fexternal-api-workflows",73,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-10-30 15:20:57",{"source":8,"skillName":5,"commands":47,"prompt":57,"zipAvailable":58},[48,51,54],{"tool":49,"command":50},"npx","npx skills add microsoft\u002Frayfin --skill external-api-workflows",{"tool":52,"command":53},"bunx","bunx skills add microsoft\u002Frayfin --skill external-api-workflows",{"tool":55,"command":56},"pnpm","pnpm dlx skills add microsoft\u002Frayfin --skill external-api-workflows","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Fexternal-api-workflows\u002FSKILL.md",true,[],[61,74,90,99,118,126],{"skillNo":62,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":32},"01M699YEY2QDVPKTZS3HR9AX84","rayfin-getting-started","Use when starting or creating a NEW Rayfin app, or when a Rayfin task comes up and you are not yet inside a Rayfin project. Gets you into a project with the Rayfin CLI, then hands off to the authoritative, version-locked in-project rayfin skill\u002Fdocs that own all in-project work. Triggers: build a Rayfin app, start a Rayfin project, create a new Rayfin app, create-rayfin, npm create @microsoft\u002Frayfin, rayfin init, scaffold rayfin, rayfin CLI, rayfin template, universal app, awesome-rayfin gallery, get started with Rayfin","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fskills\u002Frayfin-getting-started\u002FSKILL.md",[],[68,69,70,71,9,72,73],"rayfin getting started","rayfin","scaffold","init","docs","cli",{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":86,"publishedAt":32},"01M699YCN4ZDW2AMDP4NVJ2QGC","visuals","Use when user wants to incorporate charts, graphs, data grid,  or other visual representations of data into their project. Use VegaVisual and DataGrid components to create these visuals,  utilizing the shared DataTable input, formatting, theme, and interactivity. Covers the onInteraction selection\u002Fclick events host apps consume, named multi-table data input for layered overlays and reference lines, and Vega-Lite native selections. Triggers: chart, graph, plot, dashboard, KPI, metric, trend, scorecard, data grid, visualize.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Fvisuals\u002FSKILL.md",[80,83],{"categoryNo":81,"categoryName":82,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":84,"categoryName":85,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师",[76,87,88,89],"components","dashboard","visualize",{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":32},"01M699YBEP146MJZJNN8YEBZ2G","schema-discovery","Explore Power BI semantic model schemas using DAX INFO functions. Progressive metadata discovery strategy, scope estimation, and narrowing techniques for tables, columns, measures, and relationships.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Fschema-discovery\u002FSKILL.md",[],[97,98],"schema discovery","dax",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":114,"publishedAt":32},"01M699Y9E80WYFKD1S4MT4B1CS","query-design","Separates DAX data-fetching from TypeScript presentation. Guides when to use  DAX vs. TypeScript vs. Vega-Lite for aggregation, total rows, FORMAT(), SELECTCOLUMNS,  BLANK handling, filtering, multi-grain queries, cross-filtering and cross-highlight subset\u002Foverlay queries, and format strings.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Fquery-design\u002FSKILL.md",[105,108,111],{"categoryNo":106,"categoryName":107,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":109,"categoryName":110,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":112,"categoryName":113,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师",[115,116,98,117],"query design","design","typescript",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":32},"01M699Y7CKZ55QSYFE827RRVJE","functions-capability","Apply and build the Universal App functions capability. Use for trusted server-side logic, secrets, external APIs, custom model endpoints, published Fabric data agents, webhooks, or privileged operations.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Ffunctions-capability\u002FSKILL.md",[],[125],"functions capability",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":32},"01M699Y5R87YE620T78Z30KQSA","fabric-sdk","How to query Fabric data from a running app through the Rayfin connectors client. Use getRayfinClient().connectors.\u003Cname>.executeQuery to run DAX against a semantic model, and toQueryResult to normalize the response.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frayfin\u002Fblob\u002Fmain\u002Fsamples\u002Funiversal-app\u002Ftemplate\u002F.agents\u002Fskills\u002Ffabric-sdk\u002FSKILL.md",[],[133,134,98,135,69,136],"sdk","fabric sdk","rayfin connectors","connectors"]