@immediately-run/sdk 0.15.0 → 0.17.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.
Files changed (122) hide show
  1. package/README.md +27 -3
  2. package/dist/MDXProvider.cjs.map +1 -1
  3. package/dist/MDXProvider.d.cts +4 -0
  4. package/dist/MDXProvider.d.ts +4 -0
  5. package/dist/MDXProvider.js.map +1 -1
  6. package/dist/RoutingSpec.cjs.map +1 -1
  7. package/dist/RoutingSpec.d.cts +20 -3
  8. package/dist/RoutingSpec.d.ts +20 -3
  9. package/dist/auth.cjs.map +1 -1
  10. package/dist/auth.d.cts +2 -0
  11. package/dist/auth.d.ts +2 -0
  12. package/dist/auth.js.map +1 -1
  13. package/dist/boot.cjs +17 -7
  14. package/dist/boot.cjs.map +1 -1
  15. package/dist/boot.d.cts +28 -4
  16. package/dist/boot.d.ts +28 -4
  17. package/dist/boot.js +16 -7
  18. package/dist/boot.js.map +1 -1
  19. package/dist/components/Include.cjs.map +1 -1
  20. package/dist/components/Include.d.cts +7 -0
  21. package/dist/components/Include.d.ts +7 -0
  22. package/dist/components/Include.js.map +1 -1
  23. package/dist/components/MDXComponents.cjs.map +1 -1
  24. package/dist/components/MDXComponents.d.cts +6 -0
  25. package/dist/components/MDXComponents.d.ts +6 -0
  26. package/dist/components/MDXComponents.js.map +1 -1
  27. package/dist/components/Routes.cjs +59 -0
  28. package/dist/components/Routes.cjs.map +1 -0
  29. package/dist/components/Routes.d.cts +34 -0
  30. package/dist/components/Routes.d.ts +34 -0
  31. package/dist/components/Routes.js +34 -0
  32. package/dist/components/Routes.js.map +1 -0
  33. package/dist/contribute.cjs.map +1 -1
  34. package/dist/contribute.d.cts +2 -0
  35. package/dist/contribute.d.ts +2 -0
  36. package/dist/contribute.js.map +1 -1
  37. package/dist/debug.cjs +168 -0
  38. package/dist/debug.cjs.map +1 -0
  39. package/dist/debug.d.cts +22 -0
  40. package/dist/debug.d.ts +22 -0
  41. package/dist/debug.js +141 -0
  42. package/dist/debug.js.map +1 -0
  43. package/dist/diagnostics.cjs.map +1 -1
  44. package/dist/diagnostics.d.cts +3 -0
  45. package/dist/diagnostics.d.ts +3 -0
  46. package/dist/diagnostics.js.map +1 -1
  47. package/dist/formFactor.cjs.map +1 -1
  48. package/dist/formFactor.d.cts +2 -0
  49. package/dist/formFactor.d.ts +2 -0
  50. package/dist/formFactor.js.map +1 -1
  51. package/dist/hooks.cjs +27 -28
  52. package/dist/hooks.cjs.map +1 -1
  53. package/dist/hooks.d.cts +39 -4
  54. package/dist/hooks.d.ts +39 -4
  55. package/dist/hooks.js +27 -29
  56. package/dist/hooks.js.map +1 -1
  57. package/dist/index.cjs +6 -0
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.d.cts +7 -4
  60. package/dist/index.d.ts +7 -4
  61. package/dist/index.js +3 -0
  62. package/dist/index.js.map +1 -1
  63. package/dist/irMarkers.cjs.map +1 -1
  64. package/dist/irMarkers.d.cts +1 -0
  65. package/dist/irMarkers.d.ts +1 -0
  66. package/dist/irMarkers.js.map +1 -1
  67. package/dist/llm.cjs.map +1 -1
  68. package/dist/llm.d.cts +5 -0
  69. package/dist/llm.d.ts +5 -0
  70. package/dist/llm.js.map +1 -1
  71. package/dist/loading.cjs +186 -0
  72. package/dist/loading.cjs.map +1 -0
  73. package/dist/loading.d.cts +48 -0
  74. package/dist/loading.d.ts +48 -0
  75. package/dist/loading.js +162 -0
  76. package/dist/loading.js.map +1 -0
  77. package/dist/mounts.cjs.map +1 -1
  78. package/dist/mounts.d.cts +3 -1
  79. package/dist/mounts.d.ts +3 -1
  80. package/dist/mounts.js.map +1 -1
  81. package/dist/netFetch.cjs.map +1 -1
  82. package/dist/netFetch.d.cts +2 -0
  83. package/dist/netFetch.d.ts +2 -0
  84. package/dist/netFetch.js.map +1 -1
  85. package/dist/onFsChange.cjs.map +1 -1
  86. package/dist/onFsChange.d.cts +1 -0
  87. package/dist/onFsChange.d.ts +1 -0
  88. package/dist/onFsChange.js.map +1 -1
  89. package/dist/protocolStream.cjs.map +1 -1
  90. package/dist/protocolStream.d.cts +3 -0
  91. package/dist/protocolStream.d.ts +3 -0
  92. package/dist/protocolStream.js.map +1 -1
  93. package/dist/ready.cjs.map +1 -1
  94. package/dist/ready.d.cts +7 -0
  95. package/dist/ready.d.ts +7 -0
  96. package/dist/ready.js.map +1 -1
  97. package/dist/routeMatch.cjs +72 -0
  98. package/dist/routeMatch.cjs.map +1 -0
  99. package/dist/routeMatch.d.cts +19 -0
  100. package/dist/routeMatch.d.ts +19 -0
  101. package/dist/routeMatch.js +46 -0
  102. package/dist/routeMatch.js.map +1 -0
  103. package/dist/routing.cjs +35 -14
  104. package/dist/routing.cjs.map +1 -1
  105. package/dist/routing.d.cts +33 -4
  106. package/dist/routing.d.ts +33 -4
  107. package/dist/routing.js +32 -14
  108. package/dist/routing.js.map +1 -1
  109. package/dist/runtime.cjs.map +1 -1
  110. package/dist/runtime.d.cts +1 -0
  111. package/dist/runtime.d.ts +1 -0
  112. package/dist/runtime.js.map +1 -1
  113. package/dist/sandboxTypes.cjs.map +1 -1
  114. package/dist/sandboxTypes.d.cts +30 -7
  115. package/dist/sandboxTypes.d.ts +30 -7
  116. package/dist/version.cjs +1 -1
  117. package/dist/version.cjs.map +1 -1
  118. package/dist/version.d.cts +1 -1
  119. package/dist/version.d.ts +1 -1
  120. package/dist/version.js +1 -1
  121. package/dist/version.js.map +1 -1
  122. package/package.json +6 -2
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks.ts"],"sourcesContent":["import { use, useEffect, useMemo, useState } from 'react';\nimport { TinkerableContext } from './TinkerableContext';\nimport { FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult } from './sandboxTypes';\n\nconst evaluateQueryFunction = (filesMetadata:FilesMetadata, queryFunction: MetadataQueryFunction):MetadataQueryResult => {\n try {\n return {result: queryFunction(filesMetadata)}\n } catch (e) {\n return {error: e}\n }\n}\n\nconst arraysEqual = <T>(a: T[], b:T[]):boolean => {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\nexport const useMetadataQuery = (queryFunction:MetadataQueryFunction) => {\n const {filesMetadata} = use(TinkerableContext);\n // we don't care if the metadata reference has changed, we only care about the output of queryFunction()\n const [queryResult, setQueryResult] = useState<MetadataQueryResult | null>(null);\n // any time the metadata object changes,\n // recalculate the query result and update the state if necessary\n useEffect(() => {\n setQueryResult(prevResult => {\n const newResult = evaluateQueryFunction(filesMetadata, queryFunction);\n if (!prevResult) {\n return newResult;\n }\n if (!('result' in newResult)) {\n return newResult;\n }\n if (!('result' in prevResult)) {\n return newResult;\n }\n return arraysEqual(prevResult.result, newResult.result) ? prevResult : newResult;\n })\n }, [filesMetadata, setQueryResult, queryFunction])\n return queryResult;\n}\n\nexport const useFileMetadata = (path: string): Metadata|null => {\n const {filesMetadata} = use(TinkerableContext);\n const result = useMemo(() => filesMetadata[path], [path, filesMetadata]);\n return result;\n}\n"],"mappings":"AAAA,SAAS,KAAK,WAAW,SAAS,gBAAgB;AAClD,SAAS,yBAAyB;AAGlC,MAAM,wBAAwB,CAAC,eAA6B,kBAA6D;AACvH,MAAI;AACF,WAAO,EAAC,QAAQ,cAAc,aAAa,EAAC;AAAA,EAC9C,SAAS,GAAG;AACV,WAAO,EAAC,OAAO,EAAC;AAAA,EAClB;AACF;AAEA,MAAM,cAAc,CAAI,GAAQ,MAAkB;AAChD,MAAI,EAAE,WAAW,EAAE,QAAQ;AACzB,WAAO;AAAA,EACT;AACA,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,QAAI,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,mBAAmB,CAAC,kBAAwC;AACvE,QAAM,EAAC,cAAa,IAAI,IAAI,iBAAiB;AAE7C,QAAM,CAAC,aAAa,cAAc,IAAI,SAAqC,IAAI;AAG/E,YAAU,MAAM;AACd,mBAAe,gBAAc;AAC3B,YAAM,YAAY,sBAAsB,eAAe,aAAa;AACpE,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,MACT;AACA,UAAI,EAAE,YAAY,YAAY;AAC5B,eAAO;AAAA,MACT;AACA,UAAI,EAAE,YAAY,aAAa;AAC7B,eAAO;AAAA,MACT;AACA,aAAO,YAAY,WAAW,QAAQ,UAAU,MAAM,IAAI,aAAa;AAAA,IACzE,CAAC;AAAA,EACH,GAAG,CAAC,eAAe,gBAAgB,aAAa,CAAC;AACjD,SAAO;AACT;AAEO,MAAM,kBAAkB,CAAC,SAAgC;AAC9D,QAAM,EAAC,cAAa,IAAI,IAAI,iBAAiB;AAC7C,QAAM,SAAS,QAAQ,MAAM,cAAc,IAAI,GAAG,CAAC,MAAM,aAAa,CAAC;AACvE,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/hooks.ts"],"sourcesContent":["import { use, useMemo, useRef } from 'react';\nimport { TinkerableContext } from './TinkerableContext';\nimport {\n FilesMetadata,\n Metadata,\n MetadataQueryEntry,\n MetadataQueryFunction,\n MetadataQueryResult,\n} from './sandboxTypes';\n\nconst entriesEqual = <T>(a: MetadataQueryEntry<T>[], b: MetadataQueryEntry<T>[]): boolean => {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n // Unchanged frontmatter keeps its object identity across `metadata-update`\n // merges, so an identity check on `meta` is a sound \"did this match change?\".\n if (a[i].path !== b[i].path || a[i].meta !== b[i].meta) {\n return false;\n }\n }\n return true;\n};\n\n/**\n * Query the file metadata store (MDX frontmatter) with a plain JS function.\n *\n * The query receives every file's frontmatter keyed by path and returns the paths\n * that match; the hook resolves each path back to its frontmatter and returns an\n * array of `{ path, meta }` entries so a single call gives you everything you\n * filtered on, with no second lookup. A throwing query is reported as `{ error }`\n * rather than crashing the render.\n *\n * The query runs synchronously during render (no empty first frame), and the\n * returned array keeps its identity while the matches are unchanged, so it is safe\n * to use directly in downstream `useMemo`/`useEffect` dependency arrays.\n *\n * Pass a type parameter to get typed frontmatter throughout:\n * ```ts\n * interface PostMeta { title: string; date: string; draft?: boolean }\n * const posts = useMetadataQuery<PostMeta>((files) =>\n * Object.entries(files)\n * .filter(([, m]) => !m.draft)\n * .sort(([, a], [, b]) => b.date.localeCompare(a.date))\n * .map(([path]) => path),\n * );\n * ```\n */\nexport const useMetadataQuery = <T = Metadata>(\n queryFunction: MetadataQueryFunction<T>,\n): MetadataQueryResult<T> => {\n const { filesMetadata } = use(TinkerableContext);\n const previous = useRef<MetadataQueryEntry<T>[]>([]);\n return useMemo<MetadataQueryResult<T>>(() => {\n const files = (filesMetadata ?? {}) as FilesMetadata<T>;\n let entries: MetadataQueryEntry<T>[];\n try {\n entries = queryFunction(files).map((path) => ({ path, meta: files[path] }));\n } catch (error) {\n return { error };\n }\n // Preserve the prior array reference when nothing matched differently.\n if (entriesEqual(entries, previous.current)) {\n return previous.current;\n }\n previous.current = entries;\n return entries;\n }, [filesMetadata, queryFunction]);\n};\n\n/**\n * Read one file's metadata (MDX frontmatter) by repo-relative path. Returns\n * `undefined` when the path has no metadata. Pass a type parameter for typed\n * field access.\n */\nexport const useFileMetadata = <T = Metadata>(path: string): T | undefined => {\n const { filesMetadata } = use(TinkerableContext);\n return useMemo(\n () => (filesMetadata ?? {})[path] as T | undefined,\n [path, filesMetadata],\n );\n};\n\n/**\n * The raw, reactive metadata store: a map from file path to frontmatter. The\n * escape hatch for apps that want to render their own index rather than express it\n * as a path-returning query. Pass a type parameter for typed frontmatter values.\n */\nexport const useAllMetadata = <T = Metadata>(): FilesMetadata<T> => {\n const { filesMetadata } = use(TinkerableContext);\n return (filesMetadata ?? {}) as FilesMetadata<T>;\n};\n"],"mappings":"AAAA,SAAS,KAAK,SAAS,cAAc;AACrC,SAAS,yBAAyB;AASlC,MAAM,eAAe,CAAI,GAA4B,MAAwC;AAC3F,MAAI,EAAE,WAAW,EAAE,QAAQ;AACzB,WAAO;AAAA,EACT;AACA,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AAGjC,QAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM;AACtD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AA0BO,MAAM,mBAAmB,CAC9B,kBAC2B;AAC3B,QAAM,EAAE,cAAc,IAAI,IAAI,iBAAiB;AAC/C,QAAM,WAAW,OAAgC,CAAC,CAAC;AACnD,SAAO,QAAgC,MAAM;AAC3C,UAAM,QAAS,iBAAiB,CAAC;AACjC,QAAI;AACJ,QAAI;AACF,gBAAU,cAAc,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IAC5E,SAAS,OAAO;AACd,aAAO,EAAE,MAAM;AAAA,IACjB;AAEA,QAAI,aAAa,SAAS,SAAS,OAAO,GAAG;AAC3C,aAAO,SAAS;AAAA,IAClB;AACA,aAAS,UAAU;AACnB,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,aAAa,CAAC;AACnC;AAOO,MAAM,kBAAkB,CAAe,SAAgC;AAC5E,QAAM,EAAE,cAAc,IAAI,IAAI,iBAAiB;AAC/C,SAAO;AAAA,IACL,OAAO,iBAAiB,CAAC,GAAG,IAAI;AAAA,IAChC,CAAC,MAAM,aAAa;AAAA,EACtB;AACF;AAOO,MAAM,iBAAiB,MAAsC;AAClE,QAAM,EAAE,cAAc,IAAI,IAAI,iBAAiB;AAC/C,SAAQ,iBAAiB,CAAC;AAC5B;","names":[]}
package/dist/index.cjs CHANGED
@@ -20,6 +20,7 @@ __reExport(index_exports, require("./routing"), module.exports);
20
20
  __reExport(index_exports, require("./boot"), module.exports);
21
21
  __reExport(index_exports, require("./components/Include"), module.exports);
22
22
  __reExport(index_exports, require("./components/MDXComponents"), module.exports);
23
+ __reExport(index_exports, require("./components/Routes"), module.exports);
23
24
  __reExport(index_exports, require("./hooks"), module.exports);
24
25
  __reExport(index_exports, require("./auth"), module.exports);
25
26
  __reExport(index_exports, require("./theme"), module.exports);
@@ -37,10 +38,12 @@ __reExport(index_exports, require("./secrets"), module.exports);
37
38
  __reExport(index_exports, require("./llm"), module.exports);
38
39
  __reExport(index_exports, require("./diagnostics"), module.exports);
39
40
  __reExport(index_exports, require("./onFsChange"), module.exports);
41
+ __reExport(index_exports, require("./debug"), module.exports);
40
42
  __reExport(index_exports, require("./tasks"), module.exports);
41
43
  __reExport(index_exports, require("./runtime"), module.exports);
42
44
  __reExport(index_exports, require("./irMarkers"), module.exports);
43
45
  __reExport(index_exports, require("./ready"), module.exports);
46
+ __reExport(index_exports, require("./loading"), module.exports);
44
47
  __reExport(index_exports, require("./protocolStream"), module.exports);
45
48
  __reExport(index_exports, require("./sandboxTypes"), module.exports);
46
49
  // Annotate the CommonJS export names for ESM import in node:
@@ -50,6 +53,7 @@ __reExport(index_exports, require("./sandboxTypes"), module.exports);
50
53
  ...require("./boot"),
51
54
  ...require("./components/Include"),
52
55
  ...require("./components/MDXComponents"),
56
+ ...require("./components/Routes"),
53
57
  ...require("./hooks"),
54
58
  ...require("./auth"),
55
59
  ...require("./theme"),
@@ -67,10 +71,12 @@ __reExport(index_exports, require("./sandboxTypes"), module.exports);
67
71
  ...require("./llm"),
68
72
  ...require("./diagnostics"),
69
73
  ...require("./onFsChange"),
74
+ ...require("./debug"),
70
75
  ...require("./tasks"),
71
76
  ...require("./runtime"),
72
77
  ...require("./irMarkers"),
73
78
  ...require("./ready"),
79
+ ...require("./loading"),
74
80
  ...require("./protocolStream"),
75
81
  ...require("./sandboxTypes")
76
82
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './onFsChange';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAIA,0BAAc,uCAJd;AAKA,0BAAc,oBALd;AAMA,0BAAc,mBANd;AAOA,0BAAc,oBAPd;AAQA,0BAAc,4BARd;AASA,0BAAc,qBATd;AAUA,0BAAc,yBAVd;AAWA,0BAAc,qBAXd;AAYA,0BAAc,qBAZd;AAaA,0BAAc,yBAbd;AAcA,0BAAc,sBAdd;AAeA,0BAAc,kBAfd;AAgBA,0BAAc,kBAhBd;AAiBA,0BAAc,uBAjBd;AAkBA,0BAAc,sBAlBd;AAmBA,0BAAc,kBAnBd;AAoBA,0BAAc,0BApBd;AAqBA,0BAAc,yBArBd;AAsBA,0BAAc,oBAtBd;AAuBA,0BAAc,sBAvBd;AAwBA,0BAAc,wBAxBd;AAyBA,0BAAc,oBAzBd;AA0BA,0BAAc,6BA1Bd;AA2BA,0BAAc,2BA3Bd;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\nexport * from './components/MDXComponents';\nexport * from './components/Routes';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './onFsChange';\nexport * from './debug';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAIA,0BAAc,uCAJd;AAKA,0BAAc,gCALd;AAMA,0BAAc,oBANd;AAOA,0BAAc,mBAPd;AAQA,0BAAc,oBARd;AASA,0BAAc,4BATd;AAUA,0BAAc,qBAVd;AAWA,0BAAc,yBAXd;AAYA,0BAAc,qBAZd;AAaA,0BAAc,qBAbd;AAcA,0BAAc,yBAdd;AAeA,0BAAc,sBAfd;AAgBA,0BAAc,kBAhBd;AAiBA,0BAAc,kBAjBd;AAkBA,0BAAc,uBAlBd;AAmBA,0BAAc,sBAnBd;AAoBA,0BAAc,kBApBd;AAqBA,0BAAc,0BArBd;AAsBA,0BAAc,yBAtBd;AAuBA,0BAAc,oBAvBd;AAwBA,0BAAc,oBAxBd;AAyBA,0BAAc,sBAzBd;AA0BA,0BAAc,wBA1Bd;AA2BA,0BAAc,oBA3Bd;AA4BA,0BAAc,sBA5Bd;AA6BA,0BAAc,6BA7Bd;AA8BA,0BAAc,2BA9Bd;","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,9 +1,10 @@
1
1
  export { MDXProvider, useMDXComponents } from './MDXProvider.cjs';
2
- export { AppliedRoutingRule, Router, applyRoutingRule, navigate, useTinkerableLink } from './routing.cjs';
3
- export { BootProps, DEFAULT_ROUTING_SPEC, TinkerableApp, boot } from './boot.cjs';
2
+ export { AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, useRoute, useRouteParams, useTinkerableLink } from './routing.cjs';
3
+ export { BootProps, CATCH_ALL_ROUTING_SPEC, DEFAULT_ROUTING_SPEC, TinkerableApp, boot } from './boot.cjs';
4
4
  export { Include, RenderExportedComponent, RenderExportedComponentContext, RenderFileContextType } from './components/Include.cjs';
5
5
  export { DEFAULT_MDX_COMPONENTS, InternalLink, Link } from './components/MDXComponents.cjs';
6
- export { useFileMetadata, useMetadataQuery } from './hooks.cjs';
6
+ export { Route, RouteProps, Routes } from './components/Routes.cjs';
7
+ export { useAllMetadata, useFileMetadata, useMetadataQuery } from './hooks.cjs';
7
8
  export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.cjs';
8
9
  export { HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme } from './theme.cjs';
9
10
  export { EditorContext, getEditorContext, onEditorContextChange, useEditorContext } from './editorContext.cjs';
@@ -20,12 +21,14 @@ export { SecretError, SecretGrant, SecretHints, SecretQuery, SecretType, SecretV
20
21
  export { ChatDelta, ChatFeatures, ChatMessage, ChatProviderInfo, ChatRequest, ChatResult, ChatRole, ChatStopReason, ContentPart, ToolDef, chat, describeChat, onChatProviderChange, useChatProvider } from './llm.cjs';
21
22
  export { BuildError, ConsoleEntry, ConsoleLevel, Diagnostics, DiagnosticsProvenance, getDiagnostics, onDiagnosticsChange, useDiagnostics } from './diagnostics.cjs';
22
23
  export { FsChange, getFsChange, onFsChange, useFsChange } from './onFsChange.cjs';
24
+ export { DebugLevel, debug, isDebugEnabled, log, useDebugEnabled } from './debug.cjs';
23
25
  export { DirCap, FileCap, TaskInput, cancelTask, capDir, capFile, completeTask, getTaskInput, invokeTask, useTaskInput } from './tasks.cjs';
24
26
  export { SDK_PROTOCOL_VERSION, SdkHandshake, announceHandshake, sdkHandshake } from './runtime.cjs';
25
27
  export { ForwardedMarker, IR_MARKERS, IrMarkerName, isAllowedMarkerName, isIrMarkerName, resolveInteractive, validateMarker } from './irMarkers.cjs';
26
28
  export { ReadyState, __resetReady, __setReadyDeps, getReadyState, onReady, reportReady } from './ready.cjs';
29
+ export { LOADING_TIMINGS, LoadingRegion, Skeleton, SkeletonArchetype, SkeletonRow, Spinner } from './loading.cjs';
27
30
  export { StreamError, StreamFrame, StreamTransport, consumeStream, protocolStream } from './protocolStream.cjs';
28
- export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.cjs';
31
+ export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryEntry, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.cjs';
29
32
  export { ImmediatelyRunGlobal, getHostRuntime } from './hostRuntime.cjs';
30
33
  export { SDK_VERSION } from './version.cjs';
31
34
  import 'react';
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  export { MDXProvider, useMDXComponents } from './MDXProvider.js';
2
- export { AppliedRoutingRule, Router, applyRoutingRule, navigate, useTinkerableLink } from './routing.js';
3
- export { BootProps, DEFAULT_ROUTING_SPEC, TinkerableApp, boot } from './boot.js';
2
+ export { AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, useRoute, useRouteParams, useTinkerableLink } from './routing.js';
3
+ export { BootProps, CATCH_ALL_ROUTING_SPEC, DEFAULT_ROUTING_SPEC, TinkerableApp, boot } from './boot.js';
4
4
  export { Include, RenderExportedComponent, RenderExportedComponentContext, RenderFileContextType } from './components/Include.js';
5
5
  export { DEFAULT_MDX_COMPONENTS, InternalLink, Link } from './components/MDXComponents.js';
6
- export { useFileMetadata, useMetadataQuery } from './hooks.js';
6
+ export { Route, RouteProps, Routes } from './components/Routes.js';
7
+ export { useAllMetadata, useFileMetadata, useMetadataQuery } from './hooks.js';
7
8
  export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.js';
8
9
  export { HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme } from './theme.js';
9
10
  export { EditorContext, getEditorContext, onEditorContextChange, useEditorContext } from './editorContext.js';
@@ -20,12 +21,14 @@ export { SecretError, SecretGrant, SecretHints, SecretQuery, SecretType, SecretV
20
21
  export { ChatDelta, ChatFeatures, ChatMessage, ChatProviderInfo, ChatRequest, ChatResult, ChatRole, ChatStopReason, ContentPart, ToolDef, chat, describeChat, onChatProviderChange, useChatProvider } from './llm.js';
21
22
  export { BuildError, ConsoleEntry, ConsoleLevel, Diagnostics, DiagnosticsProvenance, getDiagnostics, onDiagnosticsChange, useDiagnostics } from './diagnostics.js';
22
23
  export { FsChange, getFsChange, onFsChange, useFsChange } from './onFsChange.js';
24
+ export { DebugLevel, debug, isDebugEnabled, log, useDebugEnabled } from './debug.js';
23
25
  export { DirCap, FileCap, TaskInput, cancelTask, capDir, capFile, completeTask, getTaskInput, invokeTask, useTaskInput } from './tasks.js';
24
26
  export { SDK_PROTOCOL_VERSION, SdkHandshake, announceHandshake, sdkHandshake } from './runtime.js';
25
27
  export { ForwardedMarker, IR_MARKERS, IrMarkerName, isAllowedMarkerName, isIrMarkerName, resolveInteractive, validateMarker } from './irMarkers.js';
26
28
  export { ReadyState, __resetReady, __setReadyDeps, getReadyState, onReady, reportReady } from './ready.js';
29
+ export { LOADING_TIMINGS, LoadingRegion, Skeleton, SkeletonArchetype, SkeletonRow, Spinner } from './loading.js';
27
30
  export { StreamError, StreamFrame, StreamTransport, consumeStream, protocolStream } from './protocolStream.js';
28
- export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.js';
31
+ export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryEntry, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.js';
29
32
  export { ImmediatelyRunGlobal, getHostRuntime } from './hostRuntime.js';
30
33
  export { SDK_VERSION } from './version.js';
31
34
  import 'react';
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export * from "./routing";
3
3
  export * from "./boot";
4
4
  export * from "./components/Include";
5
5
  export * from "./components/MDXComponents";
6
+ export * from "./components/Routes";
6
7
  export * from "./hooks";
7
8
  export * from "./auth";
8
9
  export * from "./theme";
@@ -20,10 +21,12 @@ export * from "./secrets";
20
21
  export * from "./llm";
21
22
  export * from "./diagnostics";
22
23
  export * from "./onFsChange";
24
+ export * from "./debug";
23
25
  export * from "./tasks";
24
26
  export * from "./runtime";
25
27
  export * from "./irMarkers";
26
28
  export * from "./ready";
29
+ export * from "./loading";
27
30
  export * from "./protocolStream";
28
31
  export * from "./sandboxTypes";
29
32
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './onFsChange';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\nexport * from './components/MDXComponents';\nexport * from './components/Routes';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './onFsChange';\nexport * from './debug';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/irMarkers.ts"],"sourcesContent":["// The `ir.*` load-profiling marker vocabulary + the host-side allowlist + the\n// `ir.interactive` precedence rule (LOAD_PROFILING_SPEC §3/§3.1, R3-46).\n//\n// This module is PURE and dependency-free on purpose: the spec (§3.1) requires the\n// host's vocabulary allowlist to be MIRRORED from this same definition (\"additions\n// to the vocabulary are spec amendments, mirrored in the host allowlist in the same\n// change\"). Keeping the table + validator here, with no transport/React imports,\n// lets the sandbox side (this SDK) and the host (site-main, its own mirrored copy)\n// share an identical contract that is unit-tested in both places.\n\n/**\n * Each `ir.*` marker name → the attribute keys its payload may carry (the §3\n * table). A forwarded marker is accepted only if BOTH its name is defined here AND\n * every attribute key it carries is in that marker's allowed set (LP-5). An empty\n * array means \"no attributes\" (a bare mark).\n */\nexport const IR_MARKERS = {\n \"ir.open\": [\"url\", \"provider\", \"ns\", \"repo\", \"ref\", \"refKind\"],\n \"ir.fetch\": [\"source\", \"bytes\", \"requestCount\", \"cacheHit\", \"httpStatus\"],\n \"ir.mount\": [\"phantomCount\", \"writablePrimed\"],\n \"ir.sandbox.boot\": [],\n \"ir.transpile\": [\"moduleCount\", \"cacheHit\", \"bytesIn\", \"bytesOut\"],\n \"ir.deps\": [\"depCount\", \"bytes\", \"requestCount\", \"cacheHit\", \"cdn\"],\n \"ir.eval\": [\"moduleCount\"],\n \"ir.fmp\": [],\n \"ir.interactive\": [\"cold\"],\n \"ir.verify\": [\"result\", \"blocking\"],\n \"ir.refresh\": [\"bytes\"],\n} as const;\n\nexport type IrMarkerName = keyof typeof IR_MARKERS;\n\n// Per-module / per-dep sub-marks (§3): a defined aggregate plus a `[…]` selector,\n// e.g. `ir.transpile.mod[/src/App.tsx]` or `ir.deps.pkg[react@18.2.0]`. A sub-mark\n// inherits its aggregate's attribute schema.\nconst SUBMARK_RE = /^(ir\\.transpile\\.mod|ir\\.deps\\.pkg)\\[[^\\]]+\\]$/;\nconst submarkAggregate = (name: string): IrMarkerName | null =>\n name.startsWith(\"ir.transpile.mod\") ? \"ir.transpile\" : name.startsWith(\"ir.deps.pkg\") ? \"ir.deps\" : null;\n\n/** Is `name` a defined top-level `ir.*` marker (not a sub-mark)? */\nexport const isIrMarkerName = (name: string): name is IrMarkerName =>\n Object.prototype.hasOwnProperty.call(IR_MARKERS, name);\n\n/** Is `name` an accepted marker name — a defined top-level marker OR a recognized\n * per-module/per-dep sub-mark? */\nexport const isAllowedMarkerName = (name: string): boolean =>\n isIrMarkerName(name) || SUBMARK_RE.test(name);\n\n/** A marker forwarded across the origin boundary (§3.2): a name, the sandbox-side\n * `performance.now()` timestamp, and the optional attribute payload. */\nexport interface ForwardedMarker {\n name: string;\n /** Sandbox-relative timestamp (`performance.now()`) at emission (§3.2). */\n at: number;\n attrs?: Record<string, unknown>;\n}\n\n/**\n * The LP-5 vocabulary allowlist (pure). Accept a forwarded marker ONLY if its name\n * is in the vocabulary AND every attribute key is in that marker's schema. An\n * unknown name — or a defined name carrying an out-of-schema attribute key — is\n * DROPPED (returns `null`), never recorded. This is the gate against an untrusted\n * sandbox minting arbitrary names/values into the host timeline (an injection\n * surface for dashboards / the deferred RUM endpoint). Sub-marks inherit their\n * aggregate's schema.\n */\nexport function validateMarker(m: ForwardedMarker | null | undefined): ForwardedMarker | null {\n if (!m || typeof m.name !== \"string\") return null;\n if (typeof m.at !== \"number\" || !Number.isFinite(m.at)) return null;\n if (!isAllowedMarkerName(m.name)) return null;\n const base: IrMarkerName = isIrMarkerName(m.name) ? m.name : submarkAggregate(m.name)!;\n const allowed: readonly string[] = IR_MARKERS[base];\n const attrs = m.attrs;\n if (attrs !== undefined) {\n if (typeof attrs !== \"object\" || attrs === null) return null;\n for (const key of Object.keys(attrs)) {\n if (!allowed.includes(key)) return null; // out-of-schema attribute → drop the whole marker\n }\n }\n return { name: m.name, at: m.at, ...(attrs !== undefined ? { attrs } : {}) };\n}\n\n/**\n * `ir.interactive = max(rootRenderCommit, reportReady)` (LP2-3). An app-called\n * `reportReady()` may only DELAY interactive — never advance it before the root\n * render commits. A `reportReady()` that fires early is recorded but takes effect\n * at the commit; if the app never reports, the commit alone stands. Budgets bind to\n * the later of the two, so an app can't game its budget by declaring itself ready\n * before it has rendered anything. PURE.\n */\nexport function resolveInteractive(rootRenderCommitAt: number, reportReadyAt?: number): number {\n if (reportReadyAt === undefined) return rootRenderCommitAt;\n return Math.max(rootRenderCommitAt, reportReadyAt);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBO,MAAM,aAAa;AAAA,EACxB,WAAW,CAAC,OAAO,YAAY,MAAM,QAAQ,OAAO,SAAS;AAAA,EAC7D,YAAY,CAAC,UAAU,SAAS,gBAAgB,YAAY,YAAY;AAAA,EACxE,YAAY,CAAC,gBAAgB,gBAAgB;AAAA,EAC7C,mBAAmB,CAAC;AAAA,EACpB,gBAAgB,CAAC,eAAe,YAAY,WAAW,UAAU;AAAA,EACjE,WAAW,CAAC,YAAY,SAAS,gBAAgB,YAAY,KAAK;AAAA,EAClE,WAAW,CAAC,aAAa;AAAA,EACzB,UAAU,CAAC;AAAA,EACX,kBAAkB,CAAC,MAAM;AAAA,EACzB,aAAa,CAAC,UAAU,UAAU;AAAA,EAClC,cAAc,CAAC,OAAO;AACxB;AAOA,MAAM,aAAa;AACnB,MAAM,mBAAmB,CAAC,SACxB,KAAK,WAAW,kBAAkB,IAAI,iBAAiB,KAAK,WAAW,aAAa,IAAI,YAAY;AAG/F,MAAM,iBAAiB,CAAC,SAC7B,OAAO,UAAU,eAAe,KAAK,YAAY,IAAI;AAIhD,MAAM,sBAAsB,CAAC,SAClC,eAAe,IAAI,KAAK,WAAW,KAAK,IAAI;AAoBvC,SAAS,eAAe,GAA+D;AAC5F,MAAI,CAAC,KAAK,OAAO,EAAE,SAAS,SAAU,QAAO;AAC7C,MAAI,OAAO,EAAE,OAAO,YAAY,CAAC,OAAO,SAAS,EAAE,EAAE,EAAG,QAAO;AAC/D,MAAI,CAAC,oBAAoB,EAAE,IAAI,EAAG,QAAO;AACzC,QAAM,OAAqB,eAAe,EAAE,IAAI,IAAI,EAAE,OAAO,iBAAiB,EAAE,IAAI;AACpF,QAAM,UAA6B,WAAW,IAAI;AAClD,QAAM,QAAQ,EAAE;AAChB,MAAI,UAAU,QAAW;AACvB,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,eAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAI,CAAC,QAAQ,SAAS,GAAG,EAAG,QAAO;AAAA,IACrC;AAAA,EACF;AACA,SAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC,EAAG;AAC7E;AAUO,SAAS,mBAAmB,oBAA4B,eAAgC;AAC7F,MAAI,kBAAkB,OAAW,QAAO;AACxC,SAAO,KAAK,IAAI,oBAAoB,aAAa;AACnD;","names":[]}
1
+ {"version":3,"sources":["../src/irMarkers.ts"],"sourcesContent":["// The `ir.*` load-profiling marker vocabulary + the host-side allowlist + the\n// `ir.interactive` precedence rule (LOAD_PROFILING_SPEC §3/§3.1, R3-46).\n//\n// This module is PURE and dependency-free on purpose: the spec (§3.1) requires the\n// host's vocabulary allowlist to be MIRRORED from this same definition (\"additions\n// to the vocabulary are spec amendments, mirrored in the host allowlist in the same\n// change\"). Keeping the table + validator here, with no transport/React imports,\n// lets the sandbox side (this SDK) and the host (site-main, its own mirrored copy)\n// share an identical contract that is unit-tested in both places.\n\n/**\n * Each `ir.*` marker name → the attribute keys its payload may carry (the §3\n * table). A forwarded marker is accepted only if BOTH its name is defined here AND\n * every attribute key it carries is in that marker's allowed set (LP-5). An empty\n * array means \"no attributes\" (a bare mark).\n */\nexport const IR_MARKERS = {\n \"ir.open\": [\"url\", \"provider\", \"ns\", \"repo\", \"ref\", \"refKind\"],\n \"ir.fetch\": [\"source\", \"bytes\", \"requestCount\", \"cacheHit\", \"httpStatus\"],\n \"ir.mount\": [\"phantomCount\", \"writablePrimed\"],\n \"ir.sandbox.boot\": [],\n \"ir.transpile\": [\"moduleCount\", \"cacheHit\", \"bytesIn\", \"bytesOut\"],\n \"ir.deps\": [\"depCount\", \"bytes\", \"requestCount\", \"cacheHit\", \"cdn\"],\n \"ir.eval\": [\"moduleCount\"],\n \"ir.fmp\": [],\n \"ir.interactive\": [\"cold\"],\n \"ir.verify\": [\"result\", \"blocking\"],\n \"ir.refresh\": [\"bytes\"],\n} as const;\n\n/** A canonical `ir.*` load-profiling marker name (a key of {@link IR_MARKERS}). */\nexport type IrMarkerName = keyof typeof IR_MARKERS;\n\n// Per-module / per-dep sub-marks (§3): a defined aggregate plus a `[…]` selector,\n// e.g. `ir.transpile.mod[/src/App.tsx]` or `ir.deps.pkg[react@18.2.0]`. A sub-mark\n// inherits its aggregate's attribute schema.\nconst SUBMARK_RE = /^(ir\\.transpile\\.mod|ir\\.deps\\.pkg)\\[[^\\]]+\\]$/;\nconst submarkAggregate = (name: string): IrMarkerName | null =>\n name.startsWith(\"ir.transpile.mod\") ? \"ir.transpile\" : name.startsWith(\"ir.deps.pkg\") ? \"ir.deps\" : null;\n\n/** Is `name` a defined top-level `ir.*` marker (not a sub-mark)? */\nexport const isIrMarkerName = (name: string): name is IrMarkerName =>\n Object.prototype.hasOwnProperty.call(IR_MARKERS, name);\n\n/** Is `name` an accepted marker name — a defined top-level marker OR a recognized\n * per-module/per-dep sub-mark? */\nexport const isAllowedMarkerName = (name: string): boolean =>\n isIrMarkerName(name) || SUBMARK_RE.test(name);\n\n/** A marker forwarded across the origin boundary (§3.2): a name, the sandbox-side\n * `performance.now()` timestamp, and the optional attribute payload. */\nexport interface ForwardedMarker {\n name: string;\n /** Sandbox-relative timestamp (`performance.now()`) at emission (§3.2). */\n at: number;\n attrs?: Record<string, unknown>;\n}\n\n/**\n * The LP-5 vocabulary allowlist (pure). Accept a forwarded marker ONLY if its name\n * is in the vocabulary AND every attribute key is in that marker's schema. An\n * unknown name — or a defined name carrying an out-of-schema attribute key — is\n * DROPPED (returns `null`), never recorded. This is the gate against an untrusted\n * sandbox minting arbitrary names/values into the host timeline (an injection\n * surface for dashboards / the deferred RUM endpoint). Sub-marks inherit their\n * aggregate's schema.\n */\nexport function validateMarker(m: ForwardedMarker | null | undefined): ForwardedMarker | null {\n if (!m || typeof m.name !== \"string\") return null;\n if (typeof m.at !== \"number\" || !Number.isFinite(m.at)) return null;\n if (!isAllowedMarkerName(m.name)) return null;\n const base: IrMarkerName = isIrMarkerName(m.name) ? m.name : submarkAggregate(m.name)!;\n const allowed: readonly string[] = IR_MARKERS[base];\n const attrs = m.attrs;\n if (attrs !== undefined) {\n if (typeof attrs !== \"object\" || attrs === null) return null;\n for (const key of Object.keys(attrs)) {\n if (!allowed.includes(key)) return null; // out-of-schema attribute → drop the whole marker\n }\n }\n return { name: m.name, at: m.at, ...(attrs !== undefined ? { attrs } : {}) };\n}\n\n/**\n * `ir.interactive = max(rootRenderCommit, reportReady)` (LP2-3). An app-called\n * `reportReady()` may only DELAY interactive — never advance it before the root\n * render commits. A `reportReady()` that fires early is recorded but takes effect\n * at the commit; if the app never reports, the commit alone stands. Budgets bind to\n * the later of the two, so an app can't game its budget by declaring itself ready\n * before it has rendered anything. PURE.\n */\nexport function resolveInteractive(rootRenderCommitAt: number, reportReadyAt?: number): number {\n if (reportReadyAt === undefined) return rootRenderCommitAt;\n return Math.max(rootRenderCommitAt, reportReadyAt);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBO,MAAM,aAAa;AAAA,EACxB,WAAW,CAAC,OAAO,YAAY,MAAM,QAAQ,OAAO,SAAS;AAAA,EAC7D,YAAY,CAAC,UAAU,SAAS,gBAAgB,YAAY,YAAY;AAAA,EACxE,YAAY,CAAC,gBAAgB,gBAAgB;AAAA,EAC7C,mBAAmB,CAAC;AAAA,EACpB,gBAAgB,CAAC,eAAe,YAAY,WAAW,UAAU;AAAA,EACjE,WAAW,CAAC,YAAY,SAAS,gBAAgB,YAAY,KAAK;AAAA,EAClE,WAAW,CAAC,aAAa;AAAA,EACzB,UAAU,CAAC;AAAA,EACX,kBAAkB,CAAC,MAAM;AAAA,EACzB,aAAa,CAAC,UAAU,UAAU;AAAA,EAClC,cAAc,CAAC,OAAO;AACxB;AAQA,MAAM,aAAa;AACnB,MAAM,mBAAmB,CAAC,SACxB,KAAK,WAAW,kBAAkB,IAAI,iBAAiB,KAAK,WAAW,aAAa,IAAI,YAAY;AAG/F,MAAM,iBAAiB,CAAC,SAC7B,OAAO,UAAU,eAAe,KAAK,YAAY,IAAI;AAIhD,MAAM,sBAAsB,CAAC,SAClC,eAAe,IAAI,KAAK,WAAW,KAAK,IAAI;AAoBvC,SAAS,eAAe,GAA+D;AAC5F,MAAI,CAAC,KAAK,OAAO,EAAE,SAAS,SAAU,QAAO;AAC7C,MAAI,OAAO,EAAE,OAAO,YAAY,CAAC,OAAO,SAAS,EAAE,EAAE,EAAG,QAAO;AAC/D,MAAI,CAAC,oBAAoB,EAAE,IAAI,EAAG,QAAO;AACzC,QAAM,OAAqB,eAAe,EAAE,IAAI,IAAI,EAAE,OAAO,iBAAiB,EAAE,IAAI;AACpF,QAAM,UAA6B,WAAW,IAAI;AAClD,QAAM,QAAQ,EAAE;AAChB,MAAI,UAAU,QAAW;AACvB,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,eAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAI,CAAC,QAAQ,SAAS,GAAG,EAAG,QAAO;AAAA,IACrC;AAAA,EACF;AACA,SAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC,EAAG;AAC7E;AAUO,SAAS,mBAAmB,oBAA4B,eAAgC;AAC7F,MAAI,kBAAkB,OAAW,QAAO;AACxC,SAAO,KAAK,IAAI,oBAAoB,aAAa;AACnD;","names":[]}
@@ -17,6 +17,7 @@ declare const IR_MARKERS: {
17
17
  readonly "ir.verify": readonly ["result", "blocking"];
18
18
  readonly "ir.refresh": readonly ["bytes"];
19
19
  };
20
+ /** A canonical `ir.*` load-profiling marker name (a key of {@link IR_MARKERS}). */
20
21
  type IrMarkerName = keyof typeof IR_MARKERS;
21
22
  /** Is `name` a defined top-level `ir.*` marker (not a sub-mark)? */
22
23
  declare const isIrMarkerName: (name: string) => name is IrMarkerName;
@@ -17,6 +17,7 @@ declare const IR_MARKERS: {
17
17
  readonly "ir.verify": readonly ["result", "blocking"];
18
18
  readonly "ir.refresh": readonly ["bytes"];
19
19
  };
20
+ /** A canonical `ir.*` load-profiling marker name (a key of {@link IR_MARKERS}). */
20
21
  type IrMarkerName = keyof typeof IR_MARKERS;
21
22
  /** Is `name` a defined top-level `ir.*` marker (not a sub-mark)? */
22
23
  declare const isIrMarkerName: (name: string) => name is IrMarkerName;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/irMarkers.ts"],"sourcesContent":["// The `ir.*` load-profiling marker vocabulary + the host-side allowlist + the\n// `ir.interactive` precedence rule (LOAD_PROFILING_SPEC §3/§3.1, R3-46).\n//\n// This module is PURE and dependency-free on purpose: the spec (§3.1) requires the\n// host's vocabulary allowlist to be MIRRORED from this same definition (\"additions\n// to the vocabulary are spec amendments, mirrored in the host allowlist in the same\n// change\"). Keeping the table + validator here, with no transport/React imports,\n// lets the sandbox side (this SDK) and the host (site-main, its own mirrored copy)\n// share an identical contract that is unit-tested in both places.\n\n/**\n * Each `ir.*` marker name → the attribute keys its payload may carry (the §3\n * table). A forwarded marker is accepted only if BOTH its name is defined here AND\n * every attribute key it carries is in that marker's allowed set (LP-5). An empty\n * array means \"no attributes\" (a bare mark).\n */\nexport const IR_MARKERS = {\n \"ir.open\": [\"url\", \"provider\", \"ns\", \"repo\", \"ref\", \"refKind\"],\n \"ir.fetch\": [\"source\", \"bytes\", \"requestCount\", \"cacheHit\", \"httpStatus\"],\n \"ir.mount\": [\"phantomCount\", \"writablePrimed\"],\n \"ir.sandbox.boot\": [],\n \"ir.transpile\": [\"moduleCount\", \"cacheHit\", \"bytesIn\", \"bytesOut\"],\n \"ir.deps\": [\"depCount\", \"bytes\", \"requestCount\", \"cacheHit\", \"cdn\"],\n \"ir.eval\": [\"moduleCount\"],\n \"ir.fmp\": [],\n \"ir.interactive\": [\"cold\"],\n \"ir.verify\": [\"result\", \"blocking\"],\n \"ir.refresh\": [\"bytes\"],\n} as const;\n\nexport type IrMarkerName = keyof typeof IR_MARKERS;\n\n// Per-module / per-dep sub-marks (§3): a defined aggregate plus a `[…]` selector,\n// e.g. `ir.transpile.mod[/src/App.tsx]` or `ir.deps.pkg[react@18.2.0]`. A sub-mark\n// inherits its aggregate's attribute schema.\nconst SUBMARK_RE = /^(ir\\.transpile\\.mod|ir\\.deps\\.pkg)\\[[^\\]]+\\]$/;\nconst submarkAggregate = (name: string): IrMarkerName | null =>\n name.startsWith(\"ir.transpile.mod\") ? \"ir.transpile\" : name.startsWith(\"ir.deps.pkg\") ? \"ir.deps\" : null;\n\n/** Is `name` a defined top-level `ir.*` marker (not a sub-mark)? */\nexport const isIrMarkerName = (name: string): name is IrMarkerName =>\n Object.prototype.hasOwnProperty.call(IR_MARKERS, name);\n\n/** Is `name` an accepted marker name — a defined top-level marker OR a recognized\n * per-module/per-dep sub-mark? */\nexport const isAllowedMarkerName = (name: string): boolean =>\n isIrMarkerName(name) || SUBMARK_RE.test(name);\n\n/** A marker forwarded across the origin boundary (§3.2): a name, the sandbox-side\n * `performance.now()` timestamp, and the optional attribute payload. */\nexport interface ForwardedMarker {\n name: string;\n /** Sandbox-relative timestamp (`performance.now()`) at emission (§3.2). */\n at: number;\n attrs?: Record<string, unknown>;\n}\n\n/**\n * The LP-5 vocabulary allowlist (pure). Accept a forwarded marker ONLY if its name\n * is in the vocabulary AND every attribute key is in that marker's schema. An\n * unknown name — or a defined name carrying an out-of-schema attribute key — is\n * DROPPED (returns `null`), never recorded. This is the gate against an untrusted\n * sandbox minting arbitrary names/values into the host timeline (an injection\n * surface for dashboards / the deferred RUM endpoint). Sub-marks inherit their\n * aggregate's schema.\n */\nexport function validateMarker(m: ForwardedMarker | null | undefined): ForwardedMarker | null {\n if (!m || typeof m.name !== \"string\") return null;\n if (typeof m.at !== \"number\" || !Number.isFinite(m.at)) return null;\n if (!isAllowedMarkerName(m.name)) return null;\n const base: IrMarkerName = isIrMarkerName(m.name) ? m.name : submarkAggregate(m.name)!;\n const allowed: readonly string[] = IR_MARKERS[base];\n const attrs = m.attrs;\n if (attrs !== undefined) {\n if (typeof attrs !== \"object\" || attrs === null) return null;\n for (const key of Object.keys(attrs)) {\n if (!allowed.includes(key)) return null; // out-of-schema attribute → drop the whole marker\n }\n }\n return { name: m.name, at: m.at, ...(attrs !== undefined ? { attrs } : {}) };\n}\n\n/**\n * `ir.interactive = max(rootRenderCommit, reportReady)` (LP2-3). An app-called\n * `reportReady()` may only DELAY interactive — never advance it before the root\n * render commits. A `reportReady()` that fires early is recorded but takes effect\n * at the commit; if the app never reports, the commit alone stands. Budgets bind to\n * the later of the two, so an app can't game its budget by declaring itself ready\n * before it has rendered anything. PURE.\n */\nexport function resolveInteractive(rootRenderCommitAt: number, reportReadyAt?: number): number {\n if (reportReadyAt === undefined) return rootRenderCommitAt;\n return Math.max(rootRenderCommitAt, reportReadyAt);\n}\n"],"mappings":"AAgBO,MAAM,aAAa;AAAA,EACxB,WAAW,CAAC,OAAO,YAAY,MAAM,QAAQ,OAAO,SAAS;AAAA,EAC7D,YAAY,CAAC,UAAU,SAAS,gBAAgB,YAAY,YAAY;AAAA,EACxE,YAAY,CAAC,gBAAgB,gBAAgB;AAAA,EAC7C,mBAAmB,CAAC;AAAA,EACpB,gBAAgB,CAAC,eAAe,YAAY,WAAW,UAAU;AAAA,EACjE,WAAW,CAAC,YAAY,SAAS,gBAAgB,YAAY,KAAK;AAAA,EAClE,WAAW,CAAC,aAAa;AAAA,EACzB,UAAU,CAAC;AAAA,EACX,kBAAkB,CAAC,MAAM;AAAA,EACzB,aAAa,CAAC,UAAU,UAAU;AAAA,EAClC,cAAc,CAAC,OAAO;AACxB;AAOA,MAAM,aAAa;AACnB,MAAM,mBAAmB,CAAC,SACxB,KAAK,WAAW,kBAAkB,IAAI,iBAAiB,KAAK,WAAW,aAAa,IAAI,YAAY;AAG/F,MAAM,iBAAiB,CAAC,SAC7B,OAAO,UAAU,eAAe,KAAK,YAAY,IAAI;AAIhD,MAAM,sBAAsB,CAAC,SAClC,eAAe,IAAI,KAAK,WAAW,KAAK,IAAI;AAoBvC,SAAS,eAAe,GAA+D;AAC5F,MAAI,CAAC,KAAK,OAAO,EAAE,SAAS,SAAU,QAAO;AAC7C,MAAI,OAAO,EAAE,OAAO,YAAY,CAAC,OAAO,SAAS,EAAE,EAAE,EAAG,QAAO;AAC/D,MAAI,CAAC,oBAAoB,EAAE,IAAI,EAAG,QAAO;AACzC,QAAM,OAAqB,eAAe,EAAE,IAAI,IAAI,EAAE,OAAO,iBAAiB,EAAE,IAAI;AACpF,QAAM,UAA6B,WAAW,IAAI;AAClD,QAAM,QAAQ,EAAE;AAChB,MAAI,UAAU,QAAW;AACvB,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,eAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAI,CAAC,QAAQ,SAAS,GAAG,EAAG,QAAO;AAAA,IACrC;AAAA,EACF;AACA,SAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC,EAAG;AAC7E;AAUO,SAAS,mBAAmB,oBAA4B,eAAgC;AAC7F,MAAI,kBAAkB,OAAW,QAAO;AACxC,SAAO,KAAK,IAAI,oBAAoB,aAAa;AACnD;","names":[]}
1
+ {"version":3,"sources":["../src/irMarkers.ts"],"sourcesContent":["// The `ir.*` load-profiling marker vocabulary + the host-side allowlist + the\n// `ir.interactive` precedence rule (LOAD_PROFILING_SPEC §3/§3.1, R3-46).\n//\n// This module is PURE and dependency-free on purpose: the spec (§3.1) requires the\n// host's vocabulary allowlist to be MIRRORED from this same definition (\"additions\n// to the vocabulary are spec amendments, mirrored in the host allowlist in the same\n// change\"). Keeping the table + validator here, with no transport/React imports,\n// lets the sandbox side (this SDK) and the host (site-main, its own mirrored copy)\n// share an identical contract that is unit-tested in both places.\n\n/**\n * Each `ir.*` marker name → the attribute keys its payload may carry (the §3\n * table). A forwarded marker is accepted only if BOTH its name is defined here AND\n * every attribute key it carries is in that marker's allowed set (LP-5). An empty\n * array means \"no attributes\" (a bare mark).\n */\nexport const IR_MARKERS = {\n \"ir.open\": [\"url\", \"provider\", \"ns\", \"repo\", \"ref\", \"refKind\"],\n \"ir.fetch\": [\"source\", \"bytes\", \"requestCount\", \"cacheHit\", \"httpStatus\"],\n \"ir.mount\": [\"phantomCount\", \"writablePrimed\"],\n \"ir.sandbox.boot\": [],\n \"ir.transpile\": [\"moduleCount\", \"cacheHit\", \"bytesIn\", \"bytesOut\"],\n \"ir.deps\": [\"depCount\", \"bytes\", \"requestCount\", \"cacheHit\", \"cdn\"],\n \"ir.eval\": [\"moduleCount\"],\n \"ir.fmp\": [],\n \"ir.interactive\": [\"cold\"],\n \"ir.verify\": [\"result\", \"blocking\"],\n \"ir.refresh\": [\"bytes\"],\n} as const;\n\n/** A canonical `ir.*` load-profiling marker name (a key of {@link IR_MARKERS}). */\nexport type IrMarkerName = keyof typeof IR_MARKERS;\n\n// Per-module / per-dep sub-marks (§3): a defined aggregate plus a `[…]` selector,\n// e.g. `ir.transpile.mod[/src/App.tsx]` or `ir.deps.pkg[react@18.2.0]`. A sub-mark\n// inherits its aggregate's attribute schema.\nconst SUBMARK_RE = /^(ir\\.transpile\\.mod|ir\\.deps\\.pkg)\\[[^\\]]+\\]$/;\nconst submarkAggregate = (name: string): IrMarkerName | null =>\n name.startsWith(\"ir.transpile.mod\") ? \"ir.transpile\" : name.startsWith(\"ir.deps.pkg\") ? \"ir.deps\" : null;\n\n/** Is `name` a defined top-level `ir.*` marker (not a sub-mark)? */\nexport const isIrMarkerName = (name: string): name is IrMarkerName =>\n Object.prototype.hasOwnProperty.call(IR_MARKERS, name);\n\n/** Is `name` an accepted marker name — a defined top-level marker OR a recognized\n * per-module/per-dep sub-mark? */\nexport const isAllowedMarkerName = (name: string): boolean =>\n isIrMarkerName(name) || SUBMARK_RE.test(name);\n\n/** A marker forwarded across the origin boundary (§3.2): a name, the sandbox-side\n * `performance.now()` timestamp, and the optional attribute payload. */\nexport interface ForwardedMarker {\n name: string;\n /** Sandbox-relative timestamp (`performance.now()`) at emission (§3.2). */\n at: number;\n attrs?: Record<string, unknown>;\n}\n\n/**\n * The LP-5 vocabulary allowlist (pure). Accept a forwarded marker ONLY if its name\n * is in the vocabulary AND every attribute key is in that marker's schema. An\n * unknown name — or a defined name carrying an out-of-schema attribute key — is\n * DROPPED (returns `null`), never recorded. This is the gate against an untrusted\n * sandbox minting arbitrary names/values into the host timeline (an injection\n * surface for dashboards / the deferred RUM endpoint). Sub-marks inherit their\n * aggregate's schema.\n */\nexport function validateMarker(m: ForwardedMarker | null | undefined): ForwardedMarker | null {\n if (!m || typeof m.name !== \"string\") return null;\n if (typeof m.at !== \"number\" || !Number.isFinite(m.at)) return null;\n if (!isAllowedMarkerName(m.name)) return null;\n const base: IrMarkerName = isIrMarkerName(m.name) ? m.name : submarkAggregate(m.name)!;\n const allowed: readonly string[] = IR_MARKERS[base];\n const attrs = m.attrs;\n if (attrs !== undefined) {\n if (typeof attrs !== \"object\" || attrs === null) return null;\n for (const key of Object.keys(attrs)) {\n if (!allowed.includes(key)) return null; // out-of-schema attribute → drop the whole marker\n }\n }\n return { name: m.name, at: m.at, ...(attrs !== undefined ? { attrs } : {}) };\n}\n\n/**\n * `ir.interactive = max(rootRenderCommit, reportReady)` (LP2-3). An app-called\n * `reportReady()` may only DELAY interactive — never advance it before the root\n * render commits. A `reportReady()` that fires early is recorded but takes effect\n * at the commit; if the app never reports, the commit alone stands. Budgets bind to\n * the later of the two, so an app can't game its budget by declaring itself ready\n * before it has rendered anything. PURE.\n */\nexport function resolveInteractive(rootRenderCommitAt: number, reportReadyAt?: number): number {\n if (reportReadyAt === undefined) return rootRenderCommitAt;\n return Math.max(rootRenderCommitAt, reportReadyAt);\n}\n"],"mappings":"AAgBO,MAAM,aAAa;AAAA,EACxB,WAAW,CAAC,OAAO,YAAY,MAAM,QAAQ,OAAO,SAAS;AAAA,EAC7D,YAAY,CAAC,UAAU,SAAS,gBAAgB,YAAY,YAAY;AAAA,EACxE,YAAY,CAAC,gBAAgB,gBAAgB;AAAA,EAC7C,mBAAmB,CAAC;AAAA,EACpB,gBAAgB,CAAC,eAAe,YAAY,WAAW,UAAU;AAAA,EACjE,WAAW,CAAC,YAAY,SAAS,gBAAgB,YAAY,KAAK;AAAA,EAClE,WAAW,CAAC,aAAa;AAAA,EACzB,UAAU,CAAC;AAAA,EACX,kBAAkB,CAAC,MAAM;AAAA,EACzB,aAAa,CAAC,UAAU,UAAU;AAAA,EAClC,cAAc,CAAC,OAAO;AACxB;AAQA,MAAM,aAAa;AACnB,MAAM,mBAAmB,CAAC,SACxB,KAAK,WAAW,kBAAkB,IAAI,iBAAiB,KAAK,WAAW,aAAa,IAAI,YAAY;AAG/F,MAAM,iBAAiB,CAAC,SAC7B,OAAO,UAAU,eAAe,KAAK,YAAY,IAAI;AAIhD,MAAM,sBAAsB,CAAC,SAClC,eAAe,IAAI,KAAK,WAAW,KAAK,IAAI;AAoBvC,SAAS,eAAe,GAA+D;AAC5F,MAAI,CAAC,KAAK,OAAO,EAAE,SAAS,SAAU,QAAO;AAC7C,MAAI,OAAO,EAAE,OAAO,YAAY,CAAC,OAAO,SAAS,EAAE,EAAE,EAAG,QAAO;AAC/D,MAAI,CAAC,oBAAoB,EAAE,IAAI,EAAG,QAAO;AACzC,QAAM,OAAqB,eAAe,EAAE,IAAI,IAAI,EAAE,OAAO,iBAAiB,EAAE,IAAI;AACpF,QAAM,UAA6B,WAAW,IAAI;AAClD,QAAM,QAAQ,EAAE;AAChB,MAAI,UAAU,QAAW;AACvB,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,eAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAI,CAAC,QAAQ,SAAS,GAAG,EAAG,QAAO;AAAA,IACrC;AAAA,EACF;AACA,SAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC,EAAG;AAC7E;AAUO,SAAS,mBAAmB,oBAA4B,eAAgC;AAC7F,MAAI,kBAAkB,OAAW,QAAO;AACxC,SAAO,KAAK,IAAI,oBAAoB,aAAa;AACnD;","names":[]}
package/dist/llm.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// Provider-agnostic LLM chat — the `llm.chat@1` slot (SERVICE_PROVIDERS_SPEC;\n// LLM_AND_AGENTS_SPEC §8 D5).\n//\n// An app calls ONE chat slot and never worries about which provider the user has a\n// key for: the HOST resolves which vendor answers from the key the user holds\n// (`SecretView.boundOrigin`) plus their `preferredImplementation` choice, normalizes\n// the wire format, injects the key host-side at the §6 net:fetch point (the\n// look-at-nothing proxy), and streams normalized deltas back. The app never names a\n// vendor, never sees the key, and needs NO `net:fetch`/`secrets` grant of its own —\n// only the `llm:chat` capability (elevated, app-scoped: a fork earns it by consent).\n//\n// Inert until the host implements `protocol-llm` (the `chat` stream) + the\n// `llm-provider` describe channel; the contract ships here so apps (the file-explorer\n// summarize fork) can be written against it — exactly how `secrets.ts` shipped ahead\n// of `protocol-secrets`.\nimport { invokeStream } from './catalog';\nimport { createPushChannel } from './pushChannel';\n\nexport type ChatRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/** A part of a message. `image` is only honored when the resolved provider\n * advertises `features.vision` (§2.5) — branch on {@link describeChat} first. */\nexport type ContentPart =\n | { type: 'text'; text: string }\n | { type: 'image'; mimeType: string; data: string }; // data: base64, no data: URL prefix\n\nexport interface ChatMessage {\n role: ChatRole;\n content: ContentPart[];\n}\n\n/** A tool the model may call — honored only when `features.tools`. */\nexport interface ToolDef {\n name: string;\n description?: string;\n /** JSON-Schema for the tool's arguments. */\n inputSchema: Record<string, unknown>;\n}\n\nexport interface ChatRequest {\n messages: ChatMessage[];\n /** Honored only when the resolved provider advertises `features.tools`. */\n tools?: ToolDef[];\n /** `'json'` honored only when `features.jsonMode`. Defaults to `'text'`. */\n responseFormat?: 'text' | 'json';\n maxTokens?: number;\n /** An ABSTRACT tier hint, never a vendor model id — the host maps it to a concrete\n * model on the resolved provider. Omit to take the provider's default. */\n modelHint?: 'fast' | 'smart';\n}\n\n/** One streamed chunk. Consumers typically accumulate `text-delta`s. */\nexport type ChatDelta =\n | { type: 'text-delta'; text: string }\n | { type: 'tool-call'; id: string; name: string; input: unknown }\n | { type: 'usage'; inputTokens: number; outputTokens: number };\n\nexport type ChatStopReason = 'end' | 'length' | 'tool' | 'filtered';\n\n/** The terminal value of the {@link chat} stream. */\nexport interface ChatResult {\n stopReason: ChatStopReason;\n}\n\n/**\n * Stream a chat completion from whichever provider the user has configured.\n *\n * ```ts\n * let summary = '';\n * for await (const d of chat({ messages: [{ role: 'user', content: [{ type: 'text', text }] }] })) {\n * if (d.type === 'text-delta') summary += d.text;\n * }\n * ```\n *\n * Requires the `llm:chat` capability. If no provider is bound the host fails the\n * stream into the SP-7 connect-me prompt (the user adds a key) — the generator\n * throws with `code: 'auth-required'`; an un-granted call throws `forbidden`.\n */\nexport function chat(req: ChatRequest): AsyncGenerator<ChatDelta, ChatResult, void> {\n return invokeStream<ChatDelta, ChatResult>('llm:chat', req as unknown as Record<string, unknown>);\n}\n\n/** The resolved provider's advertised abilities (SERVICE_PROVIDERS_SPEC §2.5) — read\n * to branch/degrade (offer image upload only when `vision`). */\nexport interface ChatFeatures {\n vision: boolean;\n tools: boolean;\n jsonMode: boolean;\n maxContextTokens: number;\n}\n\n/** Info about the provider the host resolved for this app. `null` when no provider\n * is bound (SP-7: prompt the user to add a key before calling {@link chat}). */\nexport interface ChatProviderInfo {\n /** Opaque provider id, e.g. `llm.chat.anthropic` — never a vendor secret or model id. */\n providerId: string;\n /** True for Host-proxied providers (host-vouched, SP-9); false for app-level ones,\n * whose `features` are an untrusted claim. */\n hostVouched: boolean;\n features: ChatFeatures;\n}\n\n// The `llm-provider` describe channel (Recipe A): the host pushes the resolved\n// provider info on change and replays it on register-frame, gated by `llm:chat`.\n// A message with no `provider` key is ignored; an explicit `null` means \"no provider\n// bound\" (distinct from \"not yet answered\", which keeps the `initial` null).\nconst channel = createPushChannel<ChatProviderInfo | null>({\n pushType: 'llm-provider',\n requestType: 'request-llm-provider',\n initial: null,\n parse: (msg) =>\n 'provider' in msg ? (msg.provider as ChatProviderInfo | null) : undefined,\n});\n\n/** The provider the host resolved for this app (or `null` if none bound). Poll for a\n * one-off read; use {@link onChatProviderChange}/{@link useChatProvider} to react. */\nexport const describeChat = (): ChatProviderInfo | null => channel.get();\n\n/** Subscribe to provider changes (key added/revoked, preference changed). Invoked\n * immediately with the current value, then on every change. Returns unsubscribe. */\nexport const onChatProviderChange = (\n listener: (provider: ChatProviderInfo | null) => void,\n): (() => void) => channel.onChange(listener);\n\n/** React hook returning the resolved chat provider (or `null`), re-rendering on\n * change — gate the summarize affordance on `provider !== null`. */\nexport const useChatProvider = (): ChatProviderInfo | null => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,qBAA6B;AAC7B,yBAAkC;AA8D3B,SAAS,KAAK,KAA+D;AAClF,aAAO,6BAAoC,YAAY,GAAyC;AAClG;AA0BA,MAAM,cAAU,sCAA2C;AAAA,EACzD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QACN,cAAc,MAAO,IAAI,WAAuC;AACpE,CAAC;AAIM,MAAM,eAAe,MAA+B,QAAQ,IAAI;AAIhE,MAAM,uBAAuB,CAClC,aACiB,QAAQ,SAAS,QAAQ;AAIrC,MAAM,kBAAkB,MAA+B,QAAQ,IAAI;","names":[]}
1
+ {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// Provider-agnostic LLM chat — the `llm.chat@1` slot (SERVICE_PROVIDERS_SPEC;\n// LLM_AND_AGENTS_SPEC §8 D5).\n//\n// An app calls ONE chat slot and never worries about which provider the user has a\n// key for: the HOST resolves which vendor answers from the key the user holds\n// (`SecretView.boundOrigin`) plus their `preferredImplementation` choice, normalizes\n// the wire format, injects the key host-side at the §6 net:fetch point (the\n// look-at-nothing proxy), and streams normalized deltas back. The app never names a\n// vendor, never sees the key, and needs NO `net:fetch`/`secrets` grant of its own —\n// only the `llm:chat` capability (elevated, app-scoped: a fork earns it by consent).\n//\n// Inert until the host implements `protocol-llm` (the `chat` stream) + the\n// `llm-provider` describe channel; the contract ships here so apps (the file-explorer\n// summarize fork) can be written against it — exactly how `secrets.ts` shipped ahead\n// of `protocol-secrets`.\nimport { invokeStream } from './catalog';\nimport { createPushChannel } from './pushChannel';\n\n/** Who authored a {@link ChatMessage}. */\nexport type ChatRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/** A part of a message. `image` is only honored when the resolved provider\n * advertises `features.vision` (§2.5) — branch on {@link describeChat} first. */\nexport type ContentPart =\n | { type: 'text'; text: string }\n | { type: 'image'; mimeType: string; data: string }; // data: base64, no data: URL prefix\n\n/** One message in a {@link ChatRequest}: a role plus its content parts. */\nexport interface ChatMessage {\n role: ChatRole;\n content: ContentPart[];\n}\n\n/** A tool the model may call — honored only when `features.tools`. */\nexport interface ToolDef {\n name: string;\n description?: string;\n /** JSON-Schema for the tool's arguments. */\n inputSchema: Record<string, unknown>;\n}\n\n/** A host-brokered chat completion request: the messages plus optional tools,\n * response format, and model hint (each honored per the provider's features). */\nexport interface ChatRequest {\n messages: ChatMessage[];\n /** Honored only when the resolved provider advertises `features.tools`. */\n tools?: ToolDef[];\n /** `'json'` honored only when `features.jsonMode`. Defaults to `'text'`. */\n responseFormat?: 'text' | 'json';\n maxTokens?: number;\n /** An ABSTRACT tier hint, never a vendor model id — the host maps it to a concrete\n * model on the resolved provider. Omit to take the provider's default. */\n modelHint?: 'fast' | 'smart';\n}\n\n/** One streamed chunk. Consumers typically accumulate `text-delta`s. */\nexport type ChatDelta =\n | { type: 'text-delta'; text: string }\n | { type: 'tool-call'; id: string; name: string; input: unknown }\n | { type: 'usage'; inputTokens: number; outputTokens: number };\n\n/** Why generation stopped: natural `end`, `length` cap, a `tool` call, or content `filtered`. */\nexport type ChatStopReason = 'end' | 'length' | 'tool' | 'filtered';\n\n/** The terminal value of the {@link chat} stream. */\nexport interface ChatResult {\n stopReason: ChatStopReason;\n}\n\n/**\n * Stream a chat completion from whichever provider the user has configured.\n *\n * ```ts\n * let summary = '';\n * for await (const d of chat({ messages: [{ role: 'user', content: [{ type: 'text', text }] }] })) {\n * if (d.type === 'text-delta') summary += d.text;\n * }\n * ```\n *\n * Requires the `llm:chat` capability. If no provider is bound the host fails the\n * stream into the SP-7 connect-me prompt (the user adds a key) — the generator\n * throws with `code: 'auth-required'`; an un-granted call throws `forbidden`.\n */\nexport function chat(req: ChatRequest): AsyncGenerator<ChatDelta, ChatResult, void> {\n return invokeStream<ChatDelta, ChatResult>('llm:chat', req as unknown as Record<string, unknown>);\n}\n\n/** The resolved provider's advertised abilities (SERVICE_PROVIDERS_SPEC §2.5) — read\n * to branch/degrade (offer image upload only when `vision`). */\nexport interface ChatFeatures {\n vision: boolean;\n tools: boolean;\n jsonMode: boolean;\n maxContextTokens: number;\n}\n\n/** Info about the provider the host resolved for this app. `null` when no provider\n * is bound (SP-7: prompt the user to add a key before calling {@link chat}). */\nexport interface ChatProviderInfo {\n /** Opaque provider id, e.g. `llm.chat.anthropic` — never a vendor secret or model id. */\n providerId: string;\n /** True for Host-proxied providers (host-vouched, SP-9); false for app-level ones,\n * whose `features` are an untrusted claim. */\n hostVouched: boolean;\n features: ChatFeatures;\n}\n\n// The `llm-provider` describe channel (Recipe A): the host pushes the resolved\n// provider info on change and replays it on register-frame, gated by `llm:chat`.\n// A message with no `provider` key is ignored; an explicit `null` means \"no provider\n// bound\" (distinct from \"not yet answered\", which keeps the `initial` null).\nconst channel = createPushChannel<ChatProviderInfo | null>({\n pushType: 'llm-provider',\n requestType: 'request-llm-provider',\n initial: null,\n parse: (msg) =>\n 'provider' in msg ? (msg.provider as ChatProviderInfo | null) : undefined,\n});\n\n/** The provider the host resolved for this app (or `null` if none bound). Poll for a\n * one-off read; use {@link onChatProviderChange}/{@link useChatProvider} to react. */\nexport const describeChat = (): ChatProviderInfo | null => channel.get();\n\n/** Subscribe to provider changes (key added/revoked, preference changed). Invoked\n * immediately with the current value, then on every change. Returns unsubscribe. */\nexport const onChatProviderChange = (\n listener: (provider: ChatProviderInfo | null) => void,\n): (() => void) => channel.onChange(listener);\n\n/** React hook returning the resolved chat provider (or `null`), re-rendering on\n * change — gate the summarize affordance on `provider !== null`. */\nexport const useChatProvider = (): ChatProviderInfo | null => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,qBAA6B;AAC7B,yBAAkC;AAmE3B,SAAS,KAAK,KAA+D;AAClF,aAAO,6BAAoC,YAAY,GAAyC;AAClG;AA0BA,MAAM,cAAU,sCAA2C;AAAA,EACzD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QACN,cAAc,MAAO,IAAI,WAAuC;AACpE,CAAC;AAIM,MAAM,eAAe,MAA+B,QAAQ,IAAI;AAIhE,MAAM,uBAAuB,CAClC,aACiB,QAAQ,SAAS,QAAQ;AAIrC,MAAM,kBAAkB,MAA+B,QAAQ,IAAI;","names":[]}
package/dist/llm.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ /** Who authored a {@link ChatMessage}. */
1
2
  type ChatRole = 'system' | 'user' | 'assistant' | 'tool';
2
3
  /** A part of a message. `image` is only honored when the resolved provider
3
4
  * advertises `features.vision` (§2.5) — branch on {@link describeChat} first. */
@@ -9,6 +10,7 @@ type ContentPart = {
9
10
  mimeType: string;
10
11
  data: string;
11
12
  };
13
+ /** One message in a {@link ChatRequest}: a role plus its content parts. */
12
14
  interface ChatMessage {
13
15
  role: ChatRole;
14
16
  content: ContentPart[];
@@ -20,6 +22,8 @@ interface ToolDef {
20
22
  /** JSON-Schema for the tool's arguments. */
21
23
  inputSchema: Record<string, unknown>;
22
24
  }
25
+ /** A host-brokered chat completion request: the messages plus optional tools,
26
+ * response format, and model hint (each honored per the provider's features). */
23
27
  interface ChatRequest {
24
28
  messages: ChatMessage[];
25
29
  /** Honored only when the resolved provider advertises `features.tools`. */
@@ -45,6 +49,7 @@ type ChatDelta = {
45
49
  inputTokens: number;
46
50
  outputTokens: number;
47
51
  };
52
+ /** Why generation stopped: natural `end`, `length` cap, a `tool` call, or content `filtered`. */
48
53
  type ChatStopReason = 'end' | 'length' | 'tool' | 'filtered';
49
54
  /** The terminal value of the {@link chat} stream. */
50
55
  interface ChatResult {
package/dist/llm.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** Who authored a {@link ChatMessage}. */
1
2
  type ChatRole = 'system' | 'user' | 'assistant' | 'tool';
2
3
  /** A part of a message. `image` is only honored when the resolved provider
3
4
  * advertises `features.vision` (§2.5) — branch on {@link describeChat} first. */
@@ -9,6 +10,7 @@ type ContentPart = {
9
10
  mimeType: string;
10
11
  data: string;
11
12
  };
13
+ /** One message in a {@link ChatRequest}: a role plus its content parts. */
12
14
  interface ChatMessage {
13
15
  role: ChatRole;
14
16
  content: ContentPart[];
@@ -20,6 +22,8 @@ interface ToolDef {
20
22
  /** JSON-Schema for the tool's arguments. */
21
23
  inputSchema: Record<string, unknown>;
22
24
  }
25
+ /** A host-brokered chat completion request: the messages plus optional tools,
26
+ * response format, and model hint (each honored per the provider's features). */
23
27
  interface ChatRequest {
24
28
  messages: ChatMessage[];
25
29
  /** Honored only when the resolved provider advertises `features.tools`. */
@@ -45,6 +49,7 @@ type ChatDelta = {
45
49
  inputTokens: number;
46
50
  outputTokens: number;
47
51
  };
52
+ /** Why generation stopped: natural `end`, `length` cap, a `tool` call, or content `filtered`. */
48
53
  type ChatStopReason = 'end' | 'length' | 'tool' | 'filtered';
49
54
  /** The terminal value of the {@link chat} stream. */
50
55
  interface ChatResult {
package/dist/llm.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// Provider-agnostic LLM chat — the `llm.chat@1` slot (SERVICE_PROVIDERS_SPEC;\n// LLM_AND_AGENTS_SPEC §8 D5).\n//\n// An app calls ONE chat slot and never worries about which provider the user has a\n// key for: the HOST resolves which vendor answers from the key the user holds\n// (`SecretView.boundOrigin`) plus their `preferredImplementation` choice, normalizes\n// the wire format, injects the key host-side at the §6 net:fetch point (the\n// look-at-nothing proxy), and streams normalized deltas back. The app never names a\n// vendor, never sees the key, and needs NO `net:fetch`/`secrets` grant of its own —\n// only the `llm:chat` capability (elevated, app-scoped: a fork earns it by consent).\n//\n// Inert until the host implements `protocol-llm` (the `chat` stream) + the\n// `llm-provider` describe channel; the contract ships here so apps (the file-explorer\n// summarize fork) can be written against it — exactly how `secrets.ts` shipped ahead\n// of `protocol-secrets`.\nimport { invokeStream } from './catalog';\nimport { createPushChannel } from './pushChannel';\n\nexport type ChatRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/** A part of a message. `image` is only honored when the resolved provider\n * advertises `features.vision` (§2.5) — branch on {@link describeChat} first. */\nexport type ContentPart =\n | { type: 'text'; text: string }\n | { type: 'image'; mimeType: string; data: string }; // data: base64, no data: URL prefix\n\nexport interface ChatMessage {\n role: ChatRole;\n content: ContentPart[];\n}\n\n/** A tool the model may call — honored only when `features.tools`. */\nexport interface ToolDef {\n name: string;\n description?: string;\n /** JSON-Schema for the tool's arguments. */\n inputSchema: Record<string, unknown>;\n}\n\nexport interface ChatRequest {\n messages: ChatMessage[];\n /** Honored only when the resolved provider advertises `features.tools`. */\n tools?: ToolDef[];\n /** `'json'` honored only when `features.jsonMode`. Defaults to `'text'`. */\n responseFormat?: 'text' | 'json';\n maxTokens?: number;\n /** An ABSTRACT tier hint, never a vendor model id — the host maps it to a concrete\n * model on the resolved provider. Omit to take the provider's default. */\n modelHint?: 'fast' | 'smart';\n}\n\n/** One streamed chunk. Consumers typically accumulate `text-delta`s. */\nexport type ChatDelta =\n | { type: 'text-delta'; text: string }\n | { type: 'tool-call'; id: string; name: string; input: unknown }\n | { type: 'usage'; inputTokens: number; outputTokens: number };\n\nexport type ChatStopReason = 'end' | 'length' | 'tool' | 'filtered';\n\n/** The terminal value of the {@link chat} stream. */\nexport interface ChatResult {\n stopReason: ChatStopReason;\n}\n\n/**\n * Stream a chat completion from whichever provider the user has configured.\n *\n * ```ts\n * let summary = '';\n * for await (const d of chat({ messages: [{ role: 'user', content: [{ type: 'text', text }] }] })) {\n * if (d.type === 'text-delta') summary += d.text;\n * }\n * ```\n *\n * Requires the `llm:chat` capability. If no provider is bound the host fails the\n * stream into the SP-7 connect-me prompt (the user adds a key) — the generator\n * throws with `code: 'auth-required'`; an un-granted call throws `forbidden`.\n */\nexport function chat(req: ChatRequest): AsyncGenerator<ChatDelta, ChatResult, void> {\n return invokeStream<ChatDelta, ChatResult>('llm:chat', req as unknown as Record<string, unknown>);\n}\n\n/** The resolved provider's advertised abilities (SERVICE_PROVIDERS_SPEC §2.5) — read\n * to branch/degrade (offer image upload only when `vision`). */\nexport interface ChatFeatures {\n vision: boolean;\n tools: boolean;\n jsonMode: boolean;\n maxContextTokens: number;\n}\n\n/** Info about the provider the host resolved for this app. `null` when no provider\n * is bound (SP-7: prompt the user to add a key before calling {@link chat}). */\nexport interface ChatProviderInfo {\n /** Opaque provider id, e.g. `llm.chat.anthropic` — never a vendor secret or model id. */\n providerId: string;\n /** True for Host-proxied providers (host-vouched, SP-9); false for app-level ones,\n * whose `features` are an untrusted claim. */\n hostVouched: boolean;\n features: ChatFeatures;\n}\n\n// The `llm-provider` describe channel (Recipe A): the host pushes the resolved\n// provider info on change and replays it on register-frame, gated by `llm:chat`.\n// A message with no `provider` key is ignored; an explicit `null` means \"no provider\n// bound\" (distinct from \"not yet answered\", which keeps the `initial` null).\nconst channel = createPushChannel<ChatProviderInfo | null>({\n pushType: 'llm-provider',\n requestType: 'request-llm-provider',\n initial: null,\n parse: (msg) =>\n 'provider' in msg ? (msg.provider as ChatProviderInfo | null) : undefined,\n});\n\n/** The provider the host resolved for this app (or `null` if none bound). Poll for a\n * one-off read; use {@link onChatProviderChange}/{@link useChatProvider} to react. */\nexport const describeChat = (): ChatProviderInfo | null => channel.get();\n\n/** Subscribe to provider changes (key added/revoked, preference changed). Invoked\n * immediately with the current value, then on every change. Returns unsubscribe. */\nexport const onChatProviderChange = (\n listener: (provider: ChatProviderInfo | null) => void,\n): (() => void) => channel.onChange(listener);\n\n/** React hook returning the resolved chat provider (or `null`), re-rendering on\n * change — gate the summarize affordance on `provider !== null`. */\nexport const useChatProvider = (): ChatProviderInfo | null => channel.use();\n"],"mappings":"AAeA,SAAS,oBAAoB;AAC7B,SAAS,yBAAyB;AA8D3B,SAAS,KAAK,KAA+D;AAClF,SAAO,aAAoC,YAAY,GAAyC;AAClG;AA0BA,MAAM,UAAU,kBAA2C;AAAA,EACzD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QACN,cAAc,MAAO,IAAI,WAAuC;AACpE,CAAC;AAIM,MAAM,eAAe,MAA+B,QAAQ,IAAI;AAIhE,MAAM,uBAAuB,CAClC,aACiB,QAAQ,SAAS,QAAQ;AAIrC,MAAM,kBAAkB,MAA+B,QAAQ,IAAI;","names":[]}
1
+ {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// Provider-agnostic LLM chat — the `llm.chat@1` slot (SERVICE_PROVIDERS_SPEC;\n// LLM_AND_AGENTS_SPEC §8 D5).\n//\n// An app calls ONE chat slot and never worries about which provider the user has a\n// key for: the HOST resolves which vendor answers from the key the user holds\n// (`SecretView.boundOrigin`) plus their `preferredImplementation` choice, normalizes\n// the wire format, injects the key host-side at the §6 net:fetch point (the\n// look-at-nothing proxy), and streams normalized deltas back. The app never names a\n// vendor, never sees the key, and needs NO `net:fetch`/`secrets` grant of its own —\n// only the `llm:chat` capability (elevated, app-scoped: a fork earns it by consent).\n//\n// Inert until the host implements `protocol-llm` (the `chat` stream) + the\n// `llm-provider` describe channel; the contract ships here so apps (the file-explorer\n// summarize fork) can be written against it — exactly how `secrets.ts` shipped ahead\n// of `protocol-secrets`.\nimport { invokeStream } from './catalog';\nimport { createPushChannel } from './pushChannel';\n\n/** Who authored a {@link ChatMessage}. */\nexport type ChatRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/** A part of a message. `image` is only honored when the resolved provider\n * advertises `features.vision` (§2.5) — branch on {@link describeChat} first. */\nexport type ContentPart =\n | { type: 'text'; text: string }\n | { type: 'image'; mimeType: string; data: string }; // data: base64, no data: URL prefix\n\n/** One message in a {@link ChatRequest}: a role plus its content parts. */\nexport interface ChatMessage {\n role: ChatRole;\n content: ContentPart[];\n}\n\n/** A tool the model may call — honored only when `features.tools`. */\nexport interface ToolDef {\n name: string;\n description?: string;\n /** JSON-Schema for the tool's arguments. */\n inputSchema: Record<string, unknown>;\n}\n\n/** A host-brokered chat completion request: the messages plus optional tools,\n * response format, and model hint (each honored per the provider's features). */\nexport interface ChatRequest {\n messages: ChatMessage[];\n /** Honored only when the resolved provider advertises `features.tools`. */\n tools?: ToolDef[];\n /** `'json'` honored only when `features.jsonMode`. Defaults to `'text'`. */\n responseFormat?: 'text' | 'json';\n maxTokens?: number;\n /** An ABSTRACT tier hint, never a vendor model id — the host maps it to a concrete\n * model on the resolved provider. Omit to take the provider's default. */\n modelHint?: 'fast' | 'smart';\n}\n\n/** One streamed chunk. Consumers typically accumulate `text-delta`s. */\nexport type ChatDelta =\n | { type: 'text-delta'; text: string }\n | { type: 'tool-call'; id: string; name: string; input: unknown }\n | { type: 'usage'; inputTokens: number; outputTokens: number };\n\n/** Why generation stopped: natural `end`, `length` cap, a `tool` call, or content `filtered`. */\nexport type ChatStopReason = 'end' | 'length' | 'tool' | 'filtered';\n\n/** The terminal value of the {@link chat} stream. */\nexport interface ChatResult {\n stopReason: ChatStopReason;\n}\n\n/**\n * Stream a chat completion from whichever provider the user has configured.\n *\n * ```ts\n * let summary = '';\n * for await (const d of chat({ messages: [{ role: 'user', content: [{ type: 'text', text }] }] })) {\n * if (d.type === 'text-delta') summary += d.text;\n * }\n * ```\n *\n * Requires the `llm:chat` capability. If no provider is bound the host fails the\n * stream into the SP-7 connect-me prompt (the user adds a key) — the generator\n * throws with `code: 'auth-required'`; an un-granted call throws `forbidden`.\n */\nexport function chat(req: ChatRequest): AsyncGenerator<ChatDelta, ChatResult, void> {\n return invokeStream<ChatDelta, ChatResult>('llm:chat', req as unknown as Record<string, unknown>);\n}\n\n/** The resolved provider's advertised abilities (SERVICE_PROVIDERS_SPEC §2.5) — read\n * to branch/degrade (offer image upload only when `vision`). */\nexport interface ChatFeatures {\n vision: boolean;\n tools: boolean;\n jsonMode: boolean;\n maxContextTokens: number;\n}\n\n/** Info about the provider the host resolved for this app. `null` when no provider\n * is bound (SP-7: prompt the user to add a key before calling {@link chat}). */\nexport interface ChatProviderInfo {\n /** Opaque provider id, e.g. `llm.chat.anthropic` — never a vendor secret or model id. */\n providerId: string;\n /** True for Host-proxied providers (host-vouched, SP-9); false for app-level ones,\n * whose `features` are an untrusted claim. */\n hostVouched: boolean;\n features: ChatFeatures;\n}\n\n// The `llm-provider` describe channel (Recipe A): the host pushes the resolved\n// provider info on change and replays it on register-frame, gated by `llm:chat`.\n// A message with no `provider` key is ignored; an explicit `null` means \"no provider\n// bound\" (distinct from \"not yet answered\", which keeps the `initial` null).\nconst channel = createPushChannel<ChatProviderInfo | null>({\n pushType: 'llm-provider',\n requestType: 'request-llm-provider',\n initial: null,\n parse: (msg) =>\n 'provider' in msg ? (msg.provider as ChatProviderInfo | null) : undefined,\n});\n\n/** The provider the host resolved for this app (or `null` if none bound). Poll for a\n * one-off read; use {@link onChatProviderChange}/{@link useChatProvider} to react. */\nexport const describeChat = (): ChatProviderInfo | null => channel.get();\n\n/** Subscribe to provider changes (key added/revoked, preference changed). Invoked\n * immediately with the current value, then on every change. Returns unsubscribe. */\nexport const onChatProviderChange = (\n listener: (provider: ChatProviderInfo | null) => void,\n): (() => void) => channel.onChange(listener);\n\n/** React hook returning the resolved chat provider (or `null`), re-rendering on\n * change — gate the summarize affordance on `provider !== null`. */\nexport const useChatProvider = (): ChatProviderInfo | null => channel.use();\n"],"mappings":"AAeA,SAAS,oBAAoB;AAC7B,SAAS,yBAAyB;AAmE3B,SAAS,KAAK,KAA+D;AAClF,SAAO,aAAoC,YAAY,GAAyC;AAClG;AA0BA,MAAM,UAAU,kBAA2C;AAAA,EACzD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QACN,cAAc,MAAO,IAAI,WAAuC;AACpE,CAAC;AAIM,MAAM,eAAe,MAA+B,QAAQ,IAAI;AAIhE,MAAM,uBAAuB,CAClC,aACiB,QAAQ,SAAS,QAAQ;AAIrC,MAAM,kBAAkB,MAA+B,QAAQ,IAAI;","names":[]}
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var loading_exports = {};
20
+ __export(loading_exports, {
21
+ LOADING_TIMINGS: () => LOADING_TIMINGS,
22
+ LoadingRegion: () => LoadingRegion,
23
+ Skeleton: () => Skeleton,
24
+ SkeletonRow: () => SkeletonRow,
25
+ Spinner: () => Spinner
26
+ });
27
+ module.exports = __toCommonJS(loading_exports);
28
+ var import_jsx_runtime = require("react/jsx-runtime");
29
+ var import_react = require("react");
30
+ const LOADING_TIMINGS = {
31
+ /** Below this, NO spinner appears — a fast wait never flashes one (§6.2 floor). */
32
+ spinThresholdMs: 150,
33
+ /** The reveal cross-fade duration the host uses. */
34
+ fadeMs: 150,
35
+ /** One slow shimmer sweep across a placeholder. */
36
+ shimmerMs: 1900
37
+ };
38
+ const STYLE_ID = "ir-sdk-loading-styles";
39
+ const STYLE_TEXT = `
40
+ @keyframes ir-sdk-sweep{0%{transform:translateX(-130%)}60%,100%{transform:translateX(130%)}}
41
+ @keyframes ir-sdk-spin{to{transform:rotate(360deg)}}
42
+ .ir-sdk-shim{position:relative;overflow:hidden}
43
+ .ir-sdk-shim::after{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 28%,rgba(127,127,127,.18) 50%,transparent 72%);transform:translateX(-130%);animation:ir-sdk-sweep ${LOADING_TIMINGS.shimmerMs}ms ease-in-out infinite}
44
+ .ir-sdk-spin{animation:ir-sdk-spin .8s linear infinite}
45
+ @media (prefers-reduced-motion:reduce){.ir-sdk-shim::after{display:none}.ir-sdk-spin{animation:none}}
46
+ `;
47
+ function ensureLoadingStyles() {
48
+ if (typeof document === "undefined") return;
49
+ if (document.getElementById(STYLE_ID)) return;
50
+ const el = document.createElement("style");
51
+ el.id = STYLE_ID;
52
+ el.textContent = STYLE_TEXT;
53
+ document.head.appendChild(el);
54
+ }
55
+ function useLoadingStyles() {
56
+ (0, import_react.useLayoutEffect)(() => {
57
+ ensureLoadingStyles();
58
+ }, []);
59
+ }
60
+ const PLACEHOLDER = {
61
+ background: "rgba(127,127,127,0.20)",
62
+ borderRadius: 6
63
+ };
64
+ function SkeletonRow({
65
+ width = "100%",
66
+ height = 12,
67
+ style
68
+ }) {
69
+ useLoadingStyles();
70
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
71
+ "div",
72
+ {
73
+ className: "ir-sdk-shim",
74
+ "aria-hidden": "true",
75
+ style: { ...PLACEHOLDER, width, height, ...style }
76
+ }
77
+ );
78
+ }
79
+ function rows(specs) {
80
+ return specs.map(({ key, ...s }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ir-sdk-shim", "aria-hidden": "true", style: { ...PLACEHOLDER, ...s } }, key));
81
+ }
82
+ function Skeleton({
83
+ archetype = "generic",
84
+ style
85
+ }) {
86
+ useLoadingStyles();
87
+ const wrap = {
88
+ display: "flex",
89
+ flexDirection: "column",
90
+ gap: 10,
91
+ padding: 12,
92
+ width: "100%",
93
+ boxSizing: "border-box",
94
+ ...style
95
+ };
96
+ let body;
97
+ switch (archetype) {
98
+ case "panel.list":
99
+ body = rows([0, 1, 2, 3, 4].map((key) => ({ key, height: 14 })));
100
+ break;
101
+ case "panel.tree":
102
+ body = rows([0, 1, 2, 3, 4].map((key) => ({ key, height: 14, marginLeft: key % 3 * 16 })));
103
+ break;
104
+ case "panel.editor":
105
+ body = rows([62, 88, 73, 41, 80].map((w, key) => ({ key, height: 11, width: `${w}%` })));
106
+ break;
107
+ case "panel.conversation":
108
+ body = rows(
109
+ [0, 1, 2, 3].map((key) => ({
110
+ key,
111
+ height: 40,
112
+ width: "70%",
113
+ borderRadius: 12,
114
+ alignSelf: key % 2 ? "flex-end" : "flex-start"
115
+ }))
116
+ );
117
+ break;
118
+ case "generic":
119
+ default:
120
+ body = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
121
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ir-sdk-shim", "aria-hidden": "true", style: { ...PLACEHOLDER, height: 16, width: "45%", borderRadius: 4 } }),
122
+ rows([0, 1].map((key) => ({ key, height: 56, borderRadius: 8 })))
123
+ ] });
124
+ }
125
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "aria-hidden": "true", style: wrap, children: body });
126
+ }
127
+ function useDelayedFlag(ms) {
128
+ const [on, setOn] = (0, import_react.useState)(false);
129
+ (0, import_react.useEffect)(() => {
130
+ const t = setTimeout(() => setOn(true), ms);
131
+ return () => clearTimeout(t);
132
+ }, [ms]);
133
+ return on;
134
+ }
135
+ function Spinner({
136
+ size = 18,
137
+ thresholdMs = LOADING_TIMINGS.spinThresholdMs,
138
+ label = "Loading"
139
+ }) {
140
+ useLoadingStyles();
141
+ const show = useDelayedFlag(thresholdMs);
142
+ if (!show) return null;
143
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
144
+ "span",
145
+ {
146
+ className: "ir-sdk-spin",
147
+ role: "status",
148
+ "aria-label": label,
149
+ style: {
150
+ display: "inline-block",
151
+ width: size,
152
+ height: size,
153
+ border: "2px solid rgba(127,127,127,0.3)",
154
+ borderTopColor: "currentColor",
155
+ borderRadius: "50%",
156
+ boxSizing: "border-box"
157
+ }
158
+ }
159
+ );
160
+ }
161
+ function LoadingRegion({
162
+ loading,
163
+ fallback,
164
+ label = "Loading",
165
+ children
166
+ }) {
167
+ useLoadingStyles();
168
+ if (!loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
169
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
170
+ "div",
171
+ {
172
+ "aria-busy": "true",
173
+ style: { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", minHeight: 48 },
174
+ children: fallback ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { label })
175
+ }
176
+ );
177
+ }
178
+ // Annotate the CommonJS export names for ESM import in node:
179
+ 0 && (module.exports = {
180
+ LOADING_TIMINGS,
181
+ LoadingRegion,
182
+ Skeleton,
183
+ SkeletonRow,
184
+ Spinner
185
+ });
186
+ //# sourceMappingURL=loading.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/loading.tsx"],"sourcesContent":["// In-app loading primitives (LOADING_UX_SPEC §9, Surface E; design brief 19).\n//\n// Opt-in, presentational components an app author drops in for IN-APP waits (a\n// React.lazy chunk, a slow fetch, a pending action) so they match the platform's\n// loading language for free. Per product_values §3 this is convenience — a plain\n// app that ignores it still works.\n//\n// TRUST BOUNDARY (read brief 19): these render INSIDE the app's iframe, under the\n// app's principal — presentational only, NO capability, NO host round-trip. They\n// share the token VOCABULARY (radii, the shimmer sweep, soft placeholder fills)\n// with the host skeletons, but they are deliberately NOT the host's trusted chrome:\n// no reserved landmark, no wordmark, no \"platform is loading\" framing. They use\n// ordinary app a11y (`aria-hidden` for decorative skeletons, `role=\"status\"` for an\n// indeterminate indicator) — never the host's reserved landmark/accessible name\n// (that is the trusted-path control, reserved to the host). An in-app loader that\n// mimicked host chrome would be a spoofing vector.\n//\n// Self-contained: the SDK ships no CSS pipeline, so the keyframes are injected once\n// into the document and everything else is inline styles — zero config for the author.\nimport {\n useEffect,\n useLayoutEffect,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\n/** Loading timing constants, matching the host (LOADING_UX_SPEC §3, the 2026-06-22\n * design bundle). Exported so authors who hand-roll still match the platform. */\nexport const LOADING_TIMINGS = {\n /** Below this, NO spinner appears — a fast wait never flashes one (§6.2 floor). */\n spinThresholdMs: 150,\n /** The reveal cross-fade duration the host uses. */\n fadeMs: 150,\n /** One slow shimmer sweep across a placeholder. */\n shimmerMs: 1900,\n} as const;\n\n/** The in-app skeleton archetypes (the same shapes as the host §4.1 catalog). */\nexport type SkeletonArchetype =\n | \"panel.list\"\n | \"panel.tree\"\n | \"panel.editor\"\n | \"panel.conversation\"\n | \"generic\";\n\nconst STYLE_ID = \"ir-sdk-loading-styles\";\nconst STYLE_TEXT = `\n@keyframes ir-sdk-sweep{0%{transform:translateX(-130%)}60%,100%{transform:translateX(130%)}}\n@keyframes ir-sdk-spin{to{transform:rotate(360deg)}}\n.ir-sdk-shim{position:relative;overflow:hidden}\n.ir-sdk-shim::after{content:\"\";position:absolute;inset:0;background:linear-gradient(100deg,transparent 28%,rgba(127,127,127,.18) 50%,transparent 72%);transform:translateX(-130%);animation:ir-sdk-sweep ${LOADING_TIMINGS.shimmerMs}ms ease-in-out infinite}\n.ir-sdk-spin{animation:ir-sdk-spin .8s linear infinite}\n@media (prefers-reduced-motion:reduce){.ir-sdk-shim::after{display:none}.ir-sdk-spin{animation:none}}\n`;\n\n/** Inject the shimmer/spin keyframes once (idempotent, browser-only). */\nfunction ensureLoadingStyles(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = STYLE_TEXT;\n document.head.appendChild(el);\n}\n\n/** Ensure the loading keyframes exist before the component paints. */\nfunction useLoadingStyles(): void {\n useLayoutEffect(() => {\n ensureLoadingStyles();\n }, []);\n}\n\n// A soft, low-contrast placeholder fill that reads on a light OR dark app surface.\nconst PLACEHOLDER: CSSProperties = {\n background: \"rgba(127,127,127,0.20)\",\n borderRadius: 6,\n};\n\n/** A single placeholder bar — compose these into a custom skeleton shape. */\nexport function SkeletonRow({\n width = \"100%\",\n height = 12,\n style,\n}: {\n width?: number | string;\n height?: number | string;\n style?: CSSProperties;\n}) {\n useLoadingStyles();\n return (\n <div\n className=\"ir-sdk-shim\"\n aria-hidden=\"true\"\n style={{ ...PLACEHOLDER, width, height, ...style }}\n />\n );\n}\n\nfunction rows(specs: Array<CSSProperties & { key: number }>): ReactNode {\n return specs.map(({ key, ...s }) => (\n <div key={key} className=\"ir-sdk-shim\" aria-hidden=\"true\" style={{ ...PLACEHOLDER, ...s }} />\n ));\n}\n\n/** A shaped, in-app skeleton matching the host archetypes — for an app's own lazy\n * region (e.g. `<Suspense fallback={<Skeleton archetype=\"panel.list\" />}>`).\n * Decorative (`aria-hidden`); pair it with `aria-busy` on the region it stands in. */\nexport function Skeleton({\n archetype = \"generic\",\n style,\n}: {\n archetype?: SkeletonArchetype;\n style?: CSSProperties;\n}) {\n useLoadingStyles();\n const wrap: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n gap: 10,\n padding: 12,\n width: \"100%\",\n boxSizing: \"border-box\",\n ...style,\n };\n let body: ReactNode;\n switch (archetype) {\n case \"panel.list\":\n body = rows([0, 1, 2, 3, 4].map((key) => ({ key, height: 14 })));\n break;\n case \"panel.tree\":\n body = rows([0, 1, 2, 3, 4].map((key) => ({ key, height: 14, marginLeft: (key % 3) * 16 })));\n break;\n case \"panel.editor\":\n body = rows([62, 88, 73, 41, 80].map((w, key) => ({ key, height: 11, width: `${w}%` })));\n break;\n case \"panel.conversation\":\n body = rows(\n [0, 1, 2, 3].map((key) => ({\n key,\n height: 40,\n width: \"70%\",\n borderRadius: 12,\n alignSelf: key % 2 ? \"flex-end\" : \"flex-start\",\n })),\n );\n break;\n case \"generic\":\n default:\n body = (\n <>\n <div className=\"ir-sdk-shim\" aria-hidden=\"true\" style={{ ...PLACEHOLDER, height: 16, width: \"45%\", borderRadius: 4 }} />\n {rows([0, 1].map((key) => ({ key, height: 56, borderRadius: 8 })))}\n </>\n );\n }\n return (\n <div aria-hidden=\"true\" style={wrap}>\n {body}\n </div>\n );\n}\n\n/** Become true after `ms`, so a fast wait never flashes an indicator (§6.2 floor). */\nfunction useDelayedFlag(ms: number): boolean {\n const [on, setOn] = useState(false);\n useEffect(() => {\n const t = setTimeout(() => setOn(true), ms);\n return () => clearTimeout(t);\n }, [ms]);\n return on;\n}\n\n/** An indeterminate spinner for waits where a shaped skeleton doesn't fit (a pending\n * button, a small inline fetch). Wired to the host's ~150 ms-before-spin rule: it\n * renders nothing until the threshold, so a fast wait shows no flash. Reduced motion\n * stills the rotation (the ring stays as a static indicator). In-app a11y only. */\nexport function Spinner({\n size = 18,\n thresholdMs = LOADING_TIMINGS.spinThresholdMs,\n label = \"Loading\",\n}: {\n size?: number;\n thresholdMs?: number;\n label?: string;\n}) {\n useLoadingStyles();\n const show = useDelayedFlag(thresholdMs);\n if (!show) return null;\n return (\n <span\n className=\"ir-sdk-spin\"\n role=\"status\"\n aria-label={label}\n style={{\n display: \"inline-block\",\n width: size,\n height: size,\n border: \"2px solid rgba(127,127,127,0.3)\",\n borderTopColor: \"currentColor\",\n borderRadius: \"50%\",\n boxSizing: \"border-box\",\n }}\n />\n );\n}\n\n/** Wrap an in-app region whose content is still loading: shows a centered spinner\n * (past the 150 ms floor) with `aria-busy`, then reveals `children`. For a shaped\n * wait, pass a `<Skeleton>` as `fallback` instead. App a11y only — not host chrome. */\nexport function LoadingRegion({\n loading,\n fallback,\n label = \"Loading\",\n children,\n}: {\n loading: boolean;\n fallback?: ReactNode;\n label?: string;\n children?: ReactNode;\n}) {\n useLoadingStyles();\n if (!loading) return <>{children}</>;\n return (\n <div\n aria-busy=\"true\"\n style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"center\", width: \"100%\", height: \"100%\", minHeight: 48 }}\n >\n {fallback ?? <Spinner label={label} />}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2FI;AAxEJ,mBAMO;AAIA,MAAM,kBAAkB;AAAA;AAAA,EAE7B,iBAAiB;AAAA;AAAA,EAEjB,QAAQ;AAAA;AAAA,EAER,WAAW;AACb;AAUA,MAAM,WAAW;AACjB,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA,2MAIwL,gBAAgB,SAAS;AAAA;AAAA;AAAA;AAMpO,SAAS,sBAA4B;AACnC,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI,SAAS,eAAe,QAAQ,EAAG;AACvC,QAAM,KAAK,SAAS,cAAc,OAAO;AACzC,KAAG,KAAK;AACR,KAAG,cAAc;AACjB,WAAS,KAAK,YAAY,EAAE;AAC9B;AAGA,SAAS,mBAAyB;AAChC,oCAAgB,MAAM;AACpB,wBAAoB;AAAA,EACtB,GAAG,CAAC,CAAC;AACP;AAGA,MAAM,cAA6B;AAAA,EACjC,YAAY;AAAA,EACZ,cAAc;AAChB;AAGO,SAAS,YAAY;AAAA,EAC1B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT;AACF,GAIG;AACD,mBAAiB;AACjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAY;AAAA,MACZ,OAAO,EAAE,GAAG,aAAa,OAAO,QAAQ,GAAG,MAAM;AAAA;AAAA,EACnD;AAEJ;AAEA,SAAS,KAAK,OAA0D;AACtE,SAAO,MAAM,IAAI,CAAC,EAAE,KAAK,GAAG,EAAE,MAC5B,4CAAC,SAAc,WAAU,eAAc,eAAY,QAAO,OAAO,EAAE,GAAG,aAAa,GAAG,EAAE,KAA9E,GAAiF,CAC5F;AACH;AAKO,SAAS,SAAS;AAAA,EACvB,YAAY;AAAA,EACZ;AACF,GAGG;AACD,mBAAiB;AACjB,QAAM,OAAsB;AAAA,IAC1B,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW;AAAA,IACX,GAAG;AAAA,EACL;AACA,MAAI;AACJ,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,QAAQ,GAAG,EAAE,CAAC;AAC/D;AAAA,IACF,KAAK;AACH,aAAO,KAAK,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,QAAQ,IAAI,YAAa,MAAM,IAAK,GAAG,EAAE,CAAC;AAC3F;AAAA,IACF,KAAK;AACH,aAAO,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,GAAG,SAAS,EAAE,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACvF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS;AAAA,UACzB;AAAA,UACA,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,cAAc;AAAA,UACd,WAAW,MAAM,IAAI,aAAa;AAAA,QACpC,EAAE;AAAA,MACJ;AACA;AAAA,IACF,KAAK;AAAA,IACL;AACE,aACE,4EACE;AAAA,oDAAC,SAAI,WAAU,eAAc,eAAY,QAAO,OAAO,EAAE,GAAG,aAAa,QAAQ,IAAI,OAAO,OAAO,cAAc,EAAE,GAAG;AAAA,QACrH,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,QAAQ,IAAI,cAAc,EAAE,EAAE,CAAC;AAAA,SACnE;AAAA,EAEN;AACA,SACE,4CAAC,SAAI,eAAY,QAAO,OAAO,MAC5B,gBACH;AAEJ;AAGA,SAAS,eAAe,IAAqB;AAC3C,QAAM,CAAC,IAAI,KAAK,QAAI,uBAAS,KAAK;AAClC,8BAAU,MAAM;AACd,UAAM,IAAI,WAAW,MAAM,MAAM,IAAI,GAAG,EAAE;AAC1C,WAAO,MAAM,aAAa,CAAC;AAAA,EAC7B,GAAG,CAAC,EAAE,CAAC;AACP,SAAO;AACT;AAMO,SAAS,QAAQ;AAAA,EACtB,OAAO;AAAA,EACP,cAAc,gBAAgB;AAAA,EAC9B,QAAQ;AACV,GAIG;AACD,mBAAiB;AACjB,QAAM,OAAO,eAAe,WAAW;AACvC,MAAI,CAAC,KAAM,QAAO;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,OAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,WAAW;AAAA,MACb;AAAA;AAAA,EACF;AAEJ;AAKO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AACF,GAKG;AACD,mBAAiB;AACjB,MAAI,CAAC,QAAS,QAAO,2EAAG,UAAS;AACjC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,OAAO,QAAQ,QAAQ,QAAQ,WAAW,GAAG;AAAA,MAEtH,sBAAY,4CAAC,WAAQ,OAAc;AAAA;AAAA,EACtC;AAEJ;","names":[]}