@hyperdrive.bot/fleet-server 0.3.103 → 0.3.105

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 (72) hide show
  1. package/dist/server/server/ingestion/pipedream/gateway.js +96 -0
  2. package/dist/server/server/ingestion/service.d.ts +21 -1
  3. package/dist/server/server/ingestion/service.js +61 -0
  4. package/dist/server/server/ingestion/types.d.ts +25 -0
  5. package/dist/server/server/session/ingestion/source-session.d.ts +14 -0
  6. package/dist/server/server/session/ingestion/source-session.js +38 -0
  7. package/dist/server/server/session.js +4 -0
  8. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js → desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js} +5 -5
  9. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.br +0 -0
  10. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.gz +0 -0
  11. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.map.br +0 -0
  12. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.map.gz +0 -0
  13. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-7a589090b52127457319ba733fcca36f.js → desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js} +3 -3
  14. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.br +0 -0
  15. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.gz +0 -0
  16. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.map.br +0 -0
  17. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.map.gz +0 -0
  18. package/dist/server/web-ui/_expo/static/js/web/{index-7849a27fe21660d450f204d0cabd4cbe.js → index-0ed5494b46a8402130515eb27850667e.js} +29 -27
  19. package/dist/server/web-ui/_expo/static/js/web/index-0ed5494b46a8402130515eb27850667e.js.br +0 -0
  20. package/dist/server/web-ui/_expo/static/js/web/index-0ed5494b46a8402130515eb27850667e.js.gz +0 -0
  21. package/dist/server/web-ui/_expo/static/js/web/index-0ed5494b46a8402130515eb27850667e.js.map.br +0 -0
  22. package/dist/server/web-ui/_expo/static/js/web/{index-7849a27fe21660d450f204d0cabd4cbe.js.map.gz → index-0ed5494b46a8402130515eb27850667e.js.map.gz} +0 -0
  23. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js → indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js} +3 -3
  24. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.br +0 -0
  25. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.gz +0 -0
  26. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.map.br +0 -0
  27. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.map.gz +0 -0
  28. package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js → native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js} +5 -5
  29. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.br +0 -0
  30. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.gz +0 -0
  31. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.map.br +0 -0
  32. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.map.gz +0 -0
  33. package/dist/server/web-ui/_expo/static/js/web/{profiler-d61e032c3f43b3aa19e02fb97c3f7331.js → profiler-26df68e31dea36f8074856bbc6af6da3.js} +11 -11
  34. package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.br +0 -0
  35. package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.gz +0 -0
  36. package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.map.br +0 -0
  37. package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.map.gz +0 -0
  38. package/dist/server/web-ui/_expo/static/js/web/{startRecording-1bb242d6754dee4266ba9a09a252ccea.js → startRecording-b249a152512ee8c62fd7cadef5fdbd69.js} +60 -60
  39. package/dist/server/web-ui/_expo/static/js/web/startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.br +0 -0
  40. package/dist/server/web-ui/_expo/static/js/web/startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.gz +0 -0
  41. package/dist/server/web-ui/_expo/static/js/web/startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.map.br +0 -0
  42. package/dist/server/web-ui/_expo/static/js/web/{startRecording-1bb242d6754dee4266ba9a09a252ccea.js.map.gz → startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.map.gz} +0 -0
  43. package/dist/server/web-ui/index.html +1 -1
  44. package/dist/server/web-ui/index.html.br +0 -0
  45. package/dist/server/web-ui/index.html.gz +0 -0
  46. package/package.json +6 -6
  47. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.br +0 -0
  48. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.gz +0 -0
  49. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map.br +0 -0
  50. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map.gz +0 -0
  51. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.br +0 -0
  52. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.gz +0 -0
  53. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map.br +0 -0
  54. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map.gz +0 -0
  55. package/dist/server/web-ui/_expo/static/js/web/index-7849a27fe21660d450f204d0cabd4cbe.js.br +0 -0
  56. package/dist/server/web-ui/_expo/static/js/web/index-7849a27fe21660d450f204d0cabd4cbe.js.gz +0 -0
  57. package/dist/server/web-ui/_expo/static/js/web/index-7849a27fe21660d450f204d0cabd4cbe.js.map.br +0 -0
  58. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.br +0 -0
  59. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.gz +0 -0
  60. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.map.br +0 -0
  61. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.map.gz +0 -0
  62. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.br +0 -0
  63. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.gz +0 -0
  64. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.map.br +0 -0
  65. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.map.gz +0 -0
  66. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.br +0 -0
  67. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.gz +0 -0
  68. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.map.br +0 -0
  69. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.map.gz +0 -0
  70. package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.br +0 -0
  71. package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.gz +0 -0
  72. package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.map.br +0 -0
@@ -23,6 +23,8 @@ const APPS_LIMIT = 20;
23
23
  * A history read is per trigger, so this bounds the fan-out of a single page:
24
24
  * one `deployedTriggers.list` call plus at most this many `listEvents` calls.
25
25
  */
26
+ /** Smallest polling cadence the lower Pipedream plans accept. */
27
+ const POLL_INTERVAL_SECONDS = 900;
26
28
  const TRIGGERS_PER_PAGE = 10;
27
29
  /**
28
30
  * A deployed trigger belongs to `appSlug` when its component key is prefixed by
@@ -209,6 +211,100 @@ export function createPipedreamGateway(config) {
209
211
  * Nothing here resolves an MCP target and nothing here takes a bearer. It
210
212
  * is a read, and a read that could arm something is not a preview.
211
213
  */
214
+ /**
215
+ * The app's event-source components, newest-usable first.
216
+ *
217
+ * `triggers.list` returns COMPONENTS (templates like "New Email Received"),
218
+ * not deployments. Nothing here deploys anything; picking which one to
219
+ * subscribe to is the caller's decision.
220
+ */
221
+ async describeTriggerComponent(componentId) {
222
+ const result = await client().triggers.retrieve(componentId);
223
+ return result.data ?? result;
224
+ },
225
+ async listTriggerComponents(appSlug) {
226
+ const page = await client().triggers.list({ app: appSlug });
227
+ const components = [];
228
+ for (const component of page.data ?? []) {
229
+ const key = component.key;
230
+ if (!key || !triggerBelongsToApp(key, appSlug)) {
231
+ continue;
232
+ }
233
+ components.push({
234
+ id: key,
235
+ name: component.name ?? key,
236
+ description: component.description ?? "",
237
+ });
238
+ }
239
+ return components;
240
+ },
241
+ /**
242
+ * SUBSCRIBE: deploy one of those components for this user's account.
243
+ *
244
+ * This is the call the ingestion path was missing entirely. `listItems`
245
+ * reads the event buffer of each DEPLOYED trigger, and nothing ever
246
+ * deployed one - so a backfill returned "Scanned 0 items" for any window,
247
+ * on a healthy account, with a correct filter. Connecting an account
248
+ * authorizes paseo to read; it does not subscribe to anything.
249
+ *
250
+ * `emit_on_deploy` is left at Pipedream's default (true) on purpose: it
251
+ * makes the trigger emit the events it can already see at deploy time, so
252
+ * a filter has something to match without waiting for the next real-world
253
+ * event. Without it a freshly subscribed source stays empty until someone
254
+ * happens to send an email, which is indistinguishable from the bug this
255
+ * fixes.
256
+ */
257
+ async deployTrigger(input) {
258
+ // Read the component's own prop list rather than guessing. A trigger
259
+ // deployed without its REQUIRED props fails with an opaque 500 from
260
+ // Pipedream ("unexpected error"), which says nothing about which prop was
261
+ // missing - gmail-new-email-received needs `timer` and `withTextPayload`
262
+ // beside the app auth, and no error message mentions either.
263
+ const described = (await client().triggers.retrieve(input.componentId));
264
+ const props = described.data?.configurable_props ?? [];
265
+ const configuredProps = {};
266
+ for (const prop of props) {
267
+ if (prop.optional === true) {
268
+ continue;
269
+ }
270
+ if (prop.type === "app") {
271
+ configuredProps[prop.name] = { authProvisionId: input.accountId };
272
+ continue;
273
+ }
274
+ if (prop.type === "$.interface.timer") {
275
+ // A polling source needs a cadence. 15 minutes is Pipedream's own
276
+ // smallest interval on the lower plans, and a source that polls more
277
+ // often than paseo can act on it only burns the user's quota.
278
+ configuredProps[prop.name] = { intervalSeconds: POLL_INTERVAL_SECONDS };
279
+ continue;
280
+ }
281
+ if (prop.type === "boolean") {
282
+ // `withTextPayload` is the one that matters in practice: it puts the
283
+ // message body in the event, which is what a filter clause reads.
284
+ // Defaulting a required boolean to true is only safe because these
285
+ // are payload-shape switches, never rails.
286
+ configuredProps[prop.name] = true;
287
+ continue;
288
+ }
289
+ // A required prop we have no sane default for. Fail LOUDLY naming it,
290
+ // rather than deploying something half-configured and letting the
291
+ // aggregator return its opaque 500.
292
+ throw new IngestionError("PIPEDREAM_OFFLINE", `Trigger ${input.componentId} needs a value for required prop "${prop.name}" (${prop.type})`, 422);
293
+ }
294
+ if (!(input.appSlug in configuredProps)) {
295
+ configuredProps[input.appSlug] = { authProvisionId: input.accountId };
296
+ }
297
+ const result = await client().triggers.deploy({
298
+ id: input.componentId,
299
+ externalUserId: input.externalUserId,
300
+ configuredProps,
301
+ });
302
+ const data = result.data ?? {};
303
+ if (!data.id) {
304
+ throw new IngestionError("PIPEDREAM_OFFLINE", "Pipedream returned no deployed trigger id", 502);
305
+ }
306
+ return { id: data.id, name: data.name ?? input.componentId };
307
+ },
212
308
  async listItems(input) {
213
309
  const page = await client().deployedTriggers.list({
214
310
  externalUserId: input.externalUserId,
@@ -1,7 +1,7 @@
1
1
  import type { Logger } from "pino";
2
2
  import type { SourceCatalogueEntry as WireSourceCatalogueEntry, SourceSummary } from "@hyperdrive.bot/fleet-protocol/ingestion/types";
3
3
  import type { StoredFilter } from "@hyperdrive.bot/fleet-protocol/ingestion/filter-types";
4
- import { type IngestionConfig, type SourceGateway, type SourceKind } from "./types.js";
4
+ import { type IngestionConfig, type SourceGateway, type SourceKind, type SourceTriggerComponent, type SourceTriggerDeployment } from "./types.js";
5
5
  export interface IngestionServiceOptions {
6
6
  paseoHome: string;
7
7
  serverId: string;
@@ -156,6 +156,26 @@ export declare class IngestionService {
156
156
  * written before this change already holds on disk.
157
157
  */
158
158
  private resolvePresentation;
159
+ /**
160
+ * SUBSCRIBE a connected source to its app's event stream.
161
+ *
162
+ * The step the ingestion path never had. `connect` authorizes paseo to READ
163
+ * an account; it subscribes to nothing, and `listItems` reads the event
164
+ * buffer of DEPLOYED triggers - so before this, a backfill on a healthy
165
+ * source with a correct filter returned "Scanned 0 items" for every window,
166
+ * which is indistinguishable from "your filter is wrong".
167
+ *
168
+ * Deliberately explicit rather than automatic on connect: deploying a trigger
169
+ * creates a resource at the aggregator that keeps emitting, and doing that
170
+ * silently as a side effect of "connect" would make a read-only-looking
171
+ * action start consuming the user's Pipedream quota.
172
+ */
173
+ subscribe(sourceId: string, componentId?: string): Promise<{
174
+ deployed: SourceTriggerDeployment | null;
175
+ reason: string | null;
176
+ }>;
177
+ /** The app's available event-source components, for choosing what to subscribe to. */
178
+ triggerComponents(sourceId: string): Promise<SourceTriggerComponent[]>;
159
179
  /**
160
180
  * Forget a source and every filter bound to it.
161
181
  *
@@ -412,6 +412,67 @@ export class IngestionService {
412
412
  }
413
413
  return { displayName: appSlug, imgSrc: "" };
414
414
  }
415
+ /**
416
+ * SUBSCRIBE a connected source to its app's event stream.
417
+ *
418
+ * The step the ingestion path never had. `connect` authorizes paseo to READ
419
+ * an account; it subscribes to nothing, and `listItems` reads the event
420
+ * buffer of DEPLOYED triggers - so before this, a backfill on a healthy
421
+ * source with a correct filter returned "Scanned 0 items" for every window,
422
+ * which is indistinguishable from "your filter is wrong".
423
+ *
424
+ * Deliberately explicit rather than automatic on connect: deploying a trigger
425
+ * creates a resource at the aggregator that keeps emitting, and doing that
426
+ * silently as a side effect of "connect" would make a read-only-looking
427
+ * action start consuming the user's Pipedream quota.
428
+ */
429
+ async subscribe(sourceId, componentId) {
430
+ const source = await this.store.get(sourceId);
431
+ if (source === null) {
432
+ return { deployed: null, reason: "no such source" };
433
+ }
434
+ if (source.externalAccountId === null) {
435
+ // Not an error: this is the honest state of a source whose connect poll
436
+ // never matched an account. Deploying against a null account would fail
437
+ // at the aggregator with a far less legible message.
438
+ return { deployed: null, reason: "source is not linked to an account yet" };
439
+ }
440
+ const gateway = this.resolveGateway(source.kind);
441
+ if (!gateway.deployTrigger || !gateway.listTriggerComponents) {
442
+ return { deployed: null, reason: `${source.kind} cannot deploy triggers` };
443
+ }
444
+ let chosen = componentId;
445
+ if (chosen === undefined) {
446
+ const components = await gateway.listTriggerComponents(source.appSlug);
447
+ if (components.length === 0) {
448
+ return { deployed: null, reason: `no trigger components for ${source.appSlug}` };
449
+ }
450
+ chosen = components[0]?.id;
451
+ }
452
+ if (chosen === undefined) {
453
+ return { deployed: null, reason: "no trigger component selected" };
454
+ }
455
+ const deployed = await gateway.deployTrigger({
456
+ externalUserId: this.externalUserId,
457
+ componentId: chosen,
458
+ accountId: source.externalAccountId,
459
+ appSlug: source.appSlug,
460
+ });
461
+ this.logger.info({ sourceId, componentId: chosen, triggerId: deployed.id }, "Source subscribed: trigger deployed");
462
+ return { deployed, reason: null };
463
+ }
464
+ /** The app's available event-source components, for choosing what to subscribe to. */
465
+ async triggerComponents(sourceId) {
466
+ const source = await this.store.get(sourceId);
467
+ if (source === null) {
468
+ return [];
469
+ }
470
+ const gateway = this.resolveGateway(source.kind);
471
+ if (!gateway.listTriggerComponents) {
472
+ return [];
473
+ }
474
+ return gateway.listTriggerComponents(source.appSlug);
475
+ }
415
476
  /**
416
477
  * Forget a source and every filter bound to it.
417
478
  *
@@ -52,6 +52,17 @@ export interface SourceConnectHandoff {
52
52
  * "pending" means the user is still inside the hosted OAuth popup. Story 1.5 polls
53
53
  * for "active" and must be able to tell that apart from a failed authorization.
54
54
  */
55
+ /** One event-source component an app offers, before anything is deployed. */
56
+ export interface SourceTriggerComponent {
57
+ id: string;
58
+ name: string;
59
+ description: string;
60
+ }
61
+ /** A trigger actually deployed for a user's account - the thing that fills the event buffer. */
62
+ export interface SourceTriggerDeployment {
63
+ id: string;
64
+ name: string;
65
+ }
55
66
  export interface SourceAccount {
56
67
  id: string;
57
68
  status: "active" | "pending" | "inactive";
@@ -152,6 +163,20 @@ export interface SourceGateway {
152
163
  listSources(query: string, cursor?: string): Promise<SourceCataloguePage>;
153
164
  connect(externalUserId: string, appSlug: string): Promise<SourceConnectHandoff>;
154
165
  listAccounts(externalUserId: string, appSlug: string): Promise<SourceAccount[]>;
166
+ /**
167
+ * SUBSCRIBE. Optional because only some aggregators expose deployment: a
168
+ * gateway without it simply cannot subscribe, and the service says so rather
169
+ * than pretending the source is watching something.
170
+ */
171
+ listTriggerComponents?(appSlug: string): Promise<SourceTriggerComponent[]>;
172
+ /** Raw component descriptor, including its configurable props. Diagnostics only. */
173
+ describeTriggerComponent?(componentId: string): Promise<unknown>;
174
+ deployTrigger?(input: {
175
+ externalUserId: string;
176
+ componentId: string;
177
+ accountId: string;
178
+ appSlug: string;
179
+ }): Promise<SourceTriggerDeployment>;
155
180
  /**
156
181
  * One page of a source's HISTORY, oldest boundary supplied by the caller.
157
182
  *
@@ -84,5 +84,19 @@ export declare class SourceSession {
84
84
  handleSourceDisconnectRequest(request: Extract<SessionInboundMessage, {
85
85
  type: "source/disconnect";
86
86
  }>): Promise<void>;
87
+ /**
88
+ * Subscribe a source to its app's event stream.
89
+ *
90
+ * `deployed: null` with `error: null` is a refusal WITH A REASON (no linked
91
+ * account, or an aggregator that cannot deploy). Those are actionable states,
92
+ * not failures, and reporting them as errors would make an ordinary
93
+ * situation look like a broken daemon.
94
+ */
95
+ handleSourceSubscribeRequest(request: Extract<SessionInboundMessage, {
96
+ type: "source/subscribe";
97
+ }>): Promise<void>;
98
+ handleSourceTriggersRequest(request: Extract<SessionInboundMessage, {
99
+ type: "source/triggers";
100
+ }>): Promise<void>;
87
101
  }
88
102
  //# sourceMappingURL=source-session.d.ts.map
@@ -212,5 +212,43 @@ export class SourceSession {
212
212
  this.emitSourceRpcError(request, error);
213
213
  }
214
214
  }
215
+ /**
216
+ * Subscribe a source to its app's event stream.
217
+ *
218
+ * `deployed: null` with `error: null` is a refusal WITH A REASON (no linked
219
+ * account, or an aggregator that cannot deploy). Those are actionable states,
220
+ * not failures, and reporting them as errors would make an ordinary
221
+ * situation look like a broken daemon.
222
+ */
223
+ async handleSourceSubscribeRequest(request) {
224
+ try {
225
+ const result = await this.ingestionService.subscribe(request.sourceId, request.componentId);
226
+ this.host.emit({
227
+ type: "source/subscribe/response",
228
+ payload: {
229
+ requestId: request.requestId,
230
+ sourceId: request.sourceId,
231
+ deployed: result.deployed,
232
+ reason: result.reason,
233
+ error: null,
234
+ },
235
+ });
236
+ }
237
+ catch (error) {
238
+ this.emitSourceRpcError(request, error);
239
+ }
240
+ }
241
+ async handleSourceTriggersRequest(request) {
242
+ try {
243
+ const components = await this.ingestionService.triggerComponents(request.sourceId);
244
+ this.host.emit({
245
+ type: "source/triggers/response",
246
+ payload: { requestId: request.requestId, components, error: null },
247
+ });
248
+ }
249
+ catch (error) {
250
+ this.emitSourceRpcError(request, error);
251
+ }
252
+ }
215
253
  }
216
254
  //# sourceMappingURL=source-session.js.map
@@ -1749,6 +1749,10 @@ export class Session {
1749
1749
  return this.sourceSession.handleSourceCheckRequest(msg);
1750
1750
  case "source/disconnect":
1751
1751
  return this.sourceSession.handleSourceDisconnectRequest(msg);
1752
+ case "source/subscribe":
1753
+ return this.sourceSession.handleSourceSubscribeRequest(msg);
1754
+ case "source/triggers":
1755
+ return this.sourceSession.handleSourceTriggersRequest(msg);
1752
1756
  // Epic 7 filter authoring. Routed to SourceSession rather than
1753
1757
  // ChatIngestionSession because these need no chat context: they are
1754
1758
  // store CRUD, and SourceSession is already the source-scoped surface.
@@ -1,5 +1,5 @@
1
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4922,[4927,4928]);
2
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.writeDesktopAttachmentBase64=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_base64",{attachmentId:n.attachmentId,base64:n.base64,extension:n.extension??null})},e.writeDesktopAttachmentBytes=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_bytes",{attachmentId:n.attachmentId,bytes:n.bytes,extension:n.extension??null})},e.copyDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("copy_attachment_file",{attachmentId:n.attachmentId,sourcePath:n.sourcePath,extension:n.extension??null})},e.deleteDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("delete_attachment_file",{path:n.path})},e.garbageCollectDesktopAttachmentFiles=async function(n){return await(0,t.invokeDesktopCommand)("garbage_collect_attachment_files",{referencedIds:[...n.referencedIds]})};var t=r(d[0])},4927,[3419]);
3
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.readDesktopFileBase64=s,e.createDesktopFileReader=function(){return{readFileBase64:s}},e.createBrowserObjectUrlMinter=function(){return{tryCreate({mimeType:t,base64:n}){if("undefined"==typeof URL||"function"!=typeof URL.createObjectURL)return null;const o=c(n),s=new ArrayBuffer(o.byteLength);new Uint8Array(s).set(o);const u=new Blob([s],{type:t});return URL.createObjectURL(u)},revoke(t){"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&URL.revokeObjectURL(t)}}},e.createDesktopPreviewUrlResolver=function(t){const n=new Set;return{async resolve(o){const s=await t.reader.readFileBase64(o.storageKey),c=t.objectUrls.tryCreate({mimeType:o.mimeType,base64:s});return null===c?`data:${o.mimeType};base64,${s}`:(n.add(c),c)},async release({url:o}){n.has(o)&&(n.delete(o),t.objectUrls.revoke(o))}}};var t=r(d[0]),n=r(d[1]),o=r(d[2]);async function s(o){return await(0,n.invokeDesktopCommand)("read_file_base64",{path:(0,t.fileUriToPath)(o)})}function c(t){return new Uint8Array(o.Buffer.from(t,"base64"))}},4928,[4593,3419,52]);
4
- //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map
5
- //# debugId=8d0f2f2e-6216-48e2-87c5-51b8c02d5b57
1
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4924,[4929,4930]);
2
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.writeDesktopAttachmentBase64=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_base64",{attachmentId:n.attachmentId,base64:n.base64,extension:n.extension??null})},e.writeDesktopAttachmentBytes=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_bytes",{attachmentId:n.attachmentId,bytes:n.bytes,extension:n.extension??null})},e.copyDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("copy_attachment_file",{attachmentId:n.attachmentId,sourcePath:n.sourcePath,extension:n.extension??null})},e.deleteDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("delete_attachment_file",{path:n.path})},e.garbageCollectDesktopAttachmentFiles=async function(n){return await(0,t.invokeDesktopCommand)("garbage_collect_attachment_files",{referencedIds:[...n.referencedIds]})};var t=r(d[0])},4929,[3419]);
3
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.readDesktopFileBase64=s,e.createDesktopFileReader=function(){return{readFileBase64:s}},e.createBrowserObjectUrlMinter=function(){return{tryCreate({mimeType:t,base64:n}){if("undefined"==typeof URL||"function"!=typeof URL.createObjectURL)return null;const o=c(n),s=new ArrayBuffer(o.byteLength);new Uint8Array(s).set(o);const u=new Blob([s],{type:t});return URL.createObjectURL(u)},revoke(t){"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&URL.revokeObjectURL(t)}}},e.createDesktopPreviewUrlResolver=function(t){const n=new Set;return{async resolve(o){const s=await t.reader.readFileBase64(o.storageKey),c=t.objectUrls.tryCreate({mimeType:o.mimeType,base64:s});return null===c?`data:${o.mimeType};base64,${s}`:(n.add(c),c)},async release({url:o}){n.has(o)&&(n.delete(o),t.objectUrls.revoke(o))}}};var t=r(d[0]),n=r(d[1]),o=r(d[2]);async function s(o){return await(0,n.invokeDesktopCommand)("read_file_base64",{path:(0,t.fileUriToPath)(o)})}function c(t){return new Uint8Array(o.Buffer.from(t,"base64"))}},4930,[4593,3419,52]);
4
+ //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.map
5
+ //# debugId=5851625d-0957-494e-bb9f-0d6b59b1bf98
@@ -1,3 +1,3 @@
1
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4921,[4593]);
2
- //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map
3
- //# debugId=950ba5c5-7992-4432-ad49-c7f52c12d7e4
1
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4923,[4593]);
2
+ //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.map
3
+ //# debugId=98b48941-be2d-4aa6-9b53-a8c0b408e92e