@salesforce/vite-plugin-lwc-ui-bundle 1.135.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { buildDefaultImperativeBindingsServiceDescriptor, buildQueryImperativeBindingsServiceDescriptor, buildSubscribableImperativeBindingsServiceDescriptor, buildLegacyImperativeBindingsServiceDescriptor } from "@conduit-client/service-bindings-imperative/v1";
2
2
  import { buildLWCWireBindingsServiceDescriptor } from "@conduit-client/service-bindings-lwc/v1";
3
3
  import { err, ok, toError, buildSubscribableResult } from "@conduit-client/utils";
4
- import { getChatSDK } from "@salesforce/sdk-chat";
4
+ import { getChatSDK } from "@salesforce/platform-sdk-chat";
5
5
  function normalizeMcpResponse(raw) {
6
6
  if (raw && typeof raw === "object" && "structuredContent" in raw) {
7
7
  return raw.structuredContent;
@@ -22,6 +22,13 @@ function normalizeMcpResponse(raw) {
22
22
  }
23
23
  return raw ?? {};
24
24
  }
25
+ function resolveMcpToolName(adapterName, cfg) {
26
+ const toolName = cfg.mcp?.toolName;
27
+ if (!toolName) {
28
+ throw new Error(`[${adapterName}] no dispatch backing configured — expected \`mcp.toolName\`.`);
29
+ }
30
+ return toolName;
31
+ }
25
32
  async function getCallTool(adapterName) {
26
33
  const sdk = await getChatSDK();
27
34
  if (typeof sdk.callTool !== "function") {
@@ -108,23 +115,25 @@ const queryImperativeService = buildQueryImperativeBindingsServiceDescriptor().s
108
115
  const subscribableImperativeService = buildSubscribableImperativeBindingsServiceDescriptor().service;
109
116
  const legacyImperativeService = buildLegacyImperativeBindingsServiceDescriptor().service;
110
117
  function createMutationAdapter(name, cfg) {
118
+ const toolName = resolveMcpToolName(name, cfg);
111
119
  const getCommand = (options) => {
112
120
  options.assertIsValid(options.params[0], cfg.configJsonSchema);
113
- return new McpToolCommand(name, cfg.toolName, options.params[0]);
121
+ return new McpToolCommand(name, toolName, options.params[0]);
114
122
  };
115
123
  const invoker = defaultImperativeService.bind(getCommand);
116
124
  return (...params) => Promise.resolve(invoker(...params));
117
125
  }
118
126
  function createReadAdapter(name, cfg) {
127
+ const toolName = resolveMcpToolName(name, cfg);
119
128
  const getSubscribableCommand = (options) => {
120
129
  options.assertIsValid(options.params[0], cfg.configJsonSchema);
121
- return new McpToolSubscribableCommand(name, cfg.toolName, options.params[0]);
130
+ return new McpToolSubscribableCommand(name, toolName, options.params[0]);
122
131
  };
123
132
  switch (cfg.invokerShape) {
124
133
  case "query": {
125
134
  const getCommand = (options) => {
126
135
  options.assertIsValid(options.params[0], cfg.configJsonSchema);
127
- return new McpToolCommand(name, cfg.toolName, options.params[0]);
136
+ return new McpToolCommand(name, toolName, options.params[0]);
128
137
  };
129
138
  const invoker = queryImperativeService.bind(getCommand);
130
139
  return (...params) => Promise.resolve(invoker(...params));
@@ -146,7 +155,7 @@ function createReadAdapter(name, cfg) {
146
155
  case "legacy": {
147
156
  const getLegacyCommand = (options) => {
148
157
  options.assertIsValid(options.config, cfg.configJsonSchema);
149
- return new McpToolSubscribableCommand(name, cfg.toolName, options.config);
158
+ return new McpToolSubscribableCommand(name, toolName, options.config);
150
159
  };
151
160
  return legacyImperativeService.bind(getLegacyCommand);
152
161
  }
@@ -165,8 +174,9 @@ function unwrapWireEnvelope(payload) {
165
174
  return ok(envelope?.data);
166
175
  }
167
176
  function createWireAdapter(name, cfg) {
177
+ const toolName = resolveMcpToolName(name, cfg);
168
178
  return lwcWireBindingsService.bind(
169
- (config) => new McpToolCommand(name, cfg.toolName, config, unwrapWireEnvelope),
179
+ (config) => new McpToolCommand(name, toolName, config, unwrapWireEnvelope),
170
180
  cfg.configJsonSchema
171
181
  );
172
182
  }
@@ -199,6 +209,7 @@ async function runGraphqlQuerySafe(adapterName, toolName, config) {
199
209
  }
200
210
  }
201
211
  function createGraphQLWireAdapter(name, cfg) {
212
+ const toolName = resolveMcpToolName(name, cfg);
202
213
  return class {
203
214
  _dataCallback;
204
215
  _config;
@@ -224,7 +235,7 @@ function createGraphQLWireAdapter(name, cfg) {
224
235
  return this._fetch();
225
236
  }
226
237
  async _fetch() {
227
- this._emit(await runGraphqlQuerySafe(name, cfg.toolName, this._config ?? {}));
238
+ this._emit(await runGraphqlQuerySafe(name, toolName, this._config ?? {}));
228
239
  }
229
240
  _emit({ data, errors }) {
230
241
  this._dataCallback({
@@ -236,19 +247,21 @@ function createGraphQLWireAdapter(name, cfg) {
236
247
  };
237
248
  }
238
249
  function createGraphQLMutationAdapter(name, cfg) {
250
+ const toolName = resolveMcpToolName(name, cfg);
239
251
  return async (config) => {
240
252
  if (!config?.query) return { data: void 0, errors: [{ message: "No query provided" }] };
241
- return runGraphqlQuerySafe(name, cfg.toolName, config);
253
+ return runGraphqlQuerySafe(name, toolName, config);
242
254
  };
243
255
  }
244
256
  function createGraphQLImperativeReadAdapter(name, cfg) {
257
+ const toolName = resolveMcpToolName(name, cfg);
245
258
  if (cfg.invokerShape === "legacy") {
246
259
  async function run(config, callback) {
247
260
  if (!config?.query) {
248
261
  callback({ data: void 0, errors: void 0 });
249
262
  return;
250
263
  }
251
- const result = await runGraphqlQuerySafe(name, cfg.toolName, config);
264
+ const result = await runGraphqlQuerySafe(name, toolName, config);
252
265
  callback({
253
266
  data: result.data,
254
267
  errors: result.errors?.length ? result.errors : void 0
@@ -266,7 +279,7 @@ function createGraphQLImperativeReadAdapter(name, cfg) {
266
279
  }
267
280
  if (cfg.invokerShape === "query-refreshable") {
268
281
  return async (config) => {
269
- const result = await runGraphqlQuerySafe(name, cfg.toolName, config);
282
+ const result = await runGraphqlQuerySafe(name, toolName, config);
270
283
  if (result.errors?.length) {
271
284
  return { data: void 0, errors: result.errors };
272
285
  }
@@ -281,7 +294,7 @@ function createGraphQLImperativeReadAdapter(name, cfg) {
281
294
  };
282
295
  },
283
296
  refresh: async () => {
284
- const fresh = await runGraphqlQuerySafe(name, cfg.toolName, config);
297
+ const fresh = await runGraphqlQuerySafe(name, toolName, config);
285
298
  const payload = {
286
299
  data: fresh.data,
287
300
  errors: fresh.errors?.length ? fresh.errors : void 0
@@ -292,7 +305,7 @@ function createGraphQLImperativeReadAdapter(name, cfg) {
292
305
  };
293
306
  }
294
307
  return async (config) => {
295
- const result = await runGraphqlQuerySafe(name, cfg.toolName, config);
308
+ const result = await runGraphqlQuerySafe(name, toolName, config);
296
309
  if (result.errors?.length) {
297
310
  return { data: void 0, errors: result.errors };
298
311
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sources":["../../../src/providers/shared/normalize-mcp-response.ts","../../../src/providers/lds/runtime.ts"],"sourcesContent":["/**\n * Copyright (c) 2026, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\n\n/**\n * Unwraps the MCP tool transport envelope and returns the tool's payload as-is.\n *\n * Handles the three surface shapes `sdk.callTool()` can resolve with:\n * - MCP Apps surface: `{ structuredContent, content }`\n * - OpenAI surface: `{ result: \"<JSON string>\" }`, where the JSON may itself be\n * an MCP content array (`[{ type: 'text', text: \"<JSON string>\" }, ...]`)\n * - Fallback: the raw value returned by `callTool`\n *\n * The shape of the unwrapped payload is the tool's responsibility — this helper\n * does not project out `data` / `error` / `errors`. Callers read whichever keys\n * their tool contract defines.\n */\nexport function normalizeMcpResponse(raw: unknown): unknown {\n\tif (raw && typeof raw === \"object\" && \"structuredContent\" in raw) {\n\t\treturn (raw as { structuredContent: unknown }).structuredContent;\n\t}\n\n\tif (raw && typeof raw === \"object\" && typeof (raw as { result?: unknown }).result === \"string\") {\n\t\tconst parsed = JSON.parse((raw as { result: string }).result);\n\t\tif (Array.isArray(parsed)) {\n\t\t\tconst textBlock = parsed.find(\n\t\t\t\t(b: { type?: string; text?: string }) =>\n\t\t\t\t\tb && b.type === \"text\" && typeof b.text === \"string\",\n\t\t\t);\n\t\t\tconst text = textBlock ? textBlock.text : null;\n\t\t\tif (text) {\n\t\t\t\treturn JSON.parse(text);\n\t\t\t}\n\t\t\treturn {};\n\t\t}\n\t\treturn parsed;\n\t}\n\n\treturn raw ?? {};\n}\n","/**\n * Copyright (c) 2026, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nimport type { ResultCommand, SubscribableResultCommand } from \"@conduit-client/bindings-utils/v1\";\nimport type { assertIsValid, JSONSchema } from \"@conduit-client/jsonschema-validate\";\nimport {\n\tbuildDefaultImperativeBindingsServiceDescriptor,\n\tbuildLegacyImperativeBindingsServiceDescriptor,\n\tbuildQueryImperativeBindingsServiceDescriptor,\n\tbuildSubscribableImperativeBindingsServiceDescriptor,\n} from \"@conduit-client/service-bindings-imperative/v1\";\nimport { buildLWCWireBindingsServiceDescriptor } from \"@conduit-client/service-bindings-lwc/v1\";\nimport {\n\tbuildSubscribableResult,\n\terr,\n\tok,\n\ttoError,\n\ttype Callback,\n\ttype Result,\n\ttype Unsubscribe,\n} from \"@conduit-client/utils\";\nimport { getChatSDK } from \"@salesforce/sdk-chat\";\nimport type { ReadInvokerShape } from \"./types\";\nimport { normalizeMcpResponse } from \"../shared/normalize-mcp-response\";\n\ninterface WireAdapterConfig {\n\ttoolName: string;\n\tconfigJsonSchema: JSONSchema;\n}\n\ninterface MutationAdapterConfig {\n\ttoolName: string;\n\tconfigJsonSchema: JSONSchema;\n}\n\ninterface ReadAdapterConfig {\n\tinvokerShape: ReadInvokerShape;\n\ttoolName: string;\n\tconfigJsonSchema: JSONSchema;\n}\n\n/**\n * Optional envelope splitter. Converts the normalized MCP payload into a\n * `Result<Data, Error>` — used by the wire adapter so tools that return\n * `{ data, error }` land on OneStore's Err branch when `error` is set.\n * Imperative callers leave this unset and get the raw payload wrapped in\n * `ok(...)`.\n */\ntype UnwrapEnvelope<Data> = (payload: unknown) => Result<Data, Error>;\n\n/**\n * Resolves the MCP chat SDK and returns its `callTool` function, or throws a\n * consistent \"[adapter] sdk.callTool is not available\" error. Shared by the\n * LDS `McpToolCommand` and the graphql `runGraphqlQuery` — the check and\n * message are identical on both paths.\n */\nasync function getCallTool(\n\tadapterName: string,\n): Promise<(args: { toolName: string; params?: Record<string, unknown> }) => Promise<unknown>> {\n\tconst sdk = await getChatSDK();\n\tif (typeof sdk.callTool !== \"function\") {\n\t\tthrow new Error(\n\t\t\t`[${adapterName}] sdk.callTool is not available on this surface. ` +\n\t\t\t\t\"Make sure window.openai is configured or the component is running \" +\n\t\t\t\t\"in an MCP Apps / OpenAI chat context.\",\n\t\t);\n\t}\n\treturn sdk.callTool.bind(sdk);\n}\n\n/**\n * Pulls a human-readable message out of an MCP error response\n * (`{ isError: true, content: [{ type: 'text', text: ... }, ...] }`).\n * Returns an empty string if no text content is present so the caller can\n * supply a fallback.\n */\nfunction extractToolErrorText(raw: unknown): string {\n\tconst content = (raw as { content?: unknown }).content;\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.map((c) => {\n\t\t\tif (c && typeof c === \"object\" && (c as { type?: string }).type === \"text\") {\n\t\t\t\treturn (c as { text?: string }).text ?? \"\";\n\t\t\t}\n\t\t\treturn \"\";\n\t\t})\n\t\t.join(\" \")\n\t\t.trim();\n}\n\n/**\n * `Command` implementation that calls the configured MCP tool. One class,\n * reused across imperative and wire adapters.\n *\n * `execute()` returns a `Result<Data, unknown>`:\n * - `ok(data)` when the tool resolves — `data` is the unwrapped payload from\n * `normalizeMcpResponse` (or the result of the optional `unwrap` hook).\n * - `err(error)` when the tool rejects, when `sdk.callTool` is unavailable,\n * or when the `unwrap` hook returns `err(...)`.\n *\n * OneStore's `DefaultImperativeBindingsService` wraps this: on `ok(v)` it\n * deep-freezes and returns `v`; on `err(e)` it re-throws via `toError`. Sync\n * throws from `assertIsValid` in the `getCommand` factory are funneled through\n * `throwUserlandError`. `LWCWireBindingsService` wraps the same command\n * differently — it emits `{ data, error }` to the wire callback and attaches\n * freeze / race-guard / incomplete-config behavior.\n */\nclass McpToolCommand<Data> implements ResultCommand<Data, Error> {\n\tconstructor(\n\t\tprivate readonly adapterName: string,\n\t\tprivate readonly toolName: string,\n\t\tprivate readonly params: unknown,\n\t\tprivate readonly unwrap?: UnwrapEnvelope<Data>,\n\t) {}\n\n\tasync execute(): Promise<Result<Data, Error>> {\n\t\ttry {\n\t\t\tconst callTool = await getCallTool(this.adapterName);\n\t\t\tconst raw = await callTool({\n\t\t\t\ttoolName: this.toolName,\n\t\t\t\tparams: (this.params as Record<string, unknown>) ?? undefined,\n\t\t\t});\n\t\t\t// The MCP SDK converts handler throws into a resolved tool response\n\t\t\t// with `{ isError: true, content: [...] }` — not a transport\n\t\t\t// rejection. Surface it as an Err here so the default invoker\n\t\t\t// re-throws and the wire/legacy adapters route it through their\n\t\t\t// error channel.\n\t\t\tif (raw && typeof raw === \"object\" && (raw as { isError?: boolean }).isError) {\n\t\t\t\treturn err(new Error(extractToolErrorText(raw) || \"MCP tool error\"));\n\t\t\t}\n\t\t\tconst payload = normalizeMcpResponse(raw);\n\t\t\treturn this.unwrap ? this.unwrap(payload) : ok(payload as Data);\n\t\t} catch (e) {\n\t\t\treturn err(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n}\n\n// Off-platform has no store to observe. For shapes that have no `refresh`,\n// nothing can ever trigger a post-initial update, so `subscribe` is a\n// deliberate no-op: the callback never fires and the returned unsubscribe is\n// idempotent. Shapes that *do* expose `refresh` wire subscribers into the\n// refresh path instead (see `McpToolSubscribableCommand` and the\n// `query-refreshable` graphql shape).\nconst noopUnsubscribe: Unsubscribe = () => {\n\t// no store to unsubscribe from off-platform\n};\nconst noopSubscribe = (_cb: unknown): Unsubscribe => noopUnsubscribe;\n\n/**\n * Adapts `McpToolCommand` into a `SubscribableResultCommand`. Wraps the\n * command's `Result` with `buildSubscribableResult`, supplying:\n * - `subscribe`: per-execution subscriber set. Each `execute()` call has\n * its own set so sibling invocations don't cross-pollinate. Returned\n * unsubscribe removes the callback and is idempotent.\n * - `refresh`: builds a fresh `McpToolCommand`, re-executes it, and\n * broadcasts the fresh `Result` to every registered subscriber before\n * resolving. Returns `Result<void, Error>` (ok → undefined; err → the\n * error from the fresh execute).\n *\n * Wiring subscribers into refresh mirrors on-platform behavior, where the\n * reactive store fans `refresh` results out to every listener. Off-platform\n * there is no store, so the subscriber set lives on the command itself. This\n * shim is what lets OneStore's Subscribable and Legacy services run verbatim\n * against MCP: their invokers gate on `isSubscribableResult`, which requires\n * the command's `execute()` to resolve a `SubscribableResult` (not a plain\n * `Result`).\n */\nclass McpToolSubscribableCommand<Data> implements SubscribableResultCommand<Data, Error> {\n\tconstructor(\n\t\tprivate readonly adapterName: string,\n\t\tprivate readonly toolName: string,\n\t\tprivate readonly params: unknown,\n\t\tprivate readonly unwrap?: UnwrapEnvelope<Data>,\n\t) {}\n\n\tasync execute() {\n\t\tconst base = new McpToolCommand<Data>(\n\t\t\tthis.adapterName,\n\t\t\tthis.toolName,\n\t\t\tthis.params,\n\t\t\tthis.unwrap,\n\t\t);\n\t\tconst result = await base.execute();\n\t\tconst subscribers = new Set<Callback<Result<Data, Error>>>();\n\t\tconst subscribe = (cb: Callback<Result<Data, Error>>): Unsubscribe => {\n\t\t\tsubscribers.add(cb);\n\t\t\treturn () => {\n\t\t\t\tsubscribers.delete(cb);\n\t\t\t};\n\t\t};\n\t\tconst refresh = async () => {\n\t\t\tconst next = await new McpToolCommand<Data>(\n\t\t\t\tthis.adapterName,\n\t\t\t\tthis.toolName,\n\t\t\t\tthis.params,\n\t\t\t\tthis.unwrap,\n\t\t\t).execute();\n\t\t\tsubscribers.forEach((cb) => cb(next));\n\t\t\treturn next.isOk() ? ok<void, Error>(undefined) : err(next.error);\n\t\t};\n\t\treturn buildSubscribableResult(result, subscribe, refresh);\n\t}\n}\n\nconst defaultImperativeService = buildDefaultImperativeBindingsServiceDescriptor().service;\nconst queryImperativeService = buildQueryImperativeBindingsServiceDescriptor().service;\nconst subscribableImperativeService =\n\tbuildSubscribableImperativeBindingsServiceDescriptor().service;\nconst legacyImperativeService = buildLegacyImperativeBindingsServiceDescriptor().service;\n\n/**\n * Mutation-shape factory. Builds an async `(config) => Promise<Data>` via\n * OneStore's `DefaultImperativeBindingsService`. Throws on validation error\n * (`throwUserlandError`) or tool error (`toError`). This is the only shape a\n * mutation ever takes on platform — mutation adapters do not carry an\n * `invokerShape` at all.\n */\nexport function createMutationAdapter(name: string, cfg: MutationAdapterConfig) {\n\tconst getCommand = (options: { params: unknown[]; assertIsValid: typeof assertIsValid }) => {\n\t\toptions.assertIsValid(options.params[0], cfg.configJsonSchema);\n\t\treturn new McpToolCommand<unknown>(name, cfg.toolName, options.params[0]);\n\t};\n\tconst invoker = defaultImperativeService.bind<unknown[], unknown>(getCommand);\n\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n}\n\n/**\n * Read-shape factory. Dispatches on `cfg.invokerShape`:\n *\n * - `legacy` — `{ invoke, subscribe }` callback surface with `{ data, error }`.\n * `subscribe` fires the callback once from the initial execute's `data`,\n * returns a no-op unsubscribe, and never fires again off-platform.\n * - `query` — `(config) => Promise<{ data }>`; one-shot read.\n * - `subscribable` — `(config) => Promise<{ data, subscribe }>`. Callback\n * passed to `subscribe` never fires; unsubscribe is a no-op.\n * - `subscribable-refreshable` — `(config) => Promise<{ data, subscribe, refresh }>`.\n * `refresh()` re-executes the MCP tool; `subscribe` is still a no-op.\n *\n * All four delegate to an OneStore service (Query / Subscribable / Legacy)\n * over `McpToolSubscribableCommand`, which preserves OneStore's deep-freeze\n * and error-funnel semantics end-to-end.\n */\nexport function createReadAdapter(name: string, cfg: ReadAdapterConfig) {\n\tconst getSubscribableCommand = (options: {\n\t\tparams: unknown[];\n\t\tassertIsValid: typeof assertIsValid;\n\t}) => {\n\t\toptions.assertIsValid(options.params[0], cfg.configJsonSchema);\n\t\treturn new McpToolSubscribableCommand<unknown>(name, cfg.toolName, options.params[0]);\n\t};\n\n\tswitch (cfg.invokerShape) {\n\t\tcase \"query\": {\n\t\t\tconst getCommand = (options: { params: unknown[]; assertIsValid: typeof assertIsValid }) => {\n\t\t\t\toptions.assertIsValid(options.params[0], cfg.configJsonSchema);\n\t\t\t\treturn new McpToolCommand<unknown>(name, cfg.toolName, options.params[0]);\n\t\t\t};\n\t\t\tconst invoker = queryImperativeService.bind<unknown[], unknown>(getCommand);\n\t\t\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n\t\t}\n\t\tcase \"subscribable\": {\n\t\t\tconst invoker = subscribableImperativeService.bind<unknown[], unknown>(\n\t\t\t\tgetSubscribableCommand,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n\t\t}\n\t\tcase \"subscribable-refreshable\": {\n\t\t\tconst invoker = subscribableImperativeService.bind<unknown[], unknown>(\n\t\t\t\tgetSubscribableCommand,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n\t\t}\n\t\tcase \"legacy\": {\n\t\t\t// Legacy service passes `{ config, assertIsValid }`, not `{ params, ... }`.\n\t\t\tconst getLegacyCommand = (options: {\n\t\t\t\tconfig: unknown;\n\t\t\t\tassertIsValid: typeof assertIsValid;\n\t\t\t}) => {\n\t\t\t\toptions.assertIsValid(options.config, cfg.configJsonSchema);\n\t\t\t\treturn new McpToolSubscribableCommand<unknown>(name, cfg.toolName, options.config);\n\t\t\t};\n\t\t\treturn legacyImperativeService.bind<unknown, unknown>(getLegacyCommand);\n\t\t}\n\t\tdefault:\n\t\t\tthrow new Error(\n\t\t\t\t`[${name}] unsupported invokerShape: ${String((cfg as { invokerShape: unknown }).invokerShape)}. ` +\n\t\t\t\t\t`Expected 'legacy' | 'query' | 'subscribable' | 'subscribable-refreshable'.`,\n\t\t\t);\n\t}\n}\n\nconst lwcWireBindingsService = buildLWCWireBindingsServiceDescriptor().service;\n\n/**\n * Splits the MCP tool's `{ data, error }` envelope into a `Result`. Used as\n * the `unwrap` hook on `McpToolCommand` so OneStore's wire invoker sees the\n * error branch directly instead of receiving an envelope wrapped in `ok(...)`.\n *\n * Tools that don't emit the envelope (e.g. imperative) never go through this\n * path — the default imperative invoker doesn't pass `unwrap`.\n */\nfunction unwrapWireEnvelope<Data>(payload: unknown): Result<Data, Error> {\n\tconst envelope = payload as { data?: unknown; error?: unknown } | null | undefined;\n\tif (envelope && envelope.error !== undefined && envelope.error !== null) {\n\t\treturn err(toError(envelope.error));\n\t}\n\treturn ok(envelope?.data as Data);\n}\n\n/**\n * Creates an LWC wire adapter class that calls an MCP tool. Delegates to\n * OneStore's `LWCWireBindingsService`, so the returned class inherits the\n * full `CommandWireAdapterConstructor` contract: initial empty emit, config\n * `sanitize()`, `MissingRequiredPropertyError` → wait-for-next-config gating,\n * deep-freeze on success, race guard on stale resolves, and unsubscriber\n * management on disconnect.\n *\n * The `McpToolCommand` class is reused verbatim — the wire call-site only\n * supplies an `unwrap` hook so the tool's `{ data, error }` envelope lands\n * on OneStore's Err branch rather than being leaked through as an `ok(...)`\n * envelope.\n *\n * @param name - Wire adapter export name, used in MCP error messages.\n * @param cfg - MCP tool name and JSON Schema for valid wire configs.\n */\nexport function createWireAdapter(name: string, cfg: WireAdapterConfig) {\n\treturn lwcWireBindingsService.bind<unknown>(\n\t\t(config) => new McpToolCommand(name, cfg.toolName, config, unwrapWireEnvelope),\n\t\tcfg.configJsonSchema,\n\t);\n}\n\n// ─── GraphQL adapters ─────────────────────────────────────────────────────────\n\n/**\n * GraphQL adapters diverge from the base wire / mutation shapes in two ways:\n *\n * 1. Envelope is `{ data, errors[] }` instead of `{ data, error }`. Errors\n * are collected; an empty array collapses to `undefined`.\n * 2. The `_fetch` path routes thrown errors **into** the `errors[]`\n * envelope on the wire callback (never throws to the LWC host). Mutation\n * likewise resolves with `{ data, errors }` rather than rejecting.\n *\n * Dispatch is MCP-only: `getChatSDK().callTool({ toolName, params })` with\n * `normalizeMcpResponse` unwrapping. No `globalThis.__sfdc_sdk__` shortcut —\n * the on-platform behaviour is already covered by real `lightning/graphql`,\n * and every off-platform caller routes through an MCP tool like every other\n * LDS adapter.\n */\ninterface GraphqlAdapterConfig {\n\ttoolName: string;\n}\n\ninterface GraphqlConfig {\n\tquery?: string;\n\tvariables?: Record<string, unknown>;\n}\n\ninterface GraphqlResult {\n\tdata?: unknown;\n\terrors?: { message: string }[];\n}\n\ntype GraphqlWireCallback = (result: {\n\tdata: unknown;\n\terrors: { message: string }[] | undefined;\n\trefresh: () => Promise<void>;\n}) => void;\n\n/**\n * Template-literal tag that stitches the string into a plain `query` string.\n * Deliberately minimal — no AST parsing, no fragment substitution, no opaque\n * doc emulation. Matches the shape used by today's off-platform `gql`.\n */\nexport function gql(strings: TemplateStringsArray, ...values: unknown[]): string {\n\tlet result = \"\";\n\tstrings.forEach((string, i) => {\n\t\tresult += string;\n\t\tif (i < values.length) result += String(values[i]);\n\t});\n\treturn result.trim();\n}\n\nasync function runGraphqlQuery(\n\tadapterName: string,\n\ttoolName: string,\n\tconfig: GraphqlConfig,\n): Promise<GraphqlResult> {\n\tconst { query, variables } = config;\n\tif (!query) return { data: undefined, errors: undefined };\n\n\tconst callTool = await getCallTool(adapterName);\n\tconst raw = await callTool({\n\t\ttoolName,\n\t\tparams: { query, variables: variables ?? {} },\n\t});\n\n\treturn (normalizeMcpResponse(raw) as GraphqlResult) ?? {};\n}\n\n/** Wraps a thrown Error into the graphql `{ data, errors[] }` envelope. */\nfunction toGraphqlErrorResult(error: unknown): GraphqlResult {\n\treturn { data: undefined, errors: [{ message: (error as Error).message }] };\n}\n\n/**\n * `runGraphqlQuery` wrapped in try/catch so thrown errors land on `errors[]`\n * instead of rejecting. Used by every graphql shape that routes errors\n * in-band (wire, mutation, imperative-read query/query-refreshable, legacy).\n */\nasync function runGraphqlQuerySafe(\n\tadapterName: string,\n\ttoolName: string,\n\tconfig: GraphqlConfig,\n): Promise<GraphqlResult> {\n\ttry {\n\t\treturn await runGraphqlQuery(adapterName, toolName, config);\n\t} catch (error) {\n\t\treturn toGraphqlErrorResult(error);\n\t}\n}\n\n/**\n * GraphQL wire adapter factory. Emits `{ data, errors, refresh }` to the wire\n * callback. Mirrors the `constructor(callback)` → `connect` / `disconnect` /\n * `update(config)` / `refresh()` contract used by the LWC wire service.\n * Thrown fetch errors are routed into `errors[0].message`.\n *\n * `_fetch` is gated on `_connected` so that the common wire lifecycle\n * (`constructor` → `update(config)` → `connect`) doesn't fire two requests:\n * the initial `update(config)` arrives before `connect()`, stores the config,\n * and waits. `connect()` does the one fetch; later `update(config)` while\n * connected re-fetches. This matches luvio's `LWCLuvioWireAdapter`, which\n * gates on the same flag to prevent duplicate endpoint calls.\n */\nexport function createGraphQLWireAdapter(name: string, cfg: GraphqlAdapterConfig) {\n\treturn class {\n\t\t_dataCallback: GraphqlWireCallback;\n\t\t_config: GraphqlConfig | undefined;\n\t\t_connected = false;\n\n\t\tconstructor(dataCallback: GraphqlWireCallback) {\n\t\t\tthis._dataCallback = dataCallback;\n\t\t}\n\n\t\tconnect() {\n\t\t\tthis._connected = true;\n\t\t\tvoid this._fetch();\n\t\t}\n\n\t\tdisconnect() {\n\t\t\tthis._connected = false;\n\t\t}\n\n\t\tupdate(config: GraphqlConfig | undefined) {\n\t\t\tthis._config = config;\n\n\t\t\tif (!this._connected || this._config === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvoid this._fetch();\n\t\t}\n\n\t\trefresh() {\n\t\t\treturn this._fetch();\n\t\t}\n\n\t\tasync _fetch() {\n\t\t\tthis._emit(await runGraphqlQuerySafe(name, cfg.toolName, this._config ?? {}));\n\t\t}\n\n\t\t_emit({ data, errors }: GraphqlResult) {\n\t\t\tthis._dataCallback({\n\t\t\t\tdata,\n\t\t\t\terrors: errors?.length ? errors : undefined,\n\t\t\t\trefresh: () => this.refresh(),\n\t\t\t});\n\t\t}\n\t};\n}\n\n/**\n * GraphQL mutation factory. Returns `async (config) => Promise<{ data, errors }>`.\n * Empty-query guard short-circuits with\n * `{ data: undefined, errors: [{ message: \"No query provided\" }] }`.\n * All other errors are routed in-band to the `errors[]` envelope — the\n * function never rejects.\n */\nexport function createGraphQLMutationAdapter(name: string, cfg: GraphqlAdapterConfig) {\n\treturn async (config: GraphqlConfig): Promise<GraphqlResult> => {\n\t\tif (!config?.query) return { data: undefined, errors: [{ message: \"No query provided\" }] };\n\t\treturn runGraphqlQuerySafe(name, cfg.toolName, config);\n\t};\n}\n\ntype GraphqlImperativeReadInvokerShape = \"query\" | \"query-refreshable\" | \"legacy\";\n\ninterface GraphqlImperativeReadAdapterConfig extends GraphqlAdapterConfig {\n\tinvokerShape: GraphqlImperativeReadInvokerShape;\n}\n\ntype GraphqlImperativeResult = GraphqlResult & {\n\tsubscribe?: (cb: (result: GraphqlResult) => void) => Unsubscribe;\n\trefresh?: () => Promise<void>;\n};\n\ntype LegacyGraphqlCallback = (result: GraphqlResult) => void;\n\n/**\n * Imperative GraphQL read factory — single entry point for all imperative\n * graphql read shapes, mirroring the LDS `createReadAdapter` pattern. The\n * `invokerShape` selects the return surface:\n *\n * - `query` — `async (config) => Promise<{ data, errors, subscribe }>`.\n * Mirrors on-platform `GraphQLImperativeBindingsService` without\n * `exposeRefresh`. Errors are routed in-band; the function never throws.\n * - `query-refreshable` — same as `query` plus `refresh()` that re-runs the\n * underlying MCP tool. Mirrors the same service with `exposeRefresh: true`.\n * - `legacy` — `{ invoke(config, context, callback),\n * subscribe(config, context, callback): Unsubscribe }`. The callback\n * always receives `{ data, errors }`; neither method throws. `context` is\n * accepted but ignored.\n *\n * In every shape `subscribe` is a deliberate no-op off-platform (no reactive\n * store); returned unsubscribes are idempotent.\n */\nexport function createGraphQLImperativeReadAdapter(\n\tname: string,\n\tcfg: GraphqlImperativeReadAdapterConfig,\n) {\n\tif (cfg.invokerShape === \"legacy\") {\n\t\tasync function run(\n\t\t\tconfig: GraphqlConfig | undefined,\n\t\t\tcallback: LegacyGraphqlCallback,\n\t\t): Promise<void> {\n\t\t\tif (!config?.query) {\n\t\t\t\tcallback({ data: undefined, errors: undefined });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await runGraphqlQuerySafe(name, cfg.toolName, config);\n\t\t\tcallback({\n\t\t\t\tdata: result.data,\n\t\t\t\terrors: result.errors?.length ? result.errors : undefined,\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tinvoke(\n\t\t\t\tconfig: GraphqlConfig | undefined,\n\t\t\t\t_context: unknown,\n\t\t\t\tcallback: LegacyGraphqlCallback,\n\t\t\t): void {\n\t\t\t\tvoid run(config, callback);\n\t\t\t},\n\t\t\tsubscribe(\n\t\t\t\tconfig: GraphqlConfig | undefined,\n\t\t\t\t_context: unknown,\n\t\t\t\tcallback: LegacyGraphqlCallback,\n\t\t\t): Unsubscribe {\n\t\t\t\tvoid run(config, callback);\n\t\t\t\treturn noopUnsubscribe;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (cfg.invokerShape === \"query-refreshable\") {\n\t\t// Per-invocation subscriber set: each call to the returned function\n\t\t// gets its own adapter instance with an isolated subscriber list.\n\t\t// `refresh()` re-runs the MCP tool and broadcasts the fresh\n\t\t// `{ data, errors }` to every registered callback, which mirrors the\n\t\t// on-platform contract where `refresh` causes store updates that fan\n\t\t// out through the `subscribe` fan-in. Without this wiring, `refresh`\n\t\t// would re-run the query off-platform but nothing could observe the\n\t\t// new payload (no store, noop subscribe).\n\t\treturn async (config: GraphqlConfig): Promise<GraphqlImperativeResult> => {\n\t\t\tconst result = await runGraphqlQuerySafe(name, cfg.toolName, config);\n\t\t\tif (result.errors?.length) {\n\t\t\t\treturn { data: undefined, errors: result.errors };\n\t\t\t}\n\t\t\tconst subscribers = new Set<(result: GraphqlResult) => void>();\n\t\t\treturn {\n\t\t\t\tdata: result.data,\n\t\t\t\terrors: undefined,\n\t\t\t\tsubscribe: (cb) => {\n\t\t\t\t\tsubscribers.add(cb);\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tsubscribers.delete(cb);\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\trefresh: async () => {\n\t\t\t\t\tconst fresh = await runGraphqlQuerySafe(name, cfg.toolName, config);\n\t\t\t\t\tconst payload: GraphqlResult = {\n\t\t\t\t\t\tdata: fresh.data,\n\t\t\t\t\t\terrors: fresh.errors?.length ? fresh.errors : undefined,\n\t\t\t\t\t};\n\t\t\t\t\tsubscribers.forEach((cb) => cb(payload));\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\t}\n\n\t// `query` shape: no refresh → nothing can trigger a post-initial update\n\t// off-platform, so `subscribe` stays a noop. The on-platform contract\n\t// allows subscribe callbacks to fire from unrelated store writes; off-\n\t// platform there is no store, so the callback is correctly unreachable.\n\treturn async (config: GraphqlConfig): Promise<GraphqlImperativeResult> => {\n\t\tconst result = await runGraphqlQuerySafe(name, cfg.toolName, config);\n\t\tif (result.errors?.length) {\n\t\t\treturn { data: undefined, errors: result.errors };\n\t\t}\n\t\treturn {\n\t\t\tdata: result.data,\n\t\t\terrors: undefined,\n\t\t\tsubscribe: noopSubscribe,\n\t\t};\n\t};\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","sources":["../../../src/providers/shared/normalize-mcp-response.ts","../../../src/providers/lds/runtime.ts"],"sourcesContent":["/**\n * Copyright (c) 2026, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\n\n/**\n * Unwraps the MCP tool transport envelope and returns the tool's payload as-is.\n *\n * Handles the three surface shapes `sdk.callTool()` can resolve with:\n * - MCP Apps surface: `{ structuredContent, content }`\n * - OpenAI surface: `{ result: \"<JSON string>\" }`, where the JSON may itself be\n * an MCP content array (`[{ type: 'text', text: \"<JSON string>\" }, ...]`)\n * - Fallback: the raw value returned by `callTool`\n *\n * The shape of the unwrapped payload is the tool's responsibility — this helper\n * does not project out `data` / `error` / `errors`. Callers read whichever keys\n * their tool contract defines.\n */\nexport function normalizeMcpResponse(raw: unknown): unknown {\n\tif (raw && typeof raw === \"object\" && \"structuredContent\" in raw) {\n\t\treturn (raw as { structuredContent: unknown }).structuredContent;\n\t}\n\n\tif (raw && typeof raw === \"object\" && typeof (raw as { result?: unknown }).result === \"string\") {\n\t\tconst parsed = JSON.parse((raw as { result: string }).result);\n\t\tif (Array.isArray(parsed)) {\n\t\t\tconst textBlock = parsed.find(\n\t\t\t\t(b: { type?: string; text?: string }) =>\n\t\t\t\t\tb && b.type === \"text\" && typeof b.text === \"string\",\n\t\t\t);\n\t\t\tconst text = textBlock ? textBlock.text : null;\n\t\t\tif (text) {\n\t\t\t\treturn JSON.parse(text);\n\t\t\t}\n\t\t\treturn {};\n\t\t}\n\t\treturn parsed;\n\t}\n\n\treturn raw ?? {};\n}\n","/**\n * Copyright (c) 2026, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nimport type { ResultCommand, SubscribableResultCommand } from \"@conduit-client/bindings-utils/v1\";\nimport type { assertIsValid, JSONSchema } from \"@conduit-client/jsonschema-validate\";\nimport {\n\tbuildDefaultImperativeBindingsServiceDescriptor,\n\tbuildLegacyImperativeBindingsServiceDescriptor,\n\tbuildQueryImperativeBindingsServiceDescriptor,\n\tbuildSubscribableImperativeBindingsServiceDescriptor,\n} from \"@conduit-client/service-bindings-imperative/v1\";\nimport { buildLWCWireBindingsServiceDescriptor } from \"@conduit-client/service-bindings-lwc/v1\";\nimport {\n\tbuildSubscribableResult,\n\terr,\n\tok,\n\ttoError,\n\ttype Callback,\n\ttype Result,\n\ttype Unsubscribe,\n} from \"@conduit-client/utils\";\nimport { getChatSDK } from \"@salesforce/platform-sdk-chat\";\nimport type { ReadInvokerShape } from \"./types\";\nimport { normalizeMcpResponse } from \"../shared/normalize-mcp-response\";\n\n/**\n * Runtime mirror of the public `LdsAdapterConfigBase` — adapters dispatch\n * through `cfg.mcp?.toolName`. Kept nominal-free so the virtual module can\n * cheaply deserialize the JSON-stringified config written by the load hook.\n */\ninterface McpBackedAdapterConfig {\n\tmcp?: { toolName: string };\n}\n\n/**\n * LDS adapter configs whose input is validated against a JSON Schema at\n * invoke time. Wire, mutation, and read factories all consume this shape;\n * graphql factories skip the schema layer entirely.\n */\ninterface SchemaValidatedAdapterConfig extends McpBackedAdapterConfig {\n\tconfigJsonSchema: JSONSchema;\n}\n\ntype WireAdapterConfig = SchemaValidatedAdapterConfig;\n\ntype MutationAdapterConfig = SchemaValidatedAdapterConfig;\n\ninterface ReadAdapterConfig extends SchemaValidatedAdapterConfig {\n\tinvokerShape: ReadInvokerShape;\n}\n\n/**\n * Resolves the MCP tool name for an adapter config, or throws if none of the\n * supported backings are set. Today only `mcp` is wired up; future backings\n * (e.g. `http`) will be resolved in the same choke point.\n */\nfunction resolveMcpToolName(adapterName: string, cfg: McpBackedAdapterConfig): string {\n\tconst toolName = cfg.mcp?.toolName;\n\tif (!toolName) {\n\t\tthrow new Error(`[${adapterName}] no dispatch backing configured — expected \\`mcp.toolName\\`.`);\n\t}\n\treturn toolName;\n}\n\n/**\n * Optional envelope splitter. Converts the normalized MCP payload into a\n * `Result<Data, Error>` — used by the wire adapter so tools that return\n * `{ data, error }` land on OneStore's Err branch when `error` is set.\n * Imperative callers leave this unset and get the raw payload wrapped in\n * `ok(...)`.\n */\ntype UnwrapEnvelope<Data> = (payload: unknown) => Result<Data, Error>;\n\n/**\n * Resolves the MCP chat SDK and returns its `callTool` function, or throws a\n * consistent \"[adapter] sdk.callTool is not available\" error. Shared by the\n * LDS `McpToolCommand` and the graphql `runGraphqlQuery` — the check and\n * message are identical on both paths.\n */\nasync function getCallTool(\n\tadapterName: string,\n): Promise<(args: { toolName: string; params?: Record<string, unknown> }) => Promise<unknown>> {\n\tconst sdk = await getChatSDK();\n\tif (typeof sdk.callTool !== \"function\") {\n\t\tthrow new Error(\n\t\t\t`[${adapterName}] sdk.callTool is not available on this surface. ` +\n\t\t\t\t\"Make sure window.openai is configured or the component is running \" +\n\t\t\t\t\"in an MCP Apps / OpenAI chat context.\",\n\t\t);\n\t}\n\treturn sdk.callTool.bind(sdk);\n}\n\n/**\n * Pulls a human-readable message out of an MCP error response\n * (`{ isError: true, content: [{ type: 'text', text: ... }, ...] }`).\n * Returns an empty string if no text content is present so the caller can\n * supply a fallback.\n */\nfunction extractToolErrorText(raw: unknown): string {\n\tconst content = (raw as { content?: unknown }).content;\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.map((c) => {\n\t\t\tif (c && typeof c === \"object\" && (c as { type?: string }).type === \"text\") {\n\t\t\t\treturn (c as { text?: string }).text ?? \"\";\n\t\t\t}\n\t\t\treturn \"\";\n\t\t})\n\t\t.join(\" \")\n\t\t.trim();\n}\n\n/**\n * `Command` implementation that calls the configured MCP tool. One class,\n * reused across imperative and wire adapters.\n *\n * `execute()` returns a `Result<Data, unknown>`:\n * - `ok(data)` when the tool resolves — `data` is the unwrapped payload from\n * `normalizeMcpResponse` (or the result of the optional `unwrap` hook).\n * - `err(error)` when the tool rejects, when `sdk.callTool` is unavailable,\n * or when the `unwrap` hook returns `err(...)`.\n *\n * OneStore's `DefaultImperativeBindingsService` wraps this: on `ok(v)` it\n * deep-freezes and returns `v`; on `err(e)` it re-throws via `toError`. Sync\n * throws from `assertIsValid` in the `getCommand` factory are funneled through\n * `throwUserlandError`. `LWCWireBindingsService` wraps the same command\n * differently — it emits `{ data, error }` to the wire callback and attaches\n * freeze / race-guard / incomplete-config behavior.\n */\nclass McpToolCommand<Data> implements ResultCommand<Data, Error> {\n\tconstructor(\n\t\tprivate readonly adapterName: string,\n\t\tprivate readonly toolName: string,\n\t\tprivate readonly params: unknown,\n\t\tprivate readonly unwrap?: UnwrapEnvelope<Data>,\n\t) {}\n\n\tasync execute(): Promise<Result<Data, Error>> {\n\t\ttry {\n\t\t\tconst callTool = await getCallTool(this.adapterName);\n\t\t\tconst raw = await callTool({\n\t\t\t\ttoolName: this.toolName,\n\t\t\t\tparams: (this.params as Record<string, unknown>) ?? undefined,\n\t\t\t});\n\t\t\t// The MCP SDK converts handler throws into a resolved tool response\n\t\t\t// with `{ isError: true, content: [...] }` — not a transport\n\t\t\t// rejection. Surface it as an Err here so the default invoker\n\t\t\t// re-throws and the wire/legacy adapters route it through their\n\t\t\t// error channel.\n\t\t\tif (raw && typeof raw === \"object\" && (raw as { isError?: boolean }).isError) {\n\t\t\t\treturn err(new Error(extractToolErrorText(raw) || \"MCP tool error\"));\n\t\t\t}\n\t\t\tconst payload = normalizeMcpResponse(raw);\n\t\t\treturn this.unwrap ? this.unwrap(payload) : ok(payload as Data);\n\t\t} catch (e) {\n\t\t\treturn err(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n}\n\n// Off-platform has no store to observe. For shapes that have no `refresh`,\n// nothing can ever trigger a post-initial update, so `subscribe` is a\n// deliberate no-op: the callback never fires and the returned unsubscribe is\n// idempotent. Shapes that *do* expose `refresh` wire subscribers into the\n// refresh path instead (see `McpToolSubscribableCommand` and the\n// `query-refreshable` graphql shape).\nconst noopUnsubscribe: Unsubscribe = () => {\n\t// no store to unsubscribe from off-platform\n};\nconst noopSubscribe = (_cb: unknown): Unsubscribe => noopUnsubscribe;\n\n/**\n * Adapts `McpToolCommand` into a `SubscribableResultCommand`. Wraps the\n * command's `Result` with `buildSubscribableResult`, supplying:\n * - `subscribe`: per-execution subscriber set. Each `execute()` call has\n * its own set so sibling invocations don't cross-pollinate. Returned\n * unsubscribe removes the callback and is idempotent.\n * - `refresh`: builds a fresh `McpToolCommand`, re-executes it, and\n * broadcasts the fresh `Result` to every registered subscriber before\n * resolving. Returns `Result<void, Error>` (ok → undefined; err → the\n * error from the fresh execute).\n *\n * Wiring subscribers into refresh mirrors on-platform behavior, where the\n * reactive store fans `refresh` results out to every listener. Off-platform\n * there is no store, so the subscriber set lives on the command itself. This\n * shim is what lets OneStore's Subscribable and Legacy services run verbatim\n * against MCP: their invokers gate on `isSubscribableResult`, which requires\n * the command's `execute()` to resolve a `SubscribableResult` (not a plain\n * `Result`).\n */\nclass McpToolSubscribableCommand<Data> implements SubscribableResultCommand<Data, Error> {\n\tconstructor(\n\t\tprivate readonly adapterName: string,\n\t\tprivate readonly toolName: string,\n\t\tprivate readonly params: unknown,\n\t\tprivate readonly unwrap?: UnwrapEnvelope<Data>,\n\t) {}\n\n\tasync execute() {\n\t\tconst base = new McpToolCommand<Data>(\n\t\t\tthis.adapterName,\n\t\t\tthis.toolName,\n\t\t\tthis.params,\n\t\t\tthis.unwrap,\n\t\t);\n\t\tconst result = await base.execute();\n\t\tconst subscribers = new Set<Callback<Result<Data, Error>>>();\n\t\tconst subscribe = (cb: Callback<Result<Data, Error>>): Unsubscribe => {\n\t\t\tsubscribers.add(cb);\n\t\t\treturn () => {\n\t\t\t\tsubscribers.delete(cb);\n\t\t\t};\n\t\t};\n\t\tconst refresh = async () => {\n\t\t\tconst next = await new McpToolCommand<Data>(\n\t\t\t\tthis.adapterName,\n\t\t\t\tthis.toolName,\n\t\t\t\tthis.params,\n\t\t\t\tthis.unwrap,\n\t\t\t).execute();\n\t\t\tsubscribers.forEach((cb) => cb(next));\n\t\t\treturn next.isOk() ? ok<void, Error>(undefined) : err(next.error);\n\t\t};\n\t\treturn buildSubscribableResult(result, subscribe, refresh);\n\t}\n}\n\nconst defaultImperativeService = buildDefaultImperativeBindingsServiceDescriptor().service;\nconst queryImperativeService = buildQueryImperativeBindingsServiceDescriptor().service;\nconst subscribableImperativeService =\n\tbuildSubscribableImperativeBindingsServiceDescriptor().service;\nconst legacyImperativeService = buildLegacyImperativeBindingsServiceDescriptor().service;\n\n/**\n * Mutation-shape factory. Builds an async `(config) => Promise<Data>` via\n * OneStore's `DefaultImperativeBindingsService`. Throws on validation error\n * (`throwUserlandError`) or tool error (`toError`). This is the only shape a\n * mutation ever takes on platform — mutation adapters do not carry an\n * `invokerShape` at all.\n */\nexport function createMutationAdapter(name: string, cfg: MutationAdapterConfig) {\n\tconst toolName = resolveMcpToolName(name, cfg);\n\tconst getCommand = (options: { params: unknown[]; assertIsValid: typeof assertIsValid }) => {\n\t\toptions.assertIsValid(options.params[0], cfg.configJsonSchema);\n\t\treturn new McpToolCommand<unknown>(name, toolName, options.params[0]);\n\t};\n\tconst invoker = defaultImperativeService.bind<unknown[], unknown>(getCommand);\n\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n}\n\n/**\n * Read-shape factory. Dispatches on `cfg.invokerShape`:\n *\n * - `legacy` — `{ invoke, subscribe }` callback surface with `{ data, error }`.\n * `subscribe` fires the callback once from the initial execute's `data`,\n * returns a no-op unsubscribe, and never fires again off-platform.\n * - `query` — `(config) => Promise<{ data }>`; one-shot read.\n * - `subscribable` — `(config) => Promise<{ data, subscribe }>`. Callback\n * passed to `subscribe` never fires; unsubscribe is a no-op.\n * - `subscribable-refreshable` — `(config) => Promise<{ data, subscribe, refresh }>`.\n * `refresh()` re-executes the MCP tool; `subscribe` is still a no-op.\n *\n * All four delegate to an OneStore service (Query / Subscribable / Legacy)\n * over `McpToolSubscribableCommand`, which preserves OneStore's deep-freeze\n * and error-funnel semantics end-to-end.\n */\nexport function createReadAdapter(name: string, cfg: ReadAdapterConfig) {\n\tconst toolName = resolveMcpToolName(name, cfg);\n\tconst getSubscribableCommand = (options: {\n\t\tparams: unknown[];\n\t\tassertIsValid: typeof assertIsValid;\n\t}) => {\n\t\toptions.assertIsValid(options.params[0], cfg.configJsonSchema);\n\t\treturn new McpToolSubscribableCommand<unknown>(name, toolName, options.params[0]);\n\t};\n\n\tswitch (cfg.invokerShape) {\n\t\tcase \"query\": {\n\t\t\tconst getCommand = (options: { params: unknown[]; assertIsValid: typeof assertIsValid }) => {\n\t\t\t\toptions.assertIsValid(options.params[0], cfg.configJsonSchema);\n\t\t\t\treturn new McpToolCommand<unknown>(name, toolName, options.params[0]);\n\t\t\t};\n\t\t\tconst invoker = queryImperativeService.bind<unknown[], unknown>(getCommand);\n\t\t\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n\t\t}\n\t\tcase \"subscribable\": {\n\t\t\tconst invoker = subscribableImperativeService.bind<unknown[], unknown>(\n\t\t\t\tgetSubscribableCommand,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n\t\t}\n\t\tcase \"subscribable-refreshable\": {\n\t\t\tconst invoker = subscribableImperativeService.bind<unknown[], unknown>(\n\t\t\t\tgetSubscribableCommand,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t\treturn (...params: unknown[]) => Promise.resolve(invoker(...params));\n\t\t}\n\t\tcase \"legacy\": {\n\t\t\t// Legacy service passes `{ config, assertIsValid }`, not `{ params, ... }`.\n\t\t\tconst getLegacyCommand = (options: {\n\t\t\t\tconfig: unknown;\n\t\t\t\tassertIsValid: typeof assertIsValid;\n\t\t\t}) => {\n\t\t\t\toptions.assertIsValid(options.config, cfg.configJsonSchema);\n\t\t\t\treturn new McpToolSubscribableCommand<unknown>(name, toolName, options.config);\n\t\t\t};\n\t\t\treturn legacyImperativeService.bind<unknown, unknown>(getLegacyCommand);\n\t\t}\n\t\tdefault:\n\t\t\tthrow new Error(\n\t\t\t\t`[${name}] unsupported invokerShape: ${String((cfg as { invokerShape: unknown }).invokerShape)}. ` +\n\t\t\t\t\t`Expected 'legacy' | 'query' | 'subscribable' | 'subscribable-refreshable'.`,\n\t\t\t);\n\t}\n}\n\nconst lwcWireBindingsService = buildLWCWireBindingsServiceDescriptor().service;\n\n/**\n * Splits the MCP tool's `{ data, error }` envelope into a `Result`. Used as\n * the `unwrap` hook on `McpToolCommand` so OneStore's wire invoker sees the\n * error branch directly instead of receiving an envelope wrapped in `ok(...)`.\n *\n * Tools that don't emit the envelope (e.g. imperative) never go through this\n * path — the default imperative invoker doesn't pass `unwrap`.\n */\nfunction unwrapWireEnvelope<Data>(payload: unknown): Result<Data, Error> {\n\tconst envelope = payload as { data?: unknown; error?: unknown } | null | undefined;\n\tif (envelope && envelope.error !== undefined && envelope.error !== null) {\n\t\treturn err(toError(envelope.error));\n\t}\n\treturn ok(envelope?.data as Data);\n}\n\n/**\n * Creates an LWC wire adapter class that calls an MCP tool. Delegates to\n * OneStore's `LWCWireBindingsService`, so the returned class inherits the\n * full `CommandWireAdapterConstructor` contract: initial empty emit, config\n * `sanitize()`, `MissingRequiredPropertyError` → wait-for-next-config gating,\n * deep-freeze on success, race guard on stale resolves, and unsubscriber\n * management on disconnect.\n *\n * The `McpToolCommand` class is reused verbatim — the wire call-site only\n * supplies an `unwrap` hook so the tool's `{ data, error }` envelope lands\n * on OneStore's Err branch rather than being leaked through as an `ok(...)`\n * envelope.\n *\n * @param name - Wire adapter export name, used in MCP error messages.\n * @param cfg - MCP tool name and JSON Schema for valid wire configs.\n */\nexport function createWireAdapter(name: string, cfg: WireAdapterConfig) {\n\tconst toolName = resolveMcpToolName(name, cfg);\n\treturn lwcWireBindingsService.bind<unknown>(\n\t\t(config) => new McpToolCommand(name, toolName, config, unwrapWireEnvelope),\n\t\tcfg.configJsonSchema,\n\t);\n}\n\n// ─── GraphQL adapters ─────────────────────────────────────────────────────────\n\n/**\n * GraphQL adapters diverge from the base wire / mutation shapes in two ways:\n *\n * 1. Envelope is `{ data, errors[] }` instead of `{ data, error }`. Errors\n * are collected; an empty array collapses to `undefined`.\n * 2. The `_fetch` path routes thrown errors **into** the `errors[]`\n * envelope on the wire callback (never throws to the LWC host). Mutation\n * likewise resolves with `{ data, errors }` rather than rejecting.\n *\n * Dispatch is MCP-only: `getChatSDK().callTool({ toolName, params })` with\n * `normalizeMcpResponse` unwrapping. No `globalThis.__sfdc_sdk__` shortcut —\n * the on-platform behaviour is already covered by real `lightning/graphql`,\n * and every off-platform caller routes through an MCP tool like every other\n * LDS adapter.\n */\ntype GraphqlAdapterConfig = McpBackedAdapterConfig;\n\ninterface GraphqlConfig {\n\tquery?: string;\n\tvariables?: Record<string, unknown>;\n}\n\ninterface GraphqlResult {\n\tdata?: unknown;\n\terrors?: { message: string }[];\n}\n\ntype GraphqlWireCallback = (result: {\n\tdata: unknown;\n\terrors: { message: string }[] | undefined;\n\trefresh: () => Promise<void>;\n}) => void;\n\n/**\n * Template-literal tag that stitches the string into a plain `query` string.\n * Deliberately minimal — no AST parsing, no fragment substitution, no opaque\n * doc emulation. Matches the shape used by today's off-platform `gql`.\n */\nexport function gql(strings: TemplateStringsArray, ...values: unknown[]): string {\n\tlet result = \"\";\n\tstrings.forEach((string, i) => {\n\t\tresult += string;\n\t\tif (i < values.length) result += String(values[i]);\n\t});\n\treturn result.trim();\n}\n\nasync function runGraphqlQuery(\n\tadapterName: string,\n\ttoolName: string,\n\tconfig: GraphqlConfig,\n): Promise<GraphqlResult> {\n\tconst { query, variables } = config;\n\tif (!query) return { data: undefined, errors: undefined };\n\n\tconst callTool = await getCallTool(adapterName);\n\tconst raw = await callTool({\n\t\ttoolName,\n\t\tparams: { query, variables: variables ?? {} },\n\t});\n\n\treturn (normalizeMcpResponse(raw) as GraphqlResult) ?? {};\n}\n\n/** Wraps a thrown Error into the graphql `{ data, errors[] }` envelope. */\nfunction toGraphqlErrorResult(error: unknown): GraphqlResult {\n\treturn { data: undefined, errors: [{ message: (error as Error).message }] };\n}\n\n/**\n * `runGraphqlQuery` wrapped in try/catch so thrown errors land on `errors[]`\n * instead of rejecting. Used by every graphql shape that routes errors\n * in-band (wire, mutation, imperative-read query/query-refreshable, legacy).\n */\nasync function runGraphqlQuerySafe(\n\tadapterName: string,\n\ttoolName: string,\n\tconfig: GraphqlConfig,\n): Promise<GraphqlResult> {\n\ttry {\n\t\treturn await runGraphqlQuery(adapterName, toolName, config);\n\t} catch (error) {\n\t\treturn toGraphqlErrorResult(error);\n\t}\n}\n\n/**\n * GraphQL wire adapter factory. Emits `{ data, errors, refresh }` to the wire\n * callback. Mirrors the `constructor(callback)` → `connect` / `disconnect` /\n * `update(config)` / `refresh()` contract used by the LWC wire service.\n * Thrown fetch errors are routed into `errors[0].message`.\n *\n * `_fetch` is gated on `_connected` so that the common wire lifecycle\n * (`constructor` → `update(config)` → `connect`) doesn't fire two requests:\n * the initial `update(config)` arrives before `connect()`, stores the config,\n * and waits. `connect()` does the one fetch; later `update(config)` while\n * connected re-fetches. This matches luvio's `LWCLuvioWireAdapter`, which\n * gates on the same flag to prevent duplicate endpoint calls.\n */\nexport function createGraphQLWireAdapter(name: string, cfg: GraphqlAdapterConfig) {\n\tconst toolName = resolveMcpToolName(name, cfg);\n\treturn class {\n\t\t_dataCallback: GraphqlWireCallback;\n\t\t_config: GraphqlConfig | undefined;\n\t\t_connected = false;\n\n\t\tconstructor(dataCallback: GraphqlWireCallback) {\n\t\t\tthis._dataCallback = dataCallback;\n\t\t}\n\n\t\tconnect() {\n\t\t\tthis._connected = true;\n\t\t\tvoid this._fetch();\n\t\t}\n\n\t\tdisconnect() {\n\t\t\tthis._connected = false;\n\t\t}\n\n\t\tupdate(config: GraphqlConfig | undefined) {\n\t\t\tthis._config = config;\n\n\t\t\tif (!this._connected || this._config === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvoid this._fetch();\n\t\t}\n\n\t\trefresh() {\n\t\t\treturn this._fetch();\n\t\t}\n\n\t\tasync _fetch() {\n\t\t\tthis._emit(await runGraphqlQuerySafe(name, toolName, this._config ?? {}));\n\t\t}\n\n\t\t_emit({ data, errors }: GraphqlResult) {\n\t\t\tthis._dataCallback({\n\t\t\t\tdata,\n\t\t\t\terrors: errors?.length ? errors : undefined,\n\t\t\t\trefresh: () => this.refresh(),\n\t\t\t});\n\t\t}\n\t};\n}\n\n/**\n * GraphQL mutation factory. Returns `async (config) => Promise<{ data, errors }>`.\n * Empty-query guard short-circuits with\n * `{ data: undefined, errors: [{ message: \"No query provided\" }] }`.\n * All other errors are routed in-band to the `errors[]` envelope — the\n * function never rejects.\n */\nexport function createGraphQLMutationAdapter(name: string, cfg: GraphqlAdapterConfig) {\n\tconst toolName = resolveMcpToolName(name, cfg);\n\treturn async (config: GraphqlConfig): Promise<GraphqlResult> => {\n\t\tif (!config?.query) return { data: undefined, errors: [{ message: \"No query provided\" }] };\n\t\treturn runGraphqlQuerySafe(name, toolName, config);\n\t};\n}\n\ntype GraphqlImperativeReadInvokerShape = \"query\" | \"query-refreshable\" | \"legacy\";\n\ninterface GraphqlImperativeReadAdapterConfig extends GraphqlAdapterConfig {\n\tinvokerShape: GraphqlImperativeReadInvokerShape;\n}\n\ntype GraphqlImperativeResult = GraphqlResult & {\n\tsubscribe?: (cb: (result: GraphqlResult) => void) => Unsubscribe;\n\trefresh?: () => Promise<void>;\n};\n\ntype LegacyGraphqlCallback = (result: GraphqlResult) => void;\n\n/**\n * Imperative GraphQL read factory — single entry point for all imperative\n * graphql read shapes, mirroring the LDS `createReadAdapter` pattern. The\n * `invokerShape` selects the return surface:\n *\n * - `query` — `async (config) => Promise<{ data, errors, subscribe }>`.\n * Mirrors on-platform `GraphQLImperativeBindingsService` without\n * `exposeRefresh`. Errors are routed in-band; the function never throws.\n * - `query-refreshable` — same as `query` plus `refresh()` that re-runs the\n * underlying MCP tool. Mirrors the same service with `exposeRefresh: true`.\n * - `legacy` — `{ invoke(config, context, callback),\n * subscribe(config, context, callback): Unsubscribe }`. The callback\n * always receives `{ data, errors }`; neither method throws. `context` is\n * accepted but ignored.\n *\n * In every shape `subscribe` is a deliberate no-op off-platform (no reactive\n * store); returned unsubscribes are idempotent.\n */\nexport function createGraphQLImperativeReadAdapter(\n\tname: string,\n\tcfg: GraphqlImperativeReadAdapterConfig,\n) {\n\tconst toolName = resolveMcpToolName(name, cfg);\n\tif (cfg.invokerShape === \"legacy\") {\n\t\tasync function run(\n\t\t\tconfig: GraphqlConfig | undefined,\n\t\t\tcallback: LegacyGraphqlCallback,\n\t\t): Promise<void> {\n\t\t\tif (!config?.query) {\n\t\t\t\tcallback({ data: undefined, errors: undefined });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await runGraphqlQuerySafe(name, toolName, config);\n\t\t\tcallback({\n\t\t\t\tdata: result.data,\n\t\t\t\terrors: result.errors?.length ? result.errors : undefined,\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tinvoke(\n\t\t\t\tconfig: GraphqlConfig | undefined,\n\t\t\t\t_context: unknown,\n\t\t\t\tcallback: LegacyGraphqlCallback,\n\t\t\t): void {\n\t\t\t\tvoid run(config, callback);\n\t\t\t},\n\t\t\tsubscribe(\n\t\t\t\tconfig: GraphqlConfig | undefined,\n\t\t\t\t_context: unknown,\n\t\t\t\tcallback: LegacyGraphqlCallback,\n\t\t\t): Unsubscribe {\n\t\t\t\tvoid run(config, callback);\n\t\t\t\treturn noopUnsubscribe;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (cfg.invokerShape === \"query-refreshable\") {\n\t\t// Per-invocation subscriber set: each call to the returned function\n\t\t// gets its own adapter instance with an isolated subscriber list.\n\t\t// `refresh()` re-runs the MCP tool and broadcasts the fresh\n\t\t// `{ data, errors }` to every registered callback, which mirrors the\n\t\t// on-platform contract where `refresh` causes store updates that fan\n\t\t// out through the `subscribe` fan-in. Without this wiring, `refresh`\n\t\t// would re-run the query off-platform but nothing could observe the\n\t\t// new payload (no store, noop subscribe).\n\t\treturn async (config: GraphqlConfig): Promise<GraphqlImperativeResult> => {\n\t\t\tconst result = await runGraphqlQuerySafe(name, toolName, config);\n\t\t\tif (result.errors?.length) {\n\t\t\t\treturn { data: undefined, errors: result.errors };\n\t\t\t}\n\t\t\tconst subscribers = new Set<(result: GraphqlResult) => void>();\n\t\t\treturn {\n\t\t\t\tdata: result.data,\n\t\t\t\terrors: undefined,\n\t\t\t\tsubscribe: (cb) => {\n\t\t\t\t\tsubscribers.add(cb);\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tsubscribers.delete(cb);\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\trefresh: async () => {\n\t\t\t\t\tconst fresh = await runGraphqlQuerySafe(name, toolName, config);\n\t\t\t\t\tconst payload: GraphqlResult = {\n\t\t\t\t\t\tdata: fresh.data,\n\t\t\t\t\t\terrors: fresh.errors?.length ? fresh.errors : undefined,\n\t\t\t\t\t};\n\t\t\t\t\tsubscribers.forEach((cb) => cb(payload));\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\t}\n\n\t// `query` shape: no refresh → nothing can trigger a post-initial update\n\t// off-platform, so `subscribe` stays a noop. The on-platform contract\n\t// allows subscribe callbacks to fire from unrelated store writes; off-\n\t// platform there is no store, so the callback is correctly unreachable.\n\treturn async (config: GraphqlConfig): Promise<GraphqlImperativeResult> => {\n\t\tconst result = await runGraphqlQuerySafe(name, toolName, config);\n\t\tif (result.errors?.length) {\n\t\t\treturn { data: undefined, errors: result.errors };\n\t\t}\n\t\treturn {\n\t\t\tdata: result.data,\n\t\t\terrors: undefined,\n\t\t\tsubscribe: noopSubscribe,\n\t\t};\n\t};\n}\n"],"names":[],"mappings":"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"}
@@ -10,27 +10,16 @@ existing LWC project so you can compile your components into a single self-conta
10
10
 
11
11
  - **Node.js** >= 20.0.0
12
12
  - **LWC components** in a project directory (standard SFDX project or custom layout)
13
- - **Salesforce CLI** (`sf`) — only needed if connecting to a real org (Tier 2)
14
13
 
15
14
  ---
16
15
 
17
16
  ## Overview
18
17
 
19
- The plugin supports two tiers of usage:
20
-
21
- | Tier | What You Get | Org Required? |
22
- | ------------------------------- | ------------------------------------------ | ------------------ |
23
- | **Tier 1: Off-Platform Build** | Static bundle with mock data, labels, i18n | No |
24
- | **Tier 2: Live Org Connection** | Real GraphQL queries, live Salesforce data | Yes (via `sf` CLI) |
25
-
26
- Start with Tier 1. Add Tier 2 later if your components need live org data via
27
- `@salesforce/sdk-data` (`/services/*` calls). `lightning/graphql` dispatches
28
- through MCP (`builtins.lds()`) in both tiers — route the `graphqlQuery` tool at
29
- your MCP host rather than reaching for `lwcProxy()`.
18
+ The plugin compiles your LWC components into a single self-contained `dist/index.html` that runs in a real MCP host (ChatGPT, MCP Apps, local demo MCP) — same bundle, no conditional wrapping. For **local development without a real host**, install a `window.openai.callTool` mock in your entry script; the guarded install is skipped automatically when a real host provides `window.openai`. `lightning/graphql` and `lightning/uiRecordApi` both route through MCP (`callTool("graphqlQuery", ...)` and `callTool("getRecordMcpTool", ...)`) via `builtins.lds()`.
30
19
 
31
20
  ---
32
21
 
33
- ## Tier 1: Off-Platform Build
22
+ ## Off-Platform Build
34
23
 
35
24
  ### Project Structure
36
25
 
@@ -233,20 +222,55 @@ Always include `builtins.gate()` and `builtins.accessCheck()` when using
233
222
 
234
223
  ### Step 4: Create `bootstrap.js`
235
224
 
225
+ The compiled bundle targets real MCP hosts (ChatGPT, MCP Apps, local demo MCP) — they provide `window.openai.callTool` before the bundle loads. For **local development without a real host**, install a guarded mock at the top of `bootstrap.js` so `@wire(graphql)`, `@wire(getRecord)`, and `executeMutation` calls return data. The guard (`if (!window.openai?.callTool)`) makes the mock a no-op when a real host is present, so the same compiled bundle works in both environments.
226
+
236
227
  ```js
237
- import "@salesforce-ux/design-system/assets/styles/salesforce-lightning-design-system.css";
238
- import "@lwc/synthetic-shadow";
239
- import { createElement } from "lwc";
228
+ // Mock window.openai.callTool for local dev. Must run before any LWC / sdk-core
229
+ // import, because sdk-core detects the surface at module-load time by reading
230
+ // window.openai. Guard with `if (!window.openai?.callTool)` so a real MCP host
231
+ // skips this block entirely.
232
+ if (!window.openai?.callTool) {
233
+ window.openai = {
234
+ ...window.openai,
235
+ callTool: async (name, args) => {
236
+ await new Promise((r) => setTimeout(r, 300)); // simulate latency
237
+
238
+ if (name === "getRecordMcpTool") {
239
+ // lightning/uiRecordApi → @wire(getRecord)
240
+ return {
241
+ structuredContent: {
242
+ data: {
243
+ fields: { Name: { value: "Mock Record" } },
244
+ },
245
+ },
246
+ };
247
+ }
248
+ if (name === "graphqlQuery") {
249
+ // lightning/graphql → @wire(graphql) or executeMutation(...)
250
+ // Branch on args.query to return different envelopes.
251
+ return { result: JSON.stringify({ data: {} }) };
252
+ }
253
+ return { result: JSON.stringify({ data: {} }) };
254
+ },
255
+ };
256
+ }
240
257
 
241
- // Import your root component using its LWC specifier: <namespace>/<componentName>
242
- import App from "c/myApp";
258
+ // Dynamic imports so the mock above is in place before sdk-core loads.
259
+ await import("@lwc/synthetic-shadow");
260
+ await import("@salesforce-ux/design-system/assets/styles/salesforce-lightning-design-system.css");
261
+ const { createElement } = await import("lwc");
262
+ const { default: App } = await import("c/myApp");
243
263
 
244
- // Mount it — tag name is the kebab-case version of the specifier
245
264
  const el = createElement("c-my-app", { is: App });
246
265
  document.getElementById("app").appendChild(el);
247
266
  ```
248
267
 
249
- Replace `c/myApp` and `c-my-app` with your actual root component name.
268
+ Replace `c/myApp` and `c-my-app` with your actual root component name. If your components use only labels, i18n, and base components (no LDS / graphql), the `callTool` mock block can be omitted — `window.openai` only matters when MCP-backed adapters are in play.
269
+
270
+ For complete working examples, see:
271
+
272
+ - [`lwc-simple/src/main.js`](../../../examples/lwc-axl/lwc-simple/src/main.js) — `@wire(getRecord)` + `@wire(graphql)` (read paths)
273
+ - [`lwc-records/src/app/bootstrap.js`](../../../examples/lwc-axl/lwc-records/src/app/bootstrap.js) — `executeMutation` with a `ContactUpdate` branch
250
274
 
251
275
  ### Step 5: Build and Test
252
276
 
@@ -268,107 +292,6 @@ npm run preview
268
292
 
269
293
  ---
270
294
 
271
- ## Tier 2: Live Org Connection (lwcProxy)
272
-
273
- If your components need live Salesforce data via `@salesforce/sdk-data` (e.g.
274
- `/services/*` calls from `lightning/*` modules), add `lwcProxy()` to connect to
275
- a real org during development. `lightning/graphql` itself routes through MCP
276
- via `builtins.lds()` regardless of `lwcProxy` — point the `graphqlQuery` tool
277
- at your org via your MCP host if you need live GraphQL.
278
-
279
- ### Prerequisites
280
-
281
- - Salesforce CLI installed and an org connected: `sf org display`
282
- - Additional packages: `@salesforce/sdk-data` and `@salesforce/ui-bundle`
283
-
284
- ### Step 1: Install Additional Dependencies
285
-
286
- ```bash
287
- npm install @salesforce/sdk-data @salesforce/ui-bundle
288
- ```
289
-
290
- ### Step 2: Update `vite.config.js`
291
-
292
- Add `lwcProxy()` before `lwcVitePlugin()` and add `builtins.lds()` to providers
293
- (this registers GraphQL plus the other LDS adapters by default):
294
-
295
- ```js
296
- import { defineConfig } from "vite";
297
- import lwcVitePlugin, { builtins, lwcProxy } from "@salesforce/vite-plugin-lwc-ui-bundle";
298
- import { viteSingleFile } from "vite-plugin-singlefile";
299
-
300
- export default defineConfig({
301
- build: {
302
- target: "esnext",
303
- minify: false,
304
- },
305
- plugins: [
306
- lwcProxy({ debug: true }),
307
- // lwcProxy({ orgAlias: "my-org", debug: true }), // explicit org
308
- lwcVitePlugin({
309
- modules: {
310
- dirs: [{ path: "force-app/main/default/lwc", namespace: "c" }],
311
- npm: ["lightning-base-components"],
312
- },
313
- providers: [
314
- builtins.label(),
315
- builtins.i18n(),
316
- builtins.client(),
317
- builtins.gate(),
318
- builtins.accessCheck(),
319
- builtins.lds(),
320
- ],
321
- }),
322
- viteSingleFile(),
323
- ],
324
- });
325
- ```
326
-
327
- ### Step 3: Update `bootstrap.js`
328
-
329
- Initialize the Data SDK before mounting your app. This requires top-level `await`
330
- (hence `target: "esnext"` in the vite config):
331
-
332
- ```js
333
- import "@salesforce-ux/design-system/assets/styles/salesforce-lightning-design-system.css";
334
- import "@lwc/synthetic-shadow";
335
- import { createElement } from "lwc";
336
-
337
- // Initialize SDK — lwcProxy() handles /services/* in the Vite dev server
338
- import { createDataSDK } from "@salesforce/sdk-data";
339
- try {
340
- globalThis.__sfdc_sdk__ = await createDataSDK({ uiBundle: { basePath: "/" } });
341
- } catch (_err) {
342
- globalThis.__sfdc_sdk__ = {};
343
- }
344
-
345
- // Import your root component
346
- import App from "c/myApp";
347
-
348
- const el = createElement("c-my-app", { is: App });
349
- document.getElementById("app").appendChild(el);
350
- ```
351
-
352
- ### Step 4: Run Dev Server
353
-
354
- ```bash
355
- npm run dev
356
- # Terminal shows: [lwc-proxy] Connected to https://your-org.my.salesforce.com
357
- # Open http://localhost:5173
358
- ```
359
-
360
- `lwcProxy()` intercepts `/services/*` calls inside the Vite dev server — no
361
- separate proxy process needed. This unlocks `lightning/*` modules that reach
362
- Salesforce directly through `@salesforce/sdk-data`. `@wire(graphql, ...)` still
363
- dispatches through MCP (`builtins.lds()` → `graphqlQuery` tool) rather than
364
- the proxy; wire it through your MCP host if you want live GraphQL in dev.
365
-
366
- > **Note:** `lwcProxy()` works with `npm run dev` only. The production build
367
- > (`dist/index.html`) does not include the proxy — it's a static file. For
368
- > production use with live data, you need a separate API proxy or MCP server.
369
-
370
- ---
371
-
372
295
  ## Common Errors
373
296
 
374
297
  ### `Cannot read properties of undefined (reading 'isOpen')`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/vite-plugin-lwc-ui-bundle",
3
- "version": "1.135.0",
3
+ "version": "2.0.0",
4
4
  "description": "Vite plugin for compiling LWC components into static bundles for off-platform and MCP use",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "Salesforce",
@@ -54,8 +54,8 @@
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@lwc/rollup-plugin": "^9.0.0",
57
- "@salesforce/sdk-chat": "^1.123.0",
58
- "@salesforce/ui-bundle": "^1.123.0",
57
+ "@salesforce/platform-sdk-chat": "^2.0.0",
58
+ "@salesforce/ui-bundle": "^2.0.0",
59
59
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
60
60
  "zod": "^3.23.8"
61
61
  },
@@ -65,17 +65,17 @@
65
65
  }
66
66
  },
67
67
  "dependencies": {
68
+ "@conduit-client/jsonschema-validate": "3.19.3",
69
+ "@conduit-client/service-bindings-imperative": "3.19.3",
70
+ "@conduit-client/service-bindings-lwc": "3.19.3",
71
+ "@conduit-client/utils": "3.19.3",
68
72
  "es-module-lexer": "^1.7.0",
69
73
  "magic-string": "^0.30.17"
70
74
  },
71
75
  "devDependencies": {
72
76
  "@conduit-client/bindings-utils": "3.19.3",
73
77
  "@conduit-client/command-base": "3.19.3",
74
- "@conduit-client/jsonschema-validate": "3.19.3",
75
- "@conduit-client/service-bindings-imperative": "3.19.3",
76
- "@conduit-client/service-bindings-lwc": "3.19.3",
77
- "@conduit-client/utils": "3.19.3",
78
- "@salesforce/sdk-chat": "^1.135.0",
78
+ "@salesforce/platform-sdk-chat": "^2.0.0",
79
79
  "typescript": "^5.9.3",
80
80
  "vite": "^7.0.0",
81
81
  "vite-plugin-dts": "^4.5.4",