@assistant-ui/metro 0.0.8 → 0.0.11

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/dist/index.cjs CHANGED
@@ -8,6 +8,11 @@ const require$1 = (0, require("node:module").createRequire)(require("url").pathT
8
8
  */
9
9
  const UPSTREAM_TRANSFORMER_ENV = "AUI_METRO_UPSTREAM_TRANSFORMER";
10
10
  /**
11
+ * Env var carrying the `backendless` option to the transformer. Metro forks its
12
+ * transform workers after `metro.config` is evaluated, so they inherit it.
13
+ */
14
+ const BACKENDLESS_ENV = "AUI_METRO_BACKENDLESS";
15
+ /**
11
16
  * Wraps a Metro (or Expo) config so assistant-ui `"use generative"` modules are
12
17
  * compiled. Such a file colocates a tool's schema, its `execute`, and its
13
18
  * `render` via {@link https://www.assistant-ui.com/docs/tools/defining-tools | defineToolkit}.
@@ -23,7 +28,10 @@ const UPSTREAM_TRANSFORMER_ENV = "AUI_METRO_UPSTREAM_TRANSFORMER";
23
28
  * const { getDefaultConfig } = require("expo/metro-config");
24
29
  * const { withAui } = require("@assistant-ui/metro");
25
30
  *
26
- * module.exports = withAui(getDefaultConfig(__dirname));
31
+ * module.exports = withAui({
32
+ * ...getDefaultConfig(__dirname),
33
+ * aui: { backendless: true },
34
+ * });
27
35
  * ```
28
36
  *
29
37
  * Authoring is identical to the web: a `"use generative"` file whose default
@@ -31,10 +39,12 @@ const UPSTREAM_TRANSFORMER_ENV = "AUI_METRO_UPSTREAM_TRANSFORMER";
31
39
  */
32
40
  function withAui(config) {
33
41
  const self = require$1.resolve("@assistant-ui/metro/transformer");
42
+ const { aui, ...baseConfig } = config;
34
43
  const upstream = config.transformer?.babelTransformerPath;
44
+ if (aui?.backendless) process.env[BACKENDLESS_ENV] = "1";
35
45
  if (upstream && upstream !== self) process.env[UPSTREAM_TRANSFORMER_ENV] = upstream;
36
46
  return {
37
- ...config,
47
+ ...baseConfig,
38
48
  transformer: {
39
49
  ...config.transformer,
40
50
  babelTransformerPath: self
@@ -42,6 +52,7 @@ function withAui(config) {
42
52
  };
43
53
  }
44
54
  //#endregion
55
+ exports.BACKENDLESS_ENV = BACKENDLESS_ENV;
45
56
  exports.UPSTREAM_TRANSFORMER_ENV = UPSTREAM_TRANSFORMER_ENV;
46
57
  exports.withAui = withAui;
47
58
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["require","createRequire"],"sources":["../src/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\n/**\n * The shape of a Metro / Expo config `withAui` accepts. Typed loosely so this\n * package needs no hard dependency on `metro` or `expo`; the input shape is\n * preserved and only `transformer.babelTransformerPath` is augmented.\n */\nexport type MetroConfigLike = {\n transformer?:\n | {\n babelTransformerPath?: string | undefined;\n [key: string]: unknown;\n }\n | undefined;\n [key: string]: unknown;\n};\n\n/**\n * Env var the transformer reads to delegate to the project's existing\n * (Expo / React Native) babel transformer. Metro forks its transform workers\n * after `metro.config` is evaluated, so they inherit this value.\n */\nexport const UPSTREAM_TRANSFORMER_ENV = \"AUI_METRO_UPSTREAM_TRANSFORMER\";\n\n/**\n * Wraps a Metro (or Expo) config so assistant-ui `\"use generative\"` modules are\n * compiled. Such a file colocates a tool's schema, its `execute`, and its\n * `render` via {@link https://www.assistant-ui.com/docs/tools/defining-tools | defineToolkit}.\n *\n * It points Metro's `babelTransformerPath` at this package's transformer, which\n * runs the `\"use generative\"` compiler and then delegates to your project's\n * existing transformer. The device (client) build keeps each tool's `render`\n * and any frontend `execute`; a server build (an Expo Router `+api` route)\n * keeps a server `execute` instead.\n *\n * ```js\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { withAui } = require(\"@assistant-ui/metro\");\n *\n * module.exports = withAui(getDefaultConfig(__dirname));\n * ```\n *\n * Authoring is identical to the web: a `\"use generative\"` file whose default\n * export is `defineToolkit({ ... })`, registered with `Tools({ toolkit })`.\n */\nexport function withAui<T extends MetroConfigLike>(config: T): T {\n const self = require.resolve(\"@assistant-ui/metro/transformer\");\n const upstream = config.transformer?.babelTransformerPath;\n\n // Guard against a double-wrap (`withAui(withAui(config))`, or a shared config\n // already wrapped): if it already points at our transformer, keep the real\n // upstream captured earlier rather than overwriting it with our own path,\n // which would make `resolveUpstream()` return this transformer and recurse.\n if (upstream && upstream !== self) {\n process.env[UPSTREAM_TRANSFORMER_ENV] = upstream;\n }\n\n return {\n ...config,\n transformer: {\n ...config.transformer,\n babelTransformerPath: self,\n },\n };\n}\n"],"mappings":";;AAEA,MAAMA,aAAAA,wBAAUC,CAAAA,CAAAA,cAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,IAA6B;;;;;;AAsB7C,MAAa,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;AAwBxC,SAAgB,QAAmC,QAAc;CAC/D,MAAM,OAAOD,UAAQ,QAAQ,iCAAiC;CAC9D,MAAM,WAAW,OAAO,aAAa;CAMrC,IAAI,YAAY,aAAa,MAC3B,QAAQ,IAAI,4BAA4B;CAG1C,OAAO;EACL,GAAG;EACH,aAAa;GACX,GAAG,OAAO;GACV,sBAAsB;EACxB;CACF;AACF"}
1
+ {"version":3,"file":"index.cjs","names":["require","createRequire"],"sources":["../src/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\n/**\n * The shape of a Metro / Expo config `withAui` accepts. Typed loosely so this\n * package needs no hard dependency on `metro` or `expo`; the input shape is\n * preserved and only `transformer.babelTransformerPath` is augmented.\n */\nexport type MetroConfigLike = {\n /** assistant-ui options, stripped from the config handed back to Metro. */\n aui?: WithAuiOptions | undefined;\n transformer?:\n | {\n babelTransformerPath?: string | undefined;\n [key: string]: unknown;\n }\n | undefined;\n [key: string]: unknown;\n};\n\n/**\n * Env var the transformer reads to delegate to the project's existing\n * (Expo / React Native) babel transformer. Metro forks its transform workers\n * after `metro.config` is evaluated, so they inherit this value.\n */\nexport const UPSTREAM_TRANSFORMER_ENV = \"AUI_METRO_UPSTREAM_TRANSFORMER\";\n\n/**\n * Env var carrying the `backendless` option to the transformer. Metro forks its\n * transform workers after `metro.config` is evaluated, so they inherit it.\n */\nexport const BACKENDLESS_ENV = \"AUI_METRO_BACKENDLESS\";\n\nexport interface WithAuiOptions {\n /**\n * The app has no backend importing the server builds of its `\"use generative\"`\n * modules (e.g. cloud-hosted runs). Frontend/human tool schemas then stay\n * uploadable from the client instead of being assumed backend-known.\n */\n backendless?: boolean;\n}\n\n/**\n * Wraps a Metro (or Expo) config so assistant-ui `\"use generative\"` modules are\n * compiled. Such a file colocates a tool's schema, its `execute`, and its\n * `render` via {@link https://www.assistant-ui.com/docs/tools/defining-tools | defineToolkit}.\n *\n * It points Metro's `babelTransformerPath` at this package's transformer, which\n * runs the `\"use generative\"` compiler and then delegates to your project's\n * existing transformer. The device (client) build keeps each tool's `render`\n * and any frontend `execute`; a server build (an Expo Router `+api` route)\n * keeps a server `execute` instead.\n *\n * ```js\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { withAui } = require(\"@assistant-ui/metro\");\n *\n * module.exports = withAui({\n * ...getDefaultConfig(__dirname),\n * aui: { backendless: true },\n * });\n * ```\n *\n * Authoring is identical to the web: a `\"use generative\"` file whose default\n * export is `defineToolkit({ ... })`, registered with `Tools({ toolkit })`.\n */\nexport function withAui<T extends MetroConfigLike>(config: T): T {\n const self = require.resolve(\"@assistant-ui/metro/transformer\");\n // Metro validates config keys it does not recognize, so `aui` must not\n // survive into the returned config.\n const { aui, ...baseConfig } = config;\n const upstream = config.transformer?.babelTransformerPath;\n\n if (aui?.backendless) process.env[BACKENDLESS_ENV] = \"1\";\n\n // Guard against a double-wrap (`withAui(withAui(config))`, or a shared config\n // already wrapped): if it already points at our transformer, keep the real\n // upstream captured earlier rather than overwriting it with our own path,\n // which would make `resolveUpstream()` return this transformer and recurse.\n if (upstream && upstream !== self) {\n process.env[UPSTREAM_TRANSFORMER_ENV] = upstream;\n }\n\n return {\n ...baseConfig,\n transformer: {\n ...config.transformer,\n babelTransformerPath: self,\n },\n } as T;\n}\n"],"mappings":";;AAEA,MAAMA,aAAAA,wBAAUC,CAAAA,CAAAA,cAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,IAA6B;;;;;;AAwB7C,MAAa,2BAA2B;;;;;AAMxC,MAAa,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;AAoC/B,SAAgB,QAAmC,QAAc;CAC/D,MAAM,OAAOD,UAAQ,QAAQ,iCAAiC;CAG9D,MAAM,EAAE,KAAK,GAAG,eAAe;CAC/B,MAAM,WAAW,OAAO,aAAa;CAErC,IAAI,KAAK,aAAa,QAAQ,IAAI,mBAAmB;CAMrD,IAAI,YAAY,aAAa,MAC3B,QAAQ,IAAI,4BAA4B;CAG1C,OAAO;EACL,GAAG;EACH,aAAa;GACX,GAAG,OAAO;GACV,sBAAsB;EACxB;CACF;AACF"}
package/dist/index.d.cts CHANGED
@@ -5,6 +5,8 @@
5
5
  * preserved and only `transformer.babelTransformerPath` is augmented.
6
6
  */
7
7
  type MetroConfigLike = {
8
+ /** assistant-ui options, stripped from the config handed back to Metro. */
9
+ aui?: WithAuiOptions | undefined;
8
10
  transformer?: {
9
11
  babelTransformerPath?: string | undefined;
10
12
  [key: string]: unknown;
@@ -17,6 +19,19 @@ type MetroConfigLike = {
17
19
  * after `metro.config` is evaluated, so they inherit this value.
18
20
  */
19
21
  declare const UPSTREAM_TRANSFORMER_ENV = "AUI_METRO_UPSTREAM_TRANSFORMER";
22
+ /**
23
+ * Env var carrying the `backendless` option to the transformer. Metro forks its
24
+ * transform workers after `metro.config` is evaluated, so they inherit it.
25
+ */
26
+ declare const BACKENDLESS_ENV = "AUI_METRO_BACKENDLESS";
27
+ interface WithAuiOptions {
28
+ /**
29
+ * The app has no backend importing the server builds of its `"use generative"`
30
+ * modules (e.g. cloud-hosted runs). Frontend/human tool schemas then stay
31
+ * uploadable from the client instead of being assumed backend-known.
32
+ */
33
+ backendless?: boolean;
34
+ }
20
35
  /**
21
36
  * Wraps a Metro (or Expo) config so assistant-ui `"use generative"` modules are
22
37
  * compiled. Such a file colocates a tool's schema, its `execute`, and its
@@ -33,7 +48,10 @@ declare const UPSTREAM_TRANSFORMER_ENV = "AUI_METRO_UPSTREAM_TRANSFORMER";
33
48
  * const { getDefaultConfig } = require("expo/metro-config");
34
49
  * const { withAui } = require("@assistant-ui/metro");
35
50
  *
36
- * module.exports = withAui(getDefaultConfig(__dirname));
51
+ * module.exports = withAui({
52
+ * ...getDefaultConfig(__dirname),
53
+ * aui: { backendless: true },
54
+ * });
37
55
  * ```
38
56
  *
39
57
  * Authoring is identical to the web: a `"use generative"` file whose default
@@ -41,5 +59,5 @@ declare const UPSTREAM_TRANSFORMER_ENV = "AUI_METRO_UPSTREAM_TRANSFORMER";
41
59
  */
42
60
  declare function withAui<T extends MetroConfigLike>(config: T): T;
43
61
  //#endregion
44
- export { MetroConfigLike, UPSTREAM_TRANSFORMER_ENV, withAui };
62
+ export { BACKENDLESS_ENV, MetroConfigLike, UPSTREAM_TRANSFORMER_ENV, WithAuiOptions, withAui };
45
63
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;KASY;EACV;IAEM;KACC;;GAGN;;;;;;;cAQU;;;;;;;;;;;;;;;;;;;;;;;iBAwBG,QAAQ,UAAU,iBAAiB,QAAQ,IAAI"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;KASY;;EAEV,MAAM;EACN;IAEM;KACC;;GAGN;;;;;;;cAQU;;;;;cAMA;UAEI;;;;;;EAMf;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4Bc,QAAQ,UAAU,iBAAiB,QAAQ,IAAI"}
@@ -40,7 +40,7 @@ _babel_types = __toESM(_babel_types, 1);
40
40
  const DIRECTIVE = "use generative";
41
41
  //#endregion
42
42
  //#region ../x-generative-compiler/dist/package.js
43
- var version = "0.0.12";
43
+ var version = "0.0.15";
44
44
  //#endregion
45
45
  //#region ../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/constants.js
46
46
  var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -1508,6 +1508,7 @@ function isGenerativeModule(code) {
1508
1508
  if (code[directiveEnd] !== quote) return false;
1509
1509
  return hasDirectiveTerminator(code, directiveEnd + 1);
1510
1510
  }
1511
+ const isGenerativeSource = (filename, source) => /\.[cm]?[jt]sx?$/.test(filename) && isGenerativeModule(source);
1511
1512
  function hasDirectiveTerminator(code, start) {
1512
1513
  let i = start;
1513
1514
  let sawLineTerminator = false;
@@ -1590,6 +1591,7 @@ function isLineTerminator(char) {
1590
1591
  */
1591
1592
  function compileGenerative(code, options) {
1592
1593
  const { target, filename } = options;
1594
+ const backendless = options.backendless ?? false;
1593
1595
  const ast = (0, _babel_parser.parse)(code, {
1594
1596
  sourceType: "module",
1595
1597
  plugins: parserPlugins
@@ -1616,7 +1618,7 @@ function compileGenerative(code, options) {
1616
1618
  }
1617
1619
  if (_babel_types.isIdentifier(callee, { name: TOOLKIT_WRAPPER })) {
1618
1620
  if (!object) throw new GenerativeCompileError(`${TOOLKIT_WRAPPER}() takes an inline object literal of tools`, filename);
1619
- compileToolkit(object, target, generativeInstances, interactableToolImports, toolkitSpreadNames, namespaceImports, flags, filename);
1621
+ compileToolkit(object, target, generativeInstances, interactableToolImports, toolkitSpreadNames, namespaceImports, flags, backendless, filename);
1620
1622
  path.replaceWith(object);
1621
1623
  path.skip();
1622
1624
  }
@@ -1682,9 +1684,9 @@ function packageNameFromSpecifier(specifier) {
1682
1684
  }
1683
1685
  function resolvePackageJson(packageName, filename) {
1684
1686
  const requirePath = normalizeRequirePath(filename);
1685
- const require = (0, node_module.createRequire)(requirePath);
1687
+ const require$2 = (0, node_module.createRequire)(requirePath);
1686
1688
  try {
1687
- return findPackageJson(require.resolve(packageName), packageName);
1689
+ return findPackageJson(require$2.resolve(packageName), packageName);
1688
1690
  } catch {
1689
1691
  return findPackageJsonFromNodeModules(packageName, requirePath);
1690
1692
  }
@@ -1777,6 +1779,15 @@ function collectGenerativeInstances(ast) {
1777
1779
  }
1778
1780
  return names;
1779
1781
  }
1782
+ /**
1783
+ * Wraps a pass-through generative entry (`generative.present()`) so the tool it
1784
+ * returns loses its `unstable_backendDefault` marker. The library stamps the
1785
+ * marker at runtime, out of this compiler's reach, so a backendless client
1786
+ * build strips it post-hoc instead of threading an option into the library.
1787
+ */
1788
+ function stripBackendDefaultExpression(expr) {
1789
+ return _babel_types.callExpression(_babel_types.arrowFunctionExpression([_babel_types.objectPattern([_babel_types.objectProperty(_babel_types.identifier("unstable_backendDefault"), _babel_types.identifier("_backendDefault")), _babel_types.restElement(_babel_types.identifier("tool"))])], _babel_types.identifier("tool")), [expr]);
1790
+ }
1780
1791
  function collectGenerativeFactoryImports(ast) {
1781
1792
  const names = /* @__PURE__ */ new Set();
1782
1793
  for (const statement of ast.program.body) {
@@ -2191,7 +2202,7 @@ function compileComponents(object, target, flags, filename) {
2191
2202
  * `generative.present()` passes through, the library having already split it.
2192
2203
  * Mutates the object in place and records outcomes in {@link TargetFlags}.
2193
2204
  */
2194
- function compileToolkit(object, target, instances, interactableToolImports, toolkitSpreadNames, namespaceImports, flags, filename) {
2205
+ function compileToolkit(object, target, instances, interactableToolImports, toolkitSpreadNames, namespaceImports, flags, backendless, filename) {
2195
2206
  if (target === "client") warnDuplicateToolkitNames(object, toolkitSpreadNames, filename);
2196
2207
  const nextProperties = [];
2197
2208
  for (const entry of object.properties) {
@@ -2203,6 +2214,7 @@ function compileToolkit(object, target, instances, interactableToolImports, tool
2203
2214
  }
2204
2215
  const raw = entryRawValue(entry);
2205
2216
  if (raw && isGenerativeToolEntry(raw, instances)) {
2217
+ if (backendless && target === "client" && _babel_types.isObjectProperty(entry)) entry.value = stripBackendDefaultExpression(raw);
2206
2218
  nextProperties.push(entry);
2207
2219
  continue;
2208
2220
  }
@@ -2247,7 +2259,7 @@ function compileToolkit(object, target, instances, interactableToolImports, tool
2247
2259
  }
2248
2260
  }
2249
2261
  setToolType(value, type);
2250
- setBackendDefault(value, target, type);
2262
+ setBackendDefault(value, target, type, backendless);
2251
2263
  nextProperties.push(entry);
2252
2264
  }
2253
2265
  object.properties = nextProperties;
@@ -2358,8 +2370,9 @@ function setToolType(object, type) {
2358
2370
  removeMember(object, "type");
2359
2371
  object.properties.push(_babel_types.objectProperty(_babel_types.identifier("type"), _babel_types.stringLiteral(type)));
2360
2372
  }
2361
- function setBackendDefault(object, target, type) {
2373
+ function setBackendDefault(object, target, type, backendless) {
2362
2374
  removeMember(object, "unstable_backendDefault");
2375
+ if (backendless) return;
2363
2376
  if (target !== "client" || type !== "frontend" && type !== "human") return;
2364
2377
  object.properties.push(_babel_types.objectProperty(_babel_types.identifier("unstable_backendDefault"), _babel_types.objectExpression([_babel_types.objectProperty(_babel_types.identifier("parameters"), _babel_types.booleanLiteral(true))])));
2365
2378
  }
@@ -2443,8 +2456,6 @@ function isRemovableInit(node) {
2443
2456
  //#endregion
2444
2457
  //#region src/transformer.ts
2445
2458
  const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
2446
- /** Source modules a `"use generative"` directive can appear in. */
2447
- const SOURCE_RE = /\.[cm]?[jt]sx?$/;
2448
2459
  /**
2449
2460
  * The project's upstream babel transformer: what Metro would have used without
2450
2461
  * this wrapper. Taken from {@link UPSTREAM_TRANSFORMER_ENV} (set by `withAui`),
@@ -2469,11 +2480,12 @@ function isServerEnvironment(environment) {
2469
2480
  function transform(props) {
2470
2481
  const upstream = upstreamTransformer();
2471
2482
  const { filename, src, options } = props;
2472
- if (SOURCE_RE.test(filename) && isGenerativeModule(src)) {
2483
+ if (isGenerativeSource(filename, src)) {
2473
2484
  const { code } = compileGenerative(src, {
2474
2485
  target: isServerEnvironment(options?.customTransformOptions?.environment) ? "server" : "client",
2475
2486
  filename,
2476
- injectServerOnly: false
2487
+ injectServerOnly: false,
2488
+ backendless: process.env[require_index.BACKENDLESS_ENV] === "1"
2477
2489
  });
2478
2490
  return upstream.transform({
2479
2491
  ...props,
@@ -2494,7 +2506,9 @@ function selfCacheToken() {
2494
2506
  }
2495
2507
  function getCacheKey() {
2496
2508
  const upstream = upstreamTransformer();
2497
- return `${upstream.getCacheKey ? upstream.getCacheKey() : ""}$aui-metro:${selfCacheToken()}`;
2509
+ const base = upstream.getCacheKey ? upstream.getCacheKey() : "";
2510
+ const backendless = process.env["AUI_METRO_BACKENDLESS"] === "1" ? ":backendless" : "";
2511
+ return `${base}$aui-metro:${selfCacheToken()}${backendless}`;
2498
2512
  }
2499
2513
  //#endregion
2500
2514
  exports.getCacheKey = getCacheKey;