iterate 0.2.6 → 0.3.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 (218) hide show
  1. package/README.md +86 -76
  2. package/THIRD_PARTY_NOTICES.md +55 -0
  3. package/bin/iterate.js +18 -3
  4. package/dist/api-url-B6404M82.mjs +17 -0
  5. package/dist/api-url-B6404M82.mjs.map +1 -0
  6. package/dist/app-ref-BipL0feU.mjs +35 -0
  7. package/dist/app-ref-BipL0feU.mjs.map +1 -0
  8. package/dist/app-ref-C1CrgXqX.mjs +7 -0
  9. package/dist/app-ref-C1CrgXqX.mjs.map +1 -0
  10. package/dist/app-ref-DYai_om1.mjs +7 -0
  11. package/dist/app-ref-DYai_om1.mjs.map +1 -0
  12. package/dist/cli-D0c-pDL_.mjs +1010 -0
  13. package/dist/cli-D0c-pDL_.mjs.map +1 -0
  14. package/dist/client.d.ts +3 -0
  15. package/dist/client.mjs +4 -0
  16. package/dist/cloudflare-BTm90gQ4.mjs +951 -0
  17. package/dist/cloudflare-BTm90gQ4.mjs.map +1 -0
  18. package/dist/contract-s4FW4eES.mjs +309 -0
  19. package/dist/contract-s4FW4eES.mjs.map +1 -0
  20. package/dist/document-review/index.d.ts +5 -0
  21. package/dist/document-review/types.d.ts +107 -0
  22. package/dist/document-review.mjs +7015 -0
  23. package/dist/document-review.mjs.map +1 -0
  24. package/dist/durable-object-processor-durability-CNsTjAJS.mjs +205 -0
  25. package/dist/durable-object-processor-durability-CNsTjAJS.mjs.map +1 -0
  26. package/dist/idempotency-DleloJNt.mjs +28 -0
  27. package/dist/idempotency-DleloJNt.mjs.map +1 -0
  28. package/dist/index.mjs +1 -1
  29. package/dist/itx/api-url.d.ts +6 -0
  30. package/dist/itx/itx-node-client.d.ts +65 -0
  31. package/dist/itx/itx-session.d.ts +215 -0
  32. package/dist/itx/owned-rpc-session.d.ts +14 -0
  33. package/dist/itx/query-client.d.ts +10 -0
  34. package/dist/itx-api.generated.d.ts +6195 -0
  35. package/dist/itx-session-sjud8GiT.mjs +534 -0
  36. package/dist/itx-session-sjud8GiT.mjs.map +1 -0
  37. package/dist/live-state-BJNqOwFw.mjs +299 -0
  38. package/dist/live-state-BJNqOwFw.mjs.map +1 -0
  39. package/dist/next/api.d.ts +479 -0
  40. package/dist/next/api.mjs +0 -0
  41. package/dist/next/app-server.d.ts +44 -0
  42. package/dist/next/app-server.mjs +479 -0
  43. package/dist/next/app-server.mjs.map +1 -0
  44. package/dist/next/app-session.d.ts +49 -0
  45. package/dist/next/app-session.mjs +238 -0
  46. package/dist/next/app-session.mjs.map +1 -0
  47. package/dist/next/app.d.ts +29 -0
  48. package/dist/next/app.mjs +141 -0
  49. package/dist/next/app.mjs.map +1 -0
  50. package/dist/next/client/live-state.d.ts +63 -0
  51. package/dist/next/client/oauth.d.ts +12 -0
  52. package/dist/next/client/react.d.ts +109 -0
  53. package/dist/next/client/socket.d.ts +6 -0
  54. package/dist/next/client.mjs +156 -0
  55. package/dist/next/client.mjs.map +1 -0
  56. package/dist/next/expression.d.ts +146 -0
  57. package/dist/next/expression.mjs +399 -0
  58. package/dist/next/expression.mjs.map +1 -0
  59. package/dist/next/lib.d.ts +56 -0
  60. package/dist/next/lib.mjs +199 -0
  61. package/dist/next/lib.mjs.map +1 -0
  62. package/dist/next/oauth-scopes.d.ts +32 -0
  63. package/dist/next/oauth-scopes.mjs +40 -0
  64. package/dist/next/oauth-scopes.mjs.map +1 -0
  65. package/dist/next/oauth.mjs +29 -0
  66. package/dist/next/oauth.mjs.map +1 -0
  67. package/dist/next/principal.d.ts +64 -0
  68. package/dist/next/principal.mjs +98 -0
  69. package/dist/next/principal.mjs.map +1 -0
  70. package/dist/next/project-ingress.d.ts +37 -0
  71. package/dist/next/project-ingress.mjs +75 -0
  72. package/dist/next/project-ingress.mjs.map +1 -0
  73. package/dist/next/react.mjs +285 -0
  74. package/dist/next/react.mjs.map +1 -0
  75. package/dist/next/sdk/auth.d.ts +5 -0
  76. package/dist/next/sdk/index.d.ts +112 -0
  77. package/dist/next/sdk.mjs +139 -0
  78. package/dist/next/sdk.mjs.map +1 -0
  79. package/dist/next/stream/processor.d.ts +378 -0
  80. package/dist/next/stream/processor.mjs +582 -0
  81. package/dist/next/stream/processor.mjs.map +1 -0
  82. package/dist/next/stream/run.d.ts +58 -0
  83. package/dist/next/stream/run.mjs +40 -0
  84. package/dist/next/stream/run.mjs.map +1 -0
  85. package/dist/next-node.d.ts +15 -0
  86. package/dist/next-node.mjs +51 -0
  87. package/dist/next-node.mjs.map +1 -0
  88. package/dist/node.d.ts +3 -0
  89. package/dist/node.mjs +185 -0
  90. package/dist/node.mjs.map +1 -0
  91. package/dist/processor-host-capabilities-BMFH3KTM.mjs +56 -0
  92. package/dist/processor-host-capabilities-BMFH3KTM.mjs.map +1 -0
  93. package/dist/processors/cloudflare.d.ts +3 -0
  94. package/dist/processors/durable-object-processor-durability.d.ts +79 -0
  95. package/dist/processors/event-consumption-metrics.d.ts +82 -0
  96. package/dist/processors/idempotency.d.ts +13 -0
  97. package/dist/processors/index.d.ts +12 -0
  98. package/dist/processors/processor-contracts.d.ts +342 -0
  99. package/dist/processors/processor-facet.d.ts +186 -0
  100. package/dist/processors/processor-host-capabilities.d.ts +60 -0
  101. package/dist/processors/prompt-sections.d.ts +17 -0
  102. package/dist/processors/rpc-types.d.ts +515 -0
  103. package/dist/processors/schemas.d.ts +102 -0
  104. package/dist/processors/stream-handle.d.ts +45 -0
  105. package/dist/processors/stream-processor-keepalive.d.ts +95 -0
  106. package/dist/processors/stream-processor-registry.d.ts +233 -0
  107. package/dist/processors/stream-processor-runner.d.ts +289 -0
  108. package/dist/processors/stream-processor.d.ts +339 -0
  109. package/dist/processors/stream-runtime-metrics.d.ts +107 -0
  110. package/dist/processors/testing.d.ts +302 -0
  111. package/dist/processors-BoNyeBfQ.mjs +10 -0
  112. package/dist/processors-BoNyeBfQ.mjs.map +1 -0
  113. package/dist/processors-cloudflare.mjs +3 -0
  114. package/dist/processors-testing.mjs +435 -0
  115. package/dist/processors-testing.mjs.map +1 -0
  116. package/dist/processors.mjs +52 -0
  117. package/dist/processors.mjs.map +1 -0
  118. package/dist/protocol-DnK_f2m6.mjs +251 -0
  119. package/dist/protocol-DnK_f2m6.mjs.map +1 -0
  120. package/dist/sdk/capnweb/index.d.ts +2 -0
  121. package/dist/sdk/capnweb/live-state/compact.d.ts +5 -0
  122. package/dist/sdk/capnweb/live-state/diff.d.ts +41 -0
  123. package/dist/sdk/capnweb/live-state/engine.d.ts +44 -0
  124. package/dist/sdk/capnweb/live-state/index.d.ts +41 -0
  125. package/dist/sdk/capnweb/live-state/protocol.d.ts +87 -0
  126. package/dist/sdk/capnweb/live-state/retain.d.ts +23 -0
  127. package/dist/sdk/capnweb/live-state/store.d.ts +20 -0
  128. package/dist/sdk/capnweb/live-state/types.d.ts +11 -0
  129. package/dist/sdk/capnweb/react.d.ts +45 -0
  130. package/dist/sdk/capnweb/react.mjs +316 -0
  131. package/dist/sdk/capnweb/react.mjs.map +1 -0
  132. package/dist/sdk/capnweb.mjs +4 -0
  133. package/dist/sdk/itx/react.d.ts +191 -0
  134. package/dist/sdk/itx/react.mjs +383 -0
  135. package/dist/sdk/itx/react.mjs.map +1 -0
  136. package/dist/sdk-DMB-IM11.mjs +933 -0
  137. package/dist/sdk-DMB-IM11.mjs.map +1 -0
  138. package/dist/sdk.d.ts +339 -0
  139. package/dist/sdk.mjs +2 -0
  140. package/dist/serve-itx.d.ts +46 -0
  141. package/dist/starter-apps/flake-dashboard/app-ref.d.ts +31 -0
  142. package/dist/starter-apps/flake-dashboard/configured-worker.mjs +1055 -0
  143. package/dist/starter-apps/flake-dashboard/configured-worker.mjs.map +1 -0
  144. package/dist/starter-apps/flake-dashboard/contract.d.ts +4839 -0
  145. package/dist/starter-apps/flake-dashboard/contract.mjs +2 -0
  146. package/dist/starter-apps/flake-dashboard/index.d.ts +17 -0
  147. package/dist/starter-apps/flake-dashboard/index.mjs +56 -0
  148. package/dist/starter-apps/flake-dashboard/index.mjs.map +1 -0
  149. package/dist/starter-apps/flake-dashboard/worker.d.ts +4607 -0
  150. package/dist/starter-apps/github-ai-linter/ai-linter.d.ts +8914 -0
  151. package/dist/starter-apps/github-ai-linter/configured-worker.mjs +17987 -0
  152. package/dist/starter-apps/github-ai-linter/configured-worker.mjs.map +1 -0
  153. package/dist/starter-apps/github-ai-linter/contract.d.ts +9193 -0
  154. package/dist/starter-apps/github-ai-linter/index.d.ts +10 -0
  155. package/dist/starter-apps/github-ai-linter/index.mjs +36 -0
  156. package/dist/starter-apps/github-ai-linter/index.mjs.map +1 -0
  157. package/dist/starter-apps/github-ai-linter/prompt.d.ts +13 -0
  158. package/dist/starter-apps/github-ai-linter/review-bot.d.ts +808 -0
  159. package/dist/starter-apps/github-ai-linter/rules.d.ts +34 -0
  160. package/dist/starter-apps/github-ai-linter/worker-ref.d.ts +19 -0
  161. package/dist/starter-apps/github-ai-linter/worker.d.ts +19 -0
  162. package/dist/starter-apps/github-ai-linter/worker.mjs +947 -0
  163. package/dist/starter-apps/github-ai-linter/worker.mjs.map +1 -0
  164. package/dist/starter-apps/guestbook/app-ref.d.ts +27 -0
  165. package/dist/starter-apps/guestbook/client.d.ts +7 -0
  166. package/dist/starter-apps/guestbook/client.mjs +59 -0
  167. package/dist/starter-apps/guestbook/configured-worker.mjs +205 -0
  168. package/dist/starter-apps/guestbook/configured-worker.mjs.map +1 -0
  169. package/dist/starter-apps/guestbook/index.d.ts +9 -0
  170. package/dist/starter-apps/guestbook/index.mjs +31 -0
  171. package/dist/starter-apps/guestbook/index.mjs.map +1 -0
  172. package/dist/starter-apps/guestbook/processor.d.ts +2267 -0
  173. package/dist/starter-apps/guestbook/worker.d.ts +26 -0
  174. package/dist/starter-apps/guestbook/worker.mjs +191 -0
  175. package/dist/starter-apps/guestbook/worker.mjs.map +1 -0
  176. package/dist/starter-apps/media/configured-worker.mjs +577 -0
  177. package/dist/starter-apps/media/configured-worker.mjs.map +1 -0
  178. package/dist/starter-apps/media/index.mjs +36 -0
  179. package/dist/starter-apps/media/index.mjs.map +1 -0
  180. package/dist/starter-apps/media/ref.mjs +20 -0
  181. package/dist/starter-apps/media/ref.mjs.map +1 -0
  182. package/dist/starter-apps/media/worker.mjs +579 -0
  183. package/dist/starter-apps/media/worker.mjs.map +1 -0
  184. package/dist/starter-apps/notes/configured-worker.mjs +6134 -0
  185. package/dist/starter-apps/notes/configured-worker.mjs.map +1 -0
  186. package/dist/starter-apps/notes/index.mjs +23 -0
  187. package/dist/starter-apps/notes/index.mjs.map +1 -0
  188. package/dist/starter-apps/notes/ref.mjs +21 -0
  189. package/dist/starter-apps/notes/ref.mjs.map +1 -0
  190. package/dist/starter-apps/notes/worker.mjs +427 -0
  191. package/dist/starter-apps/notes/worker.mjs.map +1 -0
  192. package/dist/starter-apps/todo/client.mjs +59 -0
  193. package/dist/starter-apps/todo/configured-worker.mjs +2864 -0
  194. package/dist/starter-apps/todo/configured-worker.mjs.map +1 -0
  195. package/dist/starter-apps/todo/index.d.ts +8 -0
  196. package/dist/starter-apps/todo/index.mjs +29 -0
  197. package/dist/starter-apps/todo/index.mjs.map +1 -0
  198. package/dist/stream-processor-keepalive-DAQTP6m3.mjs +2082 -0
  199. package/dist/stream-processor-keepalive-DAQTP6m3.mjs.map +1 -0
  200. package/dist/usingCtx-inzbY1Qz.mjs +57 -0
  201. package/dist/usingCtx-mZx5nsAW.mjs +11800 -0
  202. package/dist/usingCtx-mZx5nsAW.mjs.map +1 -0
  203. package/dist/worker-ref-DZxPDmb_.mjs +390 -0
  204. package/dist/worker-ref-DZxPDmb_.mjs.map +1 -0
  205. package/menubar/Iterate.entitlements +12 -0
  206. package/menubar/Iterate.swift +914 -0
  207. package/menubar/IterateIcon.swift +145 -0
  208. package/menubar/README.md +28 -0
  209. package/menubar/build-menubar-app.sh +59 -0
  210. package/package.json +235 -18
  211. package/dist/cli-DMS4kJph.mjs +0 -868
  212. package/dist/cli-DMS4kJph.mjs.map +0 -1
  213. package/dist/config-DtnR7Lv7.mjs +0 -170
  214. package/dist/config-DtnR7Lv7.mjs.map +0 -1
  215. package/dist/index.d.mts.map +0 -1
  216. package/dist/stream-tui/agent-chat-terminal.d.mts +0 -1
  217. package/dist/stream-tui/agent-chat-terminal.mjs +0 -933
  218. package/dist/stream-tui/agent-chat-terminal.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configured-worker.mjs","names":["z.string","z.array","z.number","z\n .string","z\n .boolean","z.object","z\n .number","z\n .record","#liveAnalyses","#attemptAnalysis","#appendSettlement"],"sources":["../../../src/starter-apps/media/analysis.ts","../../../src/starter-apps/media/ref.ts","../../../src/starter-apps/media/processor.ts","../../../src/starter-apps/media/worker.ts"],"sourcesContent":["// The media analysis pipeline: bytes → ai.toMarkdown (vision model describes\n// the image) → one vision call over the actual pixels returning\n// {title, transcript, tags}. Ported from the mobile capture script\n// (apps/mobile/src/lib/media.ts buildProcessScript, PR #2466) when analysis\n// moved server-side: the phone now appends a cheap media/uploaded event and\n// the MediaApp processor (processor.ts) drives this pipeline as an\n// obligation. The server owns the analysis vocabulary — model, taxonomy,\n// prompt; the mobile app keeps a display-only tag list (lib/media.ts\n// MEDIA_TAGS) kept in sync by hand, same convention as search semantics.\n\n/** Sees the pixels: transcribes text verbatim and picks tags. */\nconst MEDIA_VISION_MODEL = \"@cf/meta/llama-4-scout-17b-16e-instruct\";\n\n/**\n * Starter taxonomy — expect churn. Multi-tag with overlap allowed; the model\n * may also coin up to two novel kebab-case tags, and returning NO tags is an\n * acceptable answer (deliberately conservative — early dogfood tagged\n * everything `bug-report` on wild guesses).\n */\nconst MEDIA_TAG_TAXONOMY: { tag: string; hint: string }[] = [\n { tag: \"screenshot\", hint: \"a captured device screen: app UI, web page, status bar visible\" },\n { tag: \"photo\", hint: \"a camera photograph of the physical world\" },\n { tag: \"transient\", hint: \"one-off info with no lasting value: OTP codes, confirmations\" },\n { tag: \"clipping\", hint: \"a saved post, article, meme, or quote worth keeping\" },\n { tag: \"logistics\", hint: \"tickets, bookings, schedules, travel details, QR codes\" },\n { tag: \"receipt\", hint: \"proof of purchase, invoices, order confirmations\" },\n { tag: \"conversation\", hint: \"chat threads, DMs, emails, comment sections\" },\n { tag: \"code\", hint: \"code, terminals, dev tools, technical docs\" },\n { tag: \"reference\", hint: \"info to keep long-term: settings, lists, instructions\" },\n];\n\nexport type MediaAnalysisResult = {\n /** One-line description of what the image IS — the row's bold first line. */\n title: string;\n /** The vision model's natural-language description — half the search corpus. */\n markdown: string;\n /** Verbatim text visible in the image — the other half. */\n transcript: string;\n tags: string[];\n processedBy: string;\n};\n\n/**\n * The itx slice the pipeline dials — structural on purpose so the real\n * `Project` session satisfies it and tests hand in a plain fake.\n */\ntype MediaAnalysisSession = {\n files: { get(path: string): { bytes(): Promise<Uint8Array> } };\n ai: {\n toMarkdown(document: {\n name: string;\n blob: Uint8Array;\n }): Promise<{ format: string; data?: string; error?: string }>;\n run(model: string, body: unknown): Promise<unknown>;\n };\n integrations: {\n cf: {\n images: {\n transformBytes(input: {\n image: Uint8Array;\n transforms: { width: number }[];\n output: { format: string; quality: number };\n }): Promise<{ bytes: Uint8Array; contentType: string }>;\n };\n };\n };\n};\n\n/**\n * One full analysis of a stored media file. Throws on conversion failure so\n * the caller (the processor's obligation attempt) owns retry/settlement; an\n * unparseable vision answer degrades to empty title/transcript and\n * [\"untagged\"] so failures stay visible instead of hiding an item.\n */\nexport async function analyzeMediaImage(\n session: MediaAnalysisSession,\n input: { path: string; filename: string; contentType: string },\n): Promise<MediaAnalysisResult> {\n // blob takes raw bytes (a Blob cannot cross the RPC boundary); the\n // extension in `name` picks the converter.\n const bytes = await session.files.get(input.path).bytes();\n const described = await session.ai.toMarkdown({ name: input.filename, blob: bytes });\n if (described.format === \"error\") {\n throw new Error(`toMarkdown failed for ${input.filename}: ${described.error}`);\n }\n const markdown = (described.data || \"\").trim();\n\n // Workers AI rejects oversized request bodies (error 3006) — long\n // full-page screenshots hit it. Downscale for the AI call only (the\n // stored original is untouched); if the Images binding can't (e.g. some\n // local dev setups), fall through with the original and let the model\n // call answer.\n let visionBytes = bytes;\n let visionType = input.contentType;\n if (bytes.length > 1_000_000) {\n try {\n const resized = await session.integrations.cf.images.transformBytes({\n image: bytes,\n transforms: [{ width: 1280 }],\n output: { format: \"image/jpeg\", quality: 80 },\n });\n visionBytes = resized.bytes;\n visionType = resized.contentType;\n } catch {}\n }\n\n // One vision call over the actual pixels: title + verbatim transcript +\n // tags in a single JSON answer.\n let binary = \"\";\n for (let i = 0; i < visionBytes.length; i += 32_768) {\n binary += String.fromCharCode(...visionBytes.subarray(i, i + 32_768));\n }\n const answer = await session.ai.run(MEDIA_VISION_MODEL, {\n messages: [\n {\n role: \"user\",\n content: [\n { type: \"text\", text: mediaVisionPrompt() },\n {\n type: \"image_url\",\n image_url: { url: `data:${visionType};base64,${btoa(binary)}` },\n },\n ],\n },\n ],\n max_tokens: 1024,\n });\n return { ...parseVisionAnswer(visionAnswerText(answer)), markdown };\n}\n\n/** Both Workers AI answer shapes: `{ response }` and OpenAI-style choices. */\nfunction visionAnswerText(answer: unknown): string {\n const bag = answer as {\n response?: unknown;\n choices?: { message?: { content?: unknown } }[];\n } | null;\n if (typeof bag?.response === \"string\") return bag.response;\n const content = bag?.choices?.[0]?.message?.content;\n return typeof content === \"string\" ? content : \"\";\n}\n\n/** Extract the JSON object from a chatty model answer, defensively. */\nfunction parseVisionAnswer(text: string): Omit<MediaAnalysisResult, \"markdown\"> {\n let title = \"\";\n let transcript = \"\";\n let tags = [\"untagged\"];\n const match = text.match(/\\{[\\s\\S]*\\}/);\n if (match) {\n try {\n const parsed = JSON.parse(match[0]) as {\n title?: unknown;\n transcript?: unknown;\n tags?: unknown;\n };\n if (typeof parsed.title === \"string\") title = parsed.title.trim().slice(0, 120);\n if (typeof parsed.transcript === \"string\") transcript = parsed.transcript.trim();\n if (Array.isArray(parsed.tags)) {\n tags = [\n ...new Set(\n parsed.tags\n .filter((tag): tag is string => typeof tag === \"string\")\n .map((tag) =>\n tag\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\"),\n )\n .filter((tag) => tag.length > 0 && tag.length <= 30),\n ),\n ].slice(0, 6);\n }\n } catch {}\n }\n return { title, transcript, tags, processedBy: MEDIA_VISION_MODEL };\n}\n\nfunction mediaVisionPrompt(): string {\n const lines = MEDIA_TAG_TAXONOMY.map(({ tag, hint }) => `- \"${tag}\": ${hint}`);\n return [\n 'Reply with ONLY a JSON object: {\"title\": string, \"transcript\": string, \"tags\": string[]}.',\n \"title: ONE line saying what the image IS, specific not generic — 'Trenitalia ticket Rome→Florence 09:45', never 'Screenshot' or 'Image Description'.\",\n \"transcript: ALL text visible in the image, verbatim, reading order. Empty string if there is none.\",\n \"tags: pick from the list below. Include a tag ONLY when the image clearly shows it — no guesses.\",\n \"Fewer tags is better; an empty array is a fine answer. Overlap is allowed.\",\n ...lines,\n \"You may add at most 2 extra kebab-case tags if something important has no tag above.\",\n ].join(\"\\n\");\n}\n","// The MediaApp worker ref as a dependency-free literal: the mobile e2e (a\n// plain-node tsconfig with no Cloudflare lib types) needs the ref without\n// pulling in sdk.ts. app-ref.ts re-exports this with the satisfies check\n// that keeps it honest against StatefulDynamicWorkerRef.\nexport const mediaStreamPath = \"/media\";\n\nexport const mediaWorkerRef = {\n className: \"MediaApp\",\n durableWorkerKey: \"app-media-stream\",\n path: \"/\",\n source: {\n createWorker: {\n entryPoint: \"node_modules/iterate/dist/starter-apps/media/configured-worker.mjs\",\n files: {\n include: [\"package.json\"],\n repoPath: \"/repos/config\",\n type: \"repo\" as const,\n },\n },\n },\n type: \"stateful\" as const,\n};\n","// The media stream processor: folds the mobile app's capture events on\n// /media (vocab shared with apps/mobile/src/lib/media.ts) into a per-item\n// map, latest processing winning — AND owns the server-side analysis\n// reaction. A phone appends a cheap durable media/uploaded event right after\n// the bytes land; this processor treats it as an open obligation, drives the\n// vision pipeline (analysis.ts) via the injected `analyze` dep, and settles\n// with ONE terminal media/processed event whose payload carries the result\n// union (`error: null` on success). Obligation doctrine:\n// docs/writing-stream-processors.md; GithubAiLinterProcessor is the sibling\n// userland precedent. The MediaApp worker hosts this with `recovery = true`,\n// so an eviction mid-analysis is revived by the keepalive and the caught-up\n// pass restarts still-open obligations from reduced state.\nimport { z } from \"zod\";\nimport {\n defineProcessorContract,\n isIdempotencyConflict,\n StreamProcessor,\n} from \"../../processors/index.ts\";\nimport type {\n EmittedInput,\n ProcessEventArgs,\n ProcessorState,\n ReduceArgs,\n} from \"../../processors/index.ts\";\nimport type { MediaAnalysisResult } from \"./analysis.ts\";\n\n/**\n * An analysis obligation is abandoned (settled as failed, without dialing\n * the AI) when its requesting event is older than this — the staleness\n * doctrine's horizon. Generous on purpose: a phone can upload while the\n * analyzer is broken and still get analyzed when the fix deploys; Re-analyze\n * covers anything older.\n */\nexport const MEDIA_ANALYSIS_EXPIRY_MS = 24 * 60 * 60 * 1000;\n\n/** Tries per attempt, with backoff between them — covers the transient\n * Workers AI failure class (\"8005: Internal server error\") observed in prod\n * without an extra durable event per retry. */\nconst ANALYSIS_TRIES = 3;\nconst ANALYSIS_RETRY_BACKOFF_MS = [2_000, 8_000];\n\n/**\n * Attempts started per caught-up pass, matching the phone's old 3-wide\n * pipeline. A 19-item Delete-all re-sync once fired 19 parallel vision\n * pipelines from one pass and Workers AI answered with 8004s and 60s\n * binding timeouts — the in-attempt retries all landed inside the same\n * overloaded burst. The rest of the queue needs no timer: every settlement\n * append comes back through this processor's own delivery and the next\n * caught-up pass starts the next wave.\n */\nconst MAX_CONCURRENT_ANALYSES = 3;\n\nconst processingFields = {\n title: z.string().default(\"\").meta({\n description: \"One-line description of what the image IS (pre-title events fold to empty).\",\n }),\n markdown: z.string().meta({ description: \"Vision-model description — half the search corpus.\" }),\n transcript: z.string().meta({ description: \"Verbatim OCR of visible text — the other half.\" }),\n tags: z.array(z.string()).meta({ description: \"Conservative multi-label tags.\" }),\n processedBy: z.string().meta({ description: \"Model id that produced this processing.\" }),\n};\n\nconst fileFields = {\n stableKey: z.string().meta({ description: \"Content hash — the item's identity.\" }),\n path: z.string().meta({ description: \"itx.files path holding the bytes.\" }),\n filename: z.string().meta({ description: \"Original filename as picked/synced.\" }),\n contentType: z.string(),\n width: z.number(),\n height: z.number(),\n source: z\n .string()\n .default(\"picker\")\n .meta({ description: '\"picker\", \"library-sync\", or \"note\" (a note attachment).' }),\n capturedAt: z\n .string()\n .nullable()\n .default(null)\n .meta({ description: \"Asset creation time (ISO) when the source knew it.\" }),\n isScreenshot: z\n .boolean()\n .nullable()\n .default(null)\n .meta({ description: \"iOS mediaSubtypes screenshot flag.\" }),\n};\n\nconst MediaItem = z.object({\n ...fileFields,\n capturedEventAt: z.string().meta({ description: \"Stream time the capture committed.\" }),\n ...processingFields,\n analysisError: z\n .string()\n .nullable()\n .default(null)\n .meta({\n description:\n \"The latest analysis settlement's failure, or null. Rows born from \" +\n \"media/uploaded exist regardless of analysis outcome; a terminal failure lands here.\",\n }),\n settledRequestOffset: z\n .number()\n .nullable()\n .default(null)\n .meta({\n description:\n \"requestOffset of the last APPLIED settlement — settlements apply monotonically, so \" +\n \"a late one answering an older request can never overwrite a newer result (null until \" +\n \"a requestOffset-carrying settlement lands; legacy settlements don't advance it).\",\n }),\n});\n\nexport type MediaItem = z.infer<typeof MediaItem>;\n\nconst PendingAnalysis = z.object({\n stableKey: z.string(),\n path: z.string(),\n filename: z.string(),\n contentType: z.string(),\n requestOffset: z.number().meta({\n description:\n \"Offset of the uploaded/reanalyze event that opened this obligation — the \" +\n \"settlement's idempotency identity.\",\n }),\n expiresAtMs: z.number().meta({\n description:\n \"Epoch ms (request createdAt + MEDIA_ANALYSIS_EXPIRY_MS); past it the \" +\n \"obligation settles as expired without dialing the AI.\",\n }),\n});\n\ntype PendingAnalysis = z.infer<typeof PendingAnalysis>;\n\nexport const MediaProcessorContract = defineProcessorContract({\n slug: \"media\",\n version: \"0.2.1\",\n description:\n \"Reduces captured media (screenshots/photos) on /media into a searchable index, and drives \" +\n \"server-side vision analysis of uploaded items (obligation pattern).\",\n stateSchema: z.object({\n items: z\n .record(z.string(), MediaItem)\n .default({})\n .meta({ description: \"Items by stableKey, latest processing overlaid.\" }),\n pendingAnalyses: z\n .record(z.string(), PendingAnalysis)\n .default({})\n .meta({\n description:\n \"Open analysis obligations by stableKey (latest request wins); settled by one \" +\n \"media/processed event each.\",\n }),\n }),\n events: {\n \"events.iterate.com/media/uploaded\": {\n description:\n \"A media item's bytes landed in project files: the phone appends this cheap durable \" +\n \"fact right after files.put (metadata only — no analysis yet), idempotency-keyed by \" +\n \"content hash + wipe generation, sharing the media/captured key scheme so an item \" +\n \"already captured never re-uploads as a duplicate. Opens an analysis obligation.\",\n payloadSchema: z.object(fileFields),\n examples: [\n {\n description: \"A synced screenshot, uploaded and awaiting analysis.\",\n payload: {\n stableKey: \"abc123\",\n path: \"/media/abc123-IMG_0001.png\",\n filename: \"IMG_0001.png\",\n contentType: \"image/png\",\n width: 1170,\n height: 2532,\n source: \"library-sync\",\n capturedAt: \"2026-08-10T09:00:00.000Z\",\n isScreenshot: true,\n },\n },\n ],\n },\n \"events.iterate.com/media/reanalyze-requested\": {\n description:\n \"Re-analyze an existing item (the app's Re-analyze button): opens an analysis \" +\n \"obligation for it; the settlement overlays the item's processing fields.\",\n payloadSchema: z.object({ stableKey: z.string() }),\n examples: [{ description: \"A user-requested re-run.\", payload: { stableKey: \"abc123\" } }],\n },\n \"events.iterate.com/media/captured\": {\n description:\n \"LEGACY (pre media/uploaded): a media item entered the project with its first vision \" +\n \"processing inline, appended by the old phone-driven capture script. Still folded so \" +\n \"history keeps rendering; nothing appends it anymore.\",\n payloadSchema: z.object({\n ...fileFields,\n ...processingFields,\n }),\n examples: [\n {\n description: \"A synced screenshot with its first processing.\",\n payload: {\n stableKey: \"abc123\",\n path: \"/media/abc123-IMG_0001.png\",\n filename: \"IMG_0001.png\",\n contentType: \"image/png\",\n width: 1170,\n height: 2532,\n source: \"library-sync\",\n capturedAt: \"2026-08-10T09:00:00.000Z\",\n isScreenshot: true,\n markdown: \"A train ticket from Rome to Florence.\",\n transcript: \"Trenitalia 09:45\",\n tags: [\"screenshot\", \"logistics\"],\n processedBy: \"@cf/meta/llama-4-scout-17b-16e-instruct\",\n },\n },\n ],\n },\n \"events.iterate.com/media/wiped\": {\n description:\n \"Everything before this tombstone is gone: the wipe script deleted the stored files and \" +\n \"every derivation (phone list, this fold) resets. Deliberate per-invocation idempotency key.\",\n payloadSchema: z.object({\n deletedFiles: z.number().meta({ description: \"Files actually deleted.\" }),\n items: z.number().meta({ description: \"Items that existed at wipe time.\" }),\n }),\n examples: [\n { description: \"A from-scratch reset.\", payload: { deletedFiles: 24, items: 24 } },\n ],\n },\n \"events.iterate.com/media/processed\": {\n description:\n \"One analysis settlement (the obligation's single terminal event): on success the \" +\n \"processing fields overlay the item's, `error: null`; on terminal failure `error` says \" +\n \"why and the item's previous fields stay. Also appended by legacy phone-driven \" +\n \"re-analysis (no error/requestOffset).\",\n payloadSchema: z.object({\n stableKey: z.string(),\n ...processingFields,\n error: z.string().nullable().default(null).meta({\n description: \"Terminal analysis failure, or null on success.\",\n }),\n requestOffset: z.number().nullable().default(null).meta({\n description: \"The uploaded/reanalyze event this settles (null on legacy appends).\",\n }),\n }),\n examples: [\n {\n description: \"A successful server-side analysis of an uploaded item.\",\n payload: {\n stableKey: \"abc123\",\n title: \"Trenitalia ticket Rome→Florence 09:45\",\n markdown: \"A train ticket from Rome to Florence.\",\n transcript: \"Trenitalia 09:45\",\n tags: [\"screenshot\", \"logistics\"],\n processedBy: \"@cf/meta/llama-4-scout-17b-16e-instruct\",\n error: null,\n requestOffset: 12,\n },\n },\n ],\n },\n },\n consumes: [\n \"events.iterate.com/media/uploaded\",\n \"events.iterate.com/media/reanalyze-requested\",\n \"events.iterate.com/media/captured\",\n \"events.iterate.com/media/processed\",\n \"events.iterate.com/media/wiped\",\n ],\n emits: [\"events.iterate.com/media/processed\"],\n});\nexport type MediaProcessorContract = typeof MediaProcessorContract;\n\nexport type MediaState = ProcessorState<MediaProcessorContract>;\n\ntype MediaProcessorDeps = {\n /** The vision pipeline (analysis.ts), injected so tests run in plain node. */\n analyze: (input: {\n path: string;\n filename: string;\n contentType: string;\n }) => Promise<MediaAnalysisResult>;\n now: () => number;\n sleep: (ms: number) => Promise<void>;\n};\n\nexport class MediaProcessor extends StreamProcessor<MediaProcessorContract, MediaProcessorDeps> {\n readonly contract = MediaProcessorContract;\n\n /**\n * Runtime-only attempts by stableKey. The uploaded/reanalyze +\n * processed events are the durable truth: after an eviction this set is\n * empty and the next caught-up pass restarts any still-open obligation.\n */\n readonly #liveAnalyses = new Set<string>();\n\n protected override reduce({ event, state }: ReduceArgs<MediaProcessorContract>) {\n switch (event.type) {\n case \"events.iterate.com/media/uploaded\": {\n // A stableKey already present (legacy captured, or a duplicate\n // upload racing the phone's getEvent check) folds to a no-op — no\n // duplicate row, no redundant analysis.\n if (state.items[event.payload.stableKey] !== undefined) return state;\n return {\n ...state,\n items: {\n ...state.items,\n [event.payload.stableKey]: {\n ...event.payload,\n capturedEventAt: event.createdAt,\n title: \"\",\n markdown: \"\",\n transcript: \"\",\n tags: [],\n processedBy: \"\",\n analysisError: null,\n settledRequestOffset: null,\n },\n },\n pendingAnalyses: {\n ...state.pendingAnalyses,\n [event.payload.stableKey]: pendingAnalysisFor(event),\n },\n };\n }\n case \"events.iterate.com/media/reanalyze-requested\": {\n const item = state.items[event.payload.stableKey];\n // Nothing to re-analyze for an unknown item — skip rather than\n // invent an obligation with no file behind it.\n if (item === undefined) return state;\n return {\n ...state,\n pendingAnalyses: {\n ...state.pendingAnalyses,\n // Latest request wins: a reanalyze during a pending initial\n // analysis collapses to one obligation (one settlement key).\n [item.stableKey]: {\n stableKey: item.stableKey,\n path: item.path,\n filename: item.filename,\n contentType: item.contentType,\n requestOffset: event.offset,\n expiresAtMs: Date.parse(event.createdAt) + MEDIA_ANALYSIS_EXPIRY_MS,\n },\n },\n };\n }\n case \"events.iterate.com/media/captured\": {\n // Idempotency-keyed at the source; a duplicate folds to a no-op.\n if (state.items[event.payload.stableKey] !== undefined) return state;\n return {\n ...state,\n items: {\n ...state.items,\n [event.payload.stableKey]: {\n ...event.payload,\n capturedEventAt: event.createdAt,\n analysisError: null,\n settledRequestOffset: null,\n },\n },\n };\n }\n case \"events.iterate.com/media/wiped\":\n return { ...state, items: {}, pendingAnalyses: {} };\n case \"events.iterate.com/media/processed\": {\n const pendingEntry = state.pendingAnalyses[event.payload.stableKey];\n const existing = state.items[event.payload.stableKey];\n // Stale-result guard, MONOTONIC by requestOffset: a late settlement\n // answering a SUPERSEDED request — e.g. a pre-wipe attempt racing\n // Delete-all + re-upload — must neither clear the newer generation's\n // obligation nor overwrite/poison an already-applied newer result,\n // regardless of commit order. The floor is whichever is higher: the\n // open obligation's request or the last applied settlement's. Legacy\n // appends carry no requestOffset (explicit undefined check — `||`\n // would swallow a legitimate offset of 0), always apply, and never\n // advance the floor — kept in lockstep with the phone's\n // deriveMediaList.\n const requestOffset =\n event.payload.requestOffset === undefined ? null : event.payload.requestOffset;\n const settledFloor = Math.max(\n pendingEntry === undefined ? 0 : pendingEntry.requestOffset,\n existing?.settledRequestOffset || 0,\n );\n if (requestOffset !== null && requestOffset < settledFloor) return state;\n const { [event.payload.stableKey]: _settled, ...pendingAnalyses } = state.pendingAnalyses;\n // A processed event for an unknown item (e.g. pre-rename history)\n // has nothing to overlay — skip rather than invent a partial item.\n if (existing === undefined) return { ...state, pendingAnalyses };\n // `||` folds legacy payloads (no error field, reduced without the\n // contract parse in old states) into the success arm.\n const error = event.payload.error || null;\n const settledRequestOffset =\n requestOffset === null ? existing.settledRequestOffset : requestOffset;\n const item =\n error === null\n ? {\n ...existing,\n title: event.payload.title,\n markdown: event.payload.markdown,\n transcript: event.payload.transcript,\n tags: event.payload.tags,\n processedBy: event.payload.processedBy,\n analysisError: null,\n settledRequestOffset,\n }\n : // A failed analysis keeps whatever the item already shows; the\n // failure itself becomes visible on the row.\n { ...existing, analysisError: error, settledRequestOffset };\n return {\n ...state,\n items: { ...state.items, [event.payload.stableKey]: item },\n pendingAnalyses,\n };\n }\n default:\n return state;\n }\n }\n\n protected override processEvent(args: ProcessEventArgs<MediaProcessorContract>): undefined {\n // Behind head, a settlement may already sit in an unseen page — acting\n // early would re-run a settled analysis.\n if (!args.delivery.caughtUp) return;\n const now = this.deps.now();\n const expired: PendingAnalysis[] = [];\n for (const pending of Object.values(args.state.pendingAnalyses)) {\n if (this.#liveAnalyses.has(pending.stableKey)) continue;\n if (now >= pending.expiresAtMs) {\n expired.push(pending);\n continue;\n }\n // Bounded wave: leave the rest pending — their turn comes when a\n // settlement append wakes the next caught-up pass.\n if (this.#liveAnalyses.size >= MAX_CONCURRENT_ANALYSES) continue;\n // Registered synchronously before any await so this same pass never\n // classifies its own attempt as undriven.\n this.#liveAnalyses.add(pending.stableKey);\n // A dropped attempt is recovered from the still-open obligation on the\n // next caught-up/revival pass (the worker hosts this with recovery on).\n args.runInBackground(async () => {\n try {\n const settlement = await this.#attemptAnalysis(pending);\n await this.#appendSettlement(args.append, pending, settlement);\n } finally {\n this.#liveAnalyses.delete(pending.stableKey);\n }\n });\n }\n if (expired.length === 0) return;\n // Short must-happen appends: an expired obligation's settlement must\n // land even if this incarnation dies right after the pass — otherwise\n // the row shows \"Analyzing…\" forever.\n args.blockProcessorWhile(async () => {\n for (const pending of expired) {\n await this.#appendSettlement(args.append, pending, {\n error:\n \"analysis window expired before it could run \" +\n `(older than ${MEDIA_ANALYSIS_EXPIRY_MS / 3_600_000}h) — use Re-analyze to retry`,\n });\n }\n });\n }\n\n /** One attempt = up to {@link ANALYSIS_TRIES} tries with short backoff. */\n async #attemptAnalysis(\n pending: PendingAnalysis,\n ): Promise<{ result: MediaAnalysisResult } | { error: string }> {\n let lastError = \"analysis failed\";\n for (let tryIndex = 0; tryIndex < ANALYSIS_TRIES; tryIndex++) {\n if (tryIndex > 0) {\n await this.deps.sleep(\n ANALYSIS_RETRY_BACKOFF_MS[Math.min(tryIndex - 1, ANALYSIS_RETRY_BACKOFF_MS.length - 1)]!,\n );\n }\n try {\n return { result: await this.deps.analyze(pending) };\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n }\n return { error: lastError.slice(0, 2_000) };\n }\n\n /**\n * The obligation's single terminal event. The key is state-derived and\n * deterministic per obligation (`@<stableKey>:<requestOffset>`); bodies\n * contain AI output, so two racing incarnations can collide\n * same-key/different-body — the first committed settlement is the\n * authority and the loser tolerates the conflict (ai-linter shape).\n */\n async #appendSettlement(\n append: ProcessEventArgs<MediaProcessorContract>[\"append\"],\n pending: PendingAnalysis,\n outcome: { result: MediaAnalysisResult } | { error: string },\n ): Promise<void> {\n const event: EmittedInput<MediaProcessorContract> = {\n type: \"events.iterate.com/media/processed\",\n idempotencyKey: this.idempotencyKey(\n `analysis-settled@${pending.stableKey}:${pending.requestOffset}`,\n ),\n payload: {\n stableKey: pending.stableKey,\n requestOffset: pending.requestOffset,\n ...(\"result\" in outcome\n ? { ...outcome.result, error: null }\n : {\n title: \"\",\n markdown: \"\",\n transcript: \"\",\n tags: [],\n processedBy: \"\",\n error: outcome.error,\n }),\n },\n };\n try {\n await append(event);\n } catch (error) {\n if (!isIdempotencyConflict(error)) throw error;\n }\n }\n}\n\nfunction pendingAnalysisFor(event: {\n createdAt: string;\n offset: number;\n payload: { stableKey: string; path: string; filename: string; contentType: string };\n}): PendingAnalysis {\n return {\n stableKey: event.payload.stableKey,\n path: event.payload.path,\n filename: event.payload.filename,\n contentType: event.payload.contentType,\n requestOffset: event.offset,\n expiresAtMs: Date.parse(event.createdAt) + MEDIA_ANALYSIS_EXPIRY_MS,\n };\n}\n\n/**\n * Search semantics shared with the phone's client-side filter\n * (apps/mobile/src/lib/media.ts filterMedia — kept in sync by hand, the two\n * runtimes can't share a module yet): every whitespace-separated term must\n * appear in description, transcript, filename, stored name, or tags; every\n * selected tag must be present. Newest first.\n */\nexport function searchMediaItems(\n state: MediaState,\n query: { q?: string; tags?: string[]; limit?: number },\n): MediaItem[] {\n const terms = (query.q || \"\").toLowerCase().split(/\\s+/).filter(Boolean);\n const requiredTags = query.tags || [];\n return Object.values(state.items)\n .filter((item) => {\n const storedName = (item.path.split(\"/\").at(-1) || \"\").replace(/^[0-9a-f]{32,}-/, \"\");\n const haystack =\n `${item.title} ${item.markdown} ${item.transcript} ${item.filename} ${storedName} ${item.tags.join(\" \")}`.toLowerCase();\n return (\n terms.every((term) => haystack.includes(term)) &&\n requiredTags.every((tag) => item.tags.includes(tag))\n );\n })\n .sort((a, b) =>\n (b.capturedAt || b.capturedEventAt).localeCompare(a.capturedAt || a.capturedEventAt),\n )\n .slice(0, query.limit || 20);\n}\n","// The MediaApp Durable Object: hosts the media stream processor — the fold\n// AND the server-side analysis obligations (processor.ts) — and exposes the\n// query surface (search/list/get) that gets mounted at `itx.media`. Search\n// returns signed image URLs so an agent's answer can show the actual\n// screenshot. No HTTP page — this app is an API, not a site.\nimport {\n StreamProcessorDurableObject,\n type ProcessorHostDeps,\n type StreamEvent,\n} from \"../../sdk.ts\";\nimport { analyzeMediaImage } from \"./analysis.ts\";\nimport { mediaStreamPath } from \"./app-ref.ts\";\nimport { MediaProcessor, searchMediaItems, type MediaItem, type MediaState } from \"./processor.ts\";\n\nexport type MediaSearchHit = MediaItem & {\n /** Signed https URL for the image itself — paste into chat to show it. */\n url: string;\n};\n\nexport class MediaApp extends StreamProcessorDurableObject<MediaState> {\n protected readonly streamPath = mediaStreamPath;\n /** Analysis obligations must survive eviction: the keepalive revives this\n * DO and the caught-up pass restarts still-open work from reduced state. */\n protected override readonly recovery = true;\n protected createProcessor(deps: ProcessorHostDeps) {\n return new MediaProcessor({\n ...deps,\n now: Date.now,\n sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n analyze: async (input) => {\n using project = await this.env.ITX.get();\n return await analyzeMediaImage(project, input);\n },\n });\n }\n\n /** Project-worker event delivery calls this after a durable /media event\n * commits. Catch-up owns validation, ordering, checkpointing, and dedupe. */\n async syncEvent(event: StreamEvent): Promise<void> {\n if (event.path !== mediaStreamPath) return;\n const registry = await this.registry();\n await registry.catchUp(\"media\");\n registry.refreshLive();\n }\n\n /**\n * Keyword search over descriptions, OCR transcripts, filenames, and tags —\n * \"train ticket\" finds the train ticket because the vision model's prose\n * says so. `tags` all must be present; newest first; default limit 20.\n */\n async search(query: { q?: string; tags?: string[]; limit?: number }): Promise<MediaSearchHit[]> {\n const registry = await this.registry();\n await registry.catchUp(\"media\");\n const { state } = await this.snapshot();\n const hits = searchMediaItems(state, query);\n using project = await this.env.ITX.get();\n return await Promise.all(\n hits.map(async (item) => ({ ...item, url: await project.files.get(item.path).url() })),\n );\n }\n\n /** Newest items, no filtering — `search` with an empty query. */\n async list(query: { limit?: number }): Promise<MediaSearchHit[]> {\n return this.search({ limit: query.limit });\n }\n\n /** One item by its content hash, or null. */\n async get(stableKey: string): Promise<MediaItem | null> {\n const registry = await this.registry();\n await registry.catchUp(\"media\");\n const { state } = await this.snapshot();\n return state.items[stableKey] || null;\n }\n}\n"],"mappings":";;;;AAWA,MAAM,qBAAqB;;;;;;;AAQ3B,MAAM,qBAAsD;CAC1D;EAAE,KAAK;EAAc,MAAM;CAAiE;CAC5F;EAAE,KAAK;EAAS,MAAM;CAA4C;CAClE;EAAE,KAAK;EAAa,MAAM;CAA+D;CACzF;EAAE,KAAK;EAAY,MAAM;CAAsD;CAC/E;EAAE,KAAK;EAAa,MAAM;CAAyD;CACnF;EAAE,KAAK;EAAW,MAAM;CAAmD;CAC3E;EAAE,KAAK;EAAgB,MAAM;CAA8C;CAC3E;EAAE,KAAK;EAAQ,MAAM;CAA6C;CAClE;EAAE,KAAK;EAAa,MAAM;CAAwD;AACpF;;;;;;;AA6CA,eAAsB,kBACpB,SACA,OAC8B;CAG9B,MAAM,QAAQ,MAAM,QAAQ,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM;CACxD,MAAM,YAAY,MAAM,QAAQ,GAAG,WAAW;EAAE,MAAM,MAAM;EAAU,MAAM;CAAM,CAAC;CACnF,IAAI,UAAU,WAAW,SACvB,MAAM,IAAI,MAAM,yBAAyB,MAAM,SAAS,IAAI,UAAU,OAAO;CAE/E,MAAM,YAAY,UAAU,QAAQ,GAAA,CAAI,KAAK;CAO7C,IAAI,cAAc;CAClB,IAAI,aAAa,MAAM;CACvB,IAAI,MAAM,SAAS,KACjB,IAAI;EACF,MAAM,UAAU,MAAM,QAAQ,aAAa,GAAG,OAAO,eAAe;GAClE,OAAO;GACP,YAAY,CAAC,EAAE,OAAO,KAAK,CAAC;GAC5B,QAAQ;IAAE,QAAQ;IAAc,SAAS;GAAG;EAC9C,CAAC;EACD,cAAc,QAAQ;EACtB,aAAa,QAAQ;CACvB,QAAQ,CAAC;CAKX,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,OAC3C,UAAU,OAAO,aAAa,GAAG,YAAY,SAAS,GAAG,IAAI,KAAM,CAAC;CAiBtE,OAAO;EAAE,GAAG,kBAAkB,iBAAiB,MAf1B,QAAQ,GAAG,IAAI,oBAAoB;GACtD,UAAU,CACR;IACE,MAAM;IACN,SAAS,CACP;KAAE,MAAM;KAAQ,MAAM,kBAAkB;IAAE,GAC1C;KACE,MAAM;KACN,WAAW,EAAE,KAAK,QAAQ,WAAW,UAAU,KAAK,MAAM,IAAI;IAChE,CACF;GACF,CACF;GACA,YAAY;EACd,CAAC,CACoD,CAAC;EAAG;CAAS;AACpE;;AAGA,SAAS,iBAAiB,QAAyB;CACjD,MAAM,MAAM;CAIZ,IAAI,OAAO,KAAK,aAAa,UAAU,OAAO,IAAI;CAClD,MAAM,UAAU,KAAK,UAAU,EAAE,EAAE,SAAS;CAC5C,OAAO,OAAO,YAAY,WAAW,UAAU;AACjD;;AAGA,SAAS,kBAAkB,MAAqD;CAC9E,IAAI,QAAQ;CACZ,IAAI,aAAa;CACjB,IAAI,OAAO,CAAC,UAAU;CACtB,MAAM,QAAQ,KAAK,MAAM,aAAa;CACtC,IAAI,OACF,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM,EAAE;EAKlC,IAAI,OAAO,OAAO,UAAU,UAAU,QAAQ,OAAO,MAAM,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG;EAC9E,IAAI,OAAO,OAAO,eAAe,UAAU,aAAa,OAAO,WAAW,KAAK;EAC/E,IAAI,MAAM,QAAQ,OAAO,IAAI,GAC3B,OAAO,CACL,GAAG,IAAI,IACL,OAAO,KACJ,QAAQ,QAAuB,OAAO,QAAQ,QAAQ,CAAC,CACvD,KAAK,QACJ,IACG,YAAY,CAAC,CACb,KAAK,CAAC,CACN,QAAQ,gBAAgB,GAAG,CAAC,CAC5B,QAAQ,YAAY,EAAE,CAC3B,CAAC,CACA,QAAQ,QAAQ,IAAI,SAAS,KAAK,IAAI,UAAU,EAAE,CACvD,CACF,CAAC,CAAC,MAAM,GAAG,CAAC;CAEhB,QAAQ,CAAC;CAEX,OAAO;EAAE;EAAO;EAAY;EAAM,aAAa;CAAmB;AACpE;AAEA,SAAS,oBAA4B;CAEnC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,GAPY,mBAAmB,KAAK,EAAE,KAAK,WAAW,MAAM,IAAI,KAAK,MAO9D;EACP;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;ACxLA,MAAa,kBAAkB;;;;;;;;;;AC6B/B,MAAa,2BAA2B,OAAU,KAAK;;;;AAKvD,MAAM,iBAAiB;AACvB,MAAM,4BAA4B,CAAC,KAAO,GAAK;;;;;;;;;;AAW/C,MAAM,0BAA0B;AAEhC,MAAM,mBAAmB;CACvB,OAAOA,OAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,EACjC,aAAa,8EACf,CAAC;CACD,UAAUA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,qDAAqD,CAAC;CAC/F,YAAYA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,iDAAiD,CAAC;CAC7F,MAAMC,MAAQD,OAAS,CAAC,CAAC,CAAC,KAAK,EAAE,aAAa,iCAAiC,CAAC;CAChF,aAAaA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,0CAA0C,CAAC;AACzF;AAEA,MAAM,aAAa;CACjB,WAAWA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,sCAAsC,CAAC;CACjF,MAAMA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,oCAAoC,CAAC;CAC1E,UAAUA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,sCAAsC,CAAC;CAChF,aAAaA,OAAS;CACtB,OAAOE,OAAS;CAChB,QAAQA,OAAS;CACjB,QAAQC,OACE,CAAC,CACR,QAAQ,QAAQ,CAAC,CACjB,KAAK,EAAE,aAAa,iEAA2D,CAAC;CACnF,YAAYA,OACF,CAAC,CACR,SAAS,CAAC,CACV,QAAQ,IAAI,CAAC,CACb,KAAK,EAAE,aAAa,qDAAqD,CAAC;CAC7E,cAAcC,QACH,CAAC,CACT,SAAS,CAAC,CACV,QAAQ,IAAI,CAAC,CACb,KAAK,EAAE,aAAa,qCAAqC,CAAC;AAC/D;AAEA,MAAM,YAAYC,OAAS;CACzB,GAAG;CACH,iBAAiBL,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,qCAAqC,CAAC;CACtF,GAAG;CACH,eAAeG,OACL,CAAC,CACR,SAAS,CAAC,CACV,QAAQ,IAAI,CAAC,CACb,KAAK,EACJ,aACE,wJAEJ,CAAC;CACH,sBAAsBG,OACZ,CAAC,CACR,SAAS,CAAC,CACV,QAAQ,IAAI,CAAC,CACb,KAAK,EACJ,aACE,2PAGJ,CAAC;AACL,CAAC;AAID,MAAM,kBAAkBD,OAAS;CAC/B,WAAWL,OAAS;CACpB,MAAMA,OAAS;CACf,UAAUA,OAAS;CACnB,aAAaA,OAAS;CACtB,eAAeE,OAAS,CAAC,CAAC,KAAK,EAC7B,aACE,8GAEJ,CAAC;CACD,aAAaA,OAAS,CAAC,CAAC,KAAK,EAC3B,aACE,6HAEJ,CAAC;AACH,CAAC;AAID,MAAa,yBAAyB,wBAAwB;CAC5D,MAAM;CACN,SAAS;CACT,aACE;CAEF,aAAaG,OAAS;EACpB,OAAOE,OACGP,OAAS,GAAG,SAAS,CAAC,CAC7B,QAAQ,CAAC,CAAC,CAAC,CACX,KAAK,EAAE,aAAa,kDAAkD,CAAC;EAC1E,iBAAiBO,OACPP,OAAS,GAAG,eAAe,CAAC,CACnC,QAAQ,CAAC,CAAC,CAAC,CACX,KAAK,EACJ,aACE,2GAEJ,CAAC;CACL,CAAC;CACD,QAAQ;EACN,qCAAqC;GACnC,aACE;GAIF,eAAeK,OAAS,UAAU;GAClC,UAAU,CACR;IACE,aAAa;IACb,SAAS;KACP,WAAW;KACX,MAAM;KACN,UAAU;KACV,aAAa;KACb,OAAO;KACP,QAAQ;KACR,QAAQ;KACR,YAAY;KACZ,cAAc;IAChB;GACF,CACF;EACF;EACA,gDAAgD;GAC9C,aACE;GAEF,eAAeA,OAAS,EAAE,WAAWL,OAAS,EAAE,CAAC;GACjD,UAAU,CAAC;IAAE,aAAa;IAA4B,SAAS,EAAE,WAAW,SAAS;GAAE,CAAC;EAC1F;EACA,qCAAqC;GACnC,aACE;GAGF,eAAeK,OAAS;IACtB,GAAG;IACH,GAAG;GACL,CAAC;GACD,UAAU,CACR;IACE,aAAa;IACb,SAAS;KACP,WAAW;KACX,MAAM;KACN,UAAU;KACV,aAAa;KACb,OAAO;KACP,QAAQ;KACR,QAAQ;KACR,YAAY;KACZ,cAAc;KACd,UAAU;KACV,YAAY;KACZ,MAAM,CAAC,cAAc,WAAW;KAChC,aAAa;IACf;GACF,CACF;EACF;EACA,kCAAkC;GAChC,aACE;GAEF,eAAeA,OAAS;IACtB,cAAcH,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,0BAA0B,CAAC;IACxE,OAAOA,OAAS,CAAC,CAAC,KAAK,EAAE,aAAa,mCAAmC,CAAC;GAC5E,CAAC;GACD,UAAU,CACR;IAAE,aAAa;IAAyB,SAAS;KAAE,cAAc;KAAI,OAAO;IAAG;GAAE,CACnF;EACF;EACA,sCAAsC;GACpC,aACE;GAIF,eAAeG,OAAS;IACtB,WAAWL,OAAS;IACpB,GAAG;IACH,OAAOA,OAAS,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EAC9C,aAAa,iDACf,CAAC;IACD,eAAeE,OAAS,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EACtD,aAAa,sEACf,CAAC;GACH,CAAC;GACD,UAAU,CACR;IACE,aAAa;IACb,SAAS;KACP,WAAW;KACX,OAAO;KACP,UAAU;KACV,YAAY;KACZ,MAAM,CAAC,cAAc,WAAW;KAChC,aAAa;KACb,OAAO;KACP,eAAe;IACjB;GACF,CACF;EACF;CACF;CACA,UAAU;EACR;EACA;EACA;EACA;EACA;CACF;CACA,OAAO,CAAC,oCAAoC;AAC9C,CAAC;AAgBD,IAAa,iBAAb,cAAoC,gBAA4D;CAC9F,WAAoB;;;;;;CAOpB,gCAAyB,IAAI,IAAY;CAEzC,OAA0B,EAAE,OAAO,SAA6C;EAC9E,QAAQ,MAAM,MAAd;GACE,KAAK;IAIH,IAAI,MAAM,MAAM,MAAM,QAAQ,eAAe,KAAA,GAAW,OAAO;IAC/D,OAAO;KACL,GAAG;KACH,OAAO;MACL,GAAG,MAAM;OACR,MAAM,QAAQ,YAAY;OACzB,GAAG,MAAM;OACT,iBAAiB,MAAM;OACvB,OAAO;OACP,UAAU;OACV,YAAY;OACZ,MAAM,CAAC;OACP,aAAa;OACb,eAAe;OACf,sBAAsB;MACxB;KACF;KACA,iBAAiB;MACf,GAAG,MAAM;OACR,MAAM,QAAQ,YAAY,mBAAmB,KAAK;KACrD;IACF;GAEF,KAAK,gDAAgD;IACnD,MAAM,OAAO,MAAM,MAAM,MAAM,QAAQ;IAGvC,IAAI,SAAS,KAAA,GAAW,OAAO;IAC/B,OAAO;KACL,GAAG;KACH,iBAAiB;MACf,GAAG,MAAM;OAGR,KAAK,YAAY;OAChB,WAAW,KAAK;OAChB,MAAM,KAAK;OACX,UAAU,KAAK;OACf,aAAa,KAAK;OAClB,eAAe,MAAM;OACrB,aAAa,KAAK,MAAM,MAAM,SAAS,IAAI;MAC7C;KACF;IACF;GACF;GACA,KAAK;IAEH,IAAI,MAAM,MAAM,MAAM,QAAQ,eAAe,KAAA,GAAW,OAAO;IAC/D,OAAO;KACL,GAAG;KACH,OAAO;MACL,GAAG,MAAM;OACR,MAAM,QAAQ,YAAY;OACzB,GAAG,MAAM;OACT,iBAAiB,MAAM;OACvB,eAAe;OACf,sBAAsB;MACxB;KACF;IACF;GAEF,KAAK,kCACH,OAAO;IAAE,GAAG;IAAO,OAAO,CAAC;IAAG,iBAAiB,CAAC;GAAE;GACpD,KAAK,sCAAsC;IACzC,MAAM,eAAe,MAAM,gBAAgB,MAAM,QAAQ;IACzD,MAAM,WAAW,MAAM,MAAM,MAAM,QAAQ;IAW3C,MAAM,gBACJ,MAAM,QAAQ,kBAAkB,KAAA,IAAY,OAAO,MAAM,QAAQ;IACnE,MAAM,eAAe,KAAK,IACxB,iBAAiB,KAAA,IAAY,IAAI,aAAa,eAC9C,UAAU,wBAAwB,CACpC;IACA,IAAI,kBAAkB,QAAQ,gBAAgB,cAAc,OAAO;IACnE,MAAM,GAAG,MAAM,QAAQ,YAAY,UAAU,GAAG,oBAAoB,MAAM;IAG1E,IAAI,aAAa,KAAA,GAAW,OAAO;KAAE,GAAG;KAAO;IAAgB;IAG/D,MAAM,QAAQ,MAAM,QAAQ,SAAS;IACrC,MAAM,uBACJ,kBAAkB,OAAO,SAAS,uBAAuB;IAC3D,MAAM,OACJ,UAAU,OACN;KACE,GAAG;KACH,OAAO,MAAM,QAAQ;KACrB,UAAU,MAAM,QAAQ;KACxB,YAAY,MAAM,QAAQ;KAC1B,MAAM,MAAM,QAAQ;KACpB,aAAa,MAAM,QAAQ;KAC3B,eAAe;KACf;IACF,IAGA;KAAE,GAAG;KAAU,eAAe;KAAO;IAAqB;IAChE,OAAO;KACL,GAAG;KACH,OAAO;MAAE,GAAG,MAAM;OAAQ,MAAM,QAAQ,YAAY;KAAK;KACzD;IACF;GACF;GACA,SACE,OAAO;EACX;CACF;CAEA,aAAgC,MAA2D;EAGzF,IAAI,CAAC,KAAK,SAAS,UAAU;EAC7B,MAAM,MAAM,KAAK,KAAK,IAAI;EAC1B,MAAM,UAA6B,CAAC;EACpC,KAAK,MAAM,WAAW,OAAO,OAAO,KAAK,MAAM,eAAe,GAAG;GAC/D,IAAI,KAAKM,cAAc,IAAI,QAAQ,SAAS,GAAG;GAC/C,IAAI,OAAO,QAAQ,aAAa;IAC9B,QAAQ,KAAK,OAAO;IACpB;GACF;GAGA,IAAI,KAAKA,cAAc,QAAQ,yBAAyB;GAGxD,KAAKA,cAAc,IAAI,QAAQ,SAAS;GAGxC,KAAK,gBAAgB,YAAY;IAC/B,IAAI;KACF,MAAM,aAAa,MAAM,KAAKC,iBAAiB,OAAO;KACtD,MAAM,KAAKC,kBAAkB,KAAK,QAAQ,SAAS,UAAU;IAC/D,UAAU;KACR,KAAKF,cAAc,OAAO,QAAQ,SAAS;IAC7C;GACF,CAAC;EACH;EACA,IAAI,QAAQ,WAAW,GAAG;EAI1B,KAAK,oBAAoB,YAAY;GACnC,KAAK,MAAM,WAAW,SACpB,MAAM,KAAKE,kBAAkB,KAAK,QAAQ,SAAS,EACjD,OACE,2DACe,2BAA2B,KAAU,8BACxD,CAAC;EAEL,CAAC;CACH;;CAGA,MAAMD,iBACJ,SAC8D;EAC9D,IAAI,YAAY;EAChB,KAAK,IAAI,WAAW,GAAG,WAAW,gBAAgB,YAAY;GAC5D,IAAI,WAAW,GACb,MAAM,KAAK,KAAK,MACd,0BAA0B,KAAK,IAAI,WAAW,GAAG,0BAA0B,SAAS,CAAC,EACvF;GAEF,IAAI;IACF,OAAO,EAAE,QAAQ,MAAM,KAAK,KAAK,QAAQ,OAAO,EAAE;GACpD,SAAS,OAAO;IACd,YAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GACnE;EACF;EACA,OAAO,EAAE,OAAO,UAAU,MAAM,GAAG,GAAK,EAAE;CAC5C;;;;;;;;CASA,MAAMC,kBACJ,QACA,SACA,SACe;EACf,MAAM,QAA8C;GAClD,MAAM;GACN,gBAAgB,KAAK,eACnB,oBAAoB,QAAQ,UAAU,GAAG,QAAQ,eACnD;GACA,SAAS;IACP,WAAW,QAAQ;IACnB,eAAe,QAAQ;IACvB,GAAI,YAAY,UACZ;KAAE,GAAG,QAAQ;KAAQ,OAAO;IAAK,IACjC;KACE,OAAO;KACP,UAAU;KACV,YAAY;KACZ,MAAM,CAAC;KACP,aAAa;KACb,OAAO,QAAQ;IACjB;GACN;EACF;EACA,IAAI;GACF,MAAM,OAAO,KAAK;EACpB,SAAS,OAAO;GACd,IAAI,CAAC,sBAAsB,KAAK,GAAG,MAAM;EAC3C;CACF;AACF;AAEA,SAAS,mBAAmB,OAIR;CAClB,OAAO;EACL,WAAW,MAAM,QAAQ;EACzB,MAAM,MAAM,QAAQ;EACpB,UAAU,MAAM,QAAQ;EACxB,aAAa,MAAM,QAAQ;EAC3B,eAAe,MAAM;EACrB,aAAa,KAAK,MAAM,MAAM,SAAS,IAAI;CAC7C;AACF;;;;;;;;AASA,SAAgB,iBACd,OACA,OACa;CACb,MAAM,SAAS,MAAM,KAAK,GAAA,CAAI,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CACvE,MAAM,eAAe,MAAM,QAAQ,CAAC;CACpC,OAAO,OAAO,OAAO,MAAM,KAAK,CAAC,CAC9B,QAAQ,SAAS;EAChB,MAAM,cAAc,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,GAAA,CAAI,QAAQ,mBAAmB,EAAE;EACpF,MAAM,WACJ,GAAG,KAAK,MAAM,GAAG,KAAK,SAAS,GAAG,KAAK,WAAW,GAAG,KAAK,SAAS,GAAG,WAAW,GAAG,KAAK,KAAK,KAAK,GAAG,IAAI,YAAY;EACxH,OACE,MAAM,OAAO,SAAS,SAAS,SAAS,IAAI,CAAC,KAC7C,aAAa,OAAO,QAAQ,KAAK,KAAK,SAAS,GAAG,CAAC;CAEvD,CAAC,CAAC,CACD,MAAM,GAAG,OACP,EAAE,cAAc,EAAE,gBAAA,CAAiB,cAAc,EAAE,cAAc,EAAE,eAAe,CACrF,CAAC,CACA,MAAM,GAAG,MAAM,SAAS,EAAE;AAC/B;;;AC/hBA,IAAa,WAAb,cAA8B,6BAAyC;CACrE,aAAgC;;;CAGhC,WAAuC;CACvC,gBAA0B,MAAyB;EACjD,OAAO,IAAI,eAAe;GACxB,GAAG;GACH,KAAK,KAAK;GACV,QAAQ,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;GAC/D,SAAS,OAAO,UAAU;;;KAExB,OAAO,MAAM,kBAAA,YAAA,EADG,MAAM,KAAK,IAAI,IAAI,IAAI,CACF,GAAG,KAAK;;;;;;GAC/C;EACF,CAAC;CACH;;;CAIA,MAAM,UAAU,OAAmC;EACjD,IAAI,MAAM,SAAA,UAA0B;EACpC,MAAM,WAAW,MAAM,KAAK,SAAS;EACrC,MAAM,SAAS,QAAQ,OAAO;EAC9B,SAAS,YAAY;CACvB;;;;;;CAOA,MAAM,OAAO,OAAmF;;;GAE9F,OAAM,MADiB,KAAK,SAAS,EAAA,CACtB,QAAQ,OAAO;GAC9B,MAAM,EAAE,UAAU,MAAM,KAAK,SAAS;GACtC,MAAM,OAAO,iBAAiB,OAAO,KAAK;GAC1C,MAAM,UAAA,WAAA,EAAU,MAAM,KAAK,IAAI,IAAI,IAAI,CAAA;GACvC,OAAO,MAAM,QAAQ,IACnB,KAAK,IAAI,OAAO,UAAU;IAAE,GAAG;IAAM,KAAK,MAAM,QAAQ,MAAM,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI;GAAE,EAAE,CACvF;;;;;;CACF;;CAGA,MAAM,KAAK,OAAsD;EAC/D,OAAO,KAAK,OAAO,EAAE,OAAO,MAAM,MAAM,CAAC;CAC3C;;CAGA,MAAM,IAAI,WAA8C;EAEtD,OAAM,MADiB,KAAK,SAAS,EAAA,CACtB,QAAQ,OAAO;EAC9B,MAAM,EAAE,UAAU,MAAM,KAAK,SAAS;EACtC,OAAO,MAAM,MAAM,cAAc;CACnC;AACF"}
@@ -0,0 +1,36 @@
1
+ import { t as _usingCtx } from "../../usingCtx-inzbY1Qz.mjs";
2
+ import { mediaStreamPath } from "./ref.mjs";
3
+ import { t as mediaWorkerRef } from "../../app-ref-DYai_om1.mjs";
4
+ //#region src/starter-apps/media/index.ts
5
+ const MediaApp = { create(env) {
6
+ return { async processEvent(event) {
7
+ if (event.path === "/media") try {
8
+ var _usingCtx$1 = _usingCtx();
9
+ const project = _usingCtx$1.u(await env.ITX.get());
10
+ await _usingCtx$1.u(project.workers.get(mediaWorkerRef)).syncEvent(event);
11
+ return;
12
+ } catch (_) {
13
+ _usingCtx$1.e = _;
14
+ } finally {
15
+ _usingCtx$1.d();
16
+ }
17
+ if (event.type === "events.iterate.com/project/worker-updated" && event.path === "/") try {
18
+ var _usingCtx3 = _usingCtx();
19
+ await _usingCtx3.u(await env.ITX.get()).capabilityHosts.get("/").provideCapability({
20
+ type: "itx-call",
21
+ path: ["media"],
22
+ expression: ["workers", ["get", mediaWorkerRef]],
23
+ flattenNestedPaths: true,
24
+ instructions: "Captured media (screenshots/photos) from the mobile app, searchable by content. search({ q, tags?, limit? }) keyword-matches vision descriptions, OCR transcripts, filenames, and tags, newest first, returning signed image URLs. list({ limit? }) is the unfiltered newest; get(stableKey) one item."
25
+ });
26
+ } catch (_) {
27
+ _usingCtx3.e = _;
28
+ } finally {
29
+ _usingCtx3.d();
30
+ }
31
+ } };
32
+ } };
33
+ //#endregion
34
+ export { MediaApp, mediaStreamPath, mediaWorkerRef };
35
+
36
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/starter-apps/media/index.ts"],"sourcesContent":["// Project-worker glue for the MediaApp: fan committed /media events into the\n// app's Durable Object (guestbook shape — media volume doesn't warrant a\n// wake-processor subscription), and on project/worker-updated mount the\n// query surface at `itx.media` as a durable itx-call capability so agents\n// answer \"find my train ticket screenshot\" with itx.media.search(...).\nimport type { DynamicWorkerCapability, ItxBinding, StreamEvent } from \"../../sdk.ts\";\nimport { mediaStreamPath, mediaWorkerRef } from \"./app-ref.ts\";\nimport type { MediaApp as MediaWorker } from \"./worker.ts\";\n\nexport { mediaStreamPath, mediaWorkerRef } from \"./app-ref.ts\";\n\nexport const MediaApp = {\n create(env: { ITX: Pick<ItxBinding, \"get\"> }) {\n return {\n async processEvent(event: StreamEvent): Promise<void> {\n if (event.path === mediaStreamPath) {\n using project = await env.ITX.get();\n using worker = project.workers.get(mediaWorkerRef) as DynamicWorkerCapability<\n Pick<MediaWorker, \"syncEvent\">\n >;\n await worker.syncEvent(event);\n return;\n }\n if (event.type === \"events.iterate.com/project/worker-updated\" && event.path === \"/\") {\n using project = await env.ITX.get();\n // Re-providing on each worker update keeps the mount pointing at\n // the current ref; the host keeps one current mount per path.\n await project.capabilityHosts.get(\"/\").provideCapability({\n type: \"itx-call\",\n path: [\"media\"],\n expression: [\"workers\", [\"get\", mediaWorkerRef]],\n flattenNestedPaths: true,\n instructions:\n \"Captured media (screenshots/photos) from the mobile app, searchable by content. \" +\n \"search({ q, tags?, limit? }) keyword-matches vision descriptions, OCR transcripts, \" +\n \"filenames, and tags, newest first, returning signed image URLs. \" +\n \"list({ limit? }) is the unfiltered newest; get(stableKey) one item.\",\n // No `types`: the provide-time compile gate rejects strings it\n // cannot check, and a failure here would get the worker-updated\n // event skipped (delivery is onFailingEvent: skip). Untyped +\n // instructions beats a mount that never happens.\n });\n }\n },\n };\n },\n};\n"],"mappings":";;;;AAWA,MAAa,WAAW,EACtB,OAAO,KAAuC;CAC5C,OAAO,EACL,MAAM,aAAa,OAAmC;EACpD,IAAI,MAAM,SAAA,UAA0B,IAAA;;GAClC,MAAM,UAAA,YAAA,EAAU,MAAM,IAAI,IAAI,IAAI,CAAA;GAIlC,MAAA,YAAA,EAHe,QAAQ,QAAQ,IAAI,cAAc,CAGtC,CAAC,CAAC,UAAU,KAAK;GAC5B;;;;;;EAEF,IAAI,MAAM,SAAS,+CAA+C,MAAM,SAAS,KAAK,IAAA;;GAIpF,MAAA,WAAA,EAHgB,MAAM,IAAI,IAAI,IAAI,CAGtB,CAAC,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAC,kBAAkB;IACvD,MAAM;IACN,MAAM,CAAC,OAAO;IACd,YAAY,CAAC,WAAW,CAAC,OAAO,cAAc,CAAC;IAC/C,oBAAoB;IACpB,cACE;GAQJ,CAAC;;;;;;CAEL,EACF;AACF,EACF"}
@@ -0,0 +1,20 @@
1
+ //#region src/starter-apps/media/ref.ts
2
+ const mediaStreamPath = "/media";
3
+ const mediaWorkerRef = {
4
+ className: "MediaApp",
5
+ durableWorkerKey: "app-media-stream",
6
+ path: "/",
7
+ source: { createWorker: {
8
+ entryPoint: "node_modules/iterate/dist/starter-apps/media/configured-worker.mjs",
9
+ files: {
10
+ include: ["package.json"],
11
+ repoPath: "/repos/config",
12
+ type: "repo"
13
+ }
14
+ } },
15
+ type: "stateful"
16
+ };
17
+ //#endregion
18
+ export { mediaStreamPath, mediaWorkerRef };
19
+
20
+ //# sourceMappingURL=ref.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref.mjs","names":[],"sources":["../../../src/starter-apps/media/ref.ts"],"sourcesContent":["// The MediaApp worker ref as a dependency-free literal: the mobile e2e (a\n// plain-node tsconfig with no Cloudflare lib types) needs the ref without\n// pulling in sdk.ts. app-ref.ts re-exports this with the satisfies check\n// that keeps it honest against StatefulDynamicWorkerRef.\nexport const mediaStreamPath = \"/media\";\n\nexport const mediaWorkerRef = {\n className: \"MediaApp\",\n durableWorkerKey: \"app-media-stream\",\n path: \"/\",\n source: {\n createWorker: {\n entryPoint: \"node_modules/iterate/dist/starter-apps/media/configured-worker.mjs\",\n files: {\n include: [\"package.json\"],\n repoPath: \"/repos/config\",\n type: \"repo\" as const,\n },\n },\n },\n type: \"stateful\" as const,\n};\n"],"mappings":";AAIA,MAAa,kBAAkB;AAE/B,MAAa,iBAAiB;CAC5B,WAAW;CACX,kBAAkB;CAClB,MAAM;CACN,QAAQ,EACN,cAAc;EACZ,YAAY;EACZ,OAAO;GACL,SAAS,CAAC,cAAc;GACxB,UAAU;GACV,MAAM;EACR;CACF,EACF;CACA,MAAM;AACR"}