@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.
- package/dist/server/server/ingestion/pipedream/gateway.js +96 -0
- package/dist/server/server/ingestion/service.d.ts +21 -1
- package/dist/server/server/ingestion/service.js +61 -0
- package/dist/server/server/ingestion/types.d.ts +25 -0
- package/dist/server/server/session/ingestion/source-session.d.ts +14 -0
- package/dist/server/server/session/ingestion/source-session.js +38 -0
- package/dist/server/server/session.js +4 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js → desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js} +5 -5
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5efd07b4b7ae13d731c59c10f3908268.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-7a589090b52127457319ba733fcca36f.js → desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js} +3 -3
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-4f4e056215f1004ccd00a7112d24be81.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7849a27fe21660d450f204d0cabd4cbe.js → index-0ed5494b46a8402130515eb27850667e.js} +29 -27
- package/dist/server/web-ui/_expo/static/js/web/index-0ed5494b46a8402130515eb27850667e.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ed5494b46a8402130515eb27850667e.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ed5494b46a8402130515eb27850667e.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7849a27fe21660d450f204d0cabd4cbe.js.map.gz → index-0ed5494b46a8402130515eb27850667e.js.map.gz} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js → indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js} +3 -3
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-593c7a311b436569163c4b063d6d7251.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js → native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js} +5 -5
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-9a49946fe848f21fa1b0bf91a4eebf82.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{profiler-d61e032c3f43b3aa19e02fb97c3f7331.js → profiler-26df68e31dea36f8074856bbc6af6da3.js} +11 -11
- package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-26df68e31dea36f8074856bbc6af6da3.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{startRecording-1bb242d6754dee4266ba9a09a252ccea.js → startRecording-b249a152512ee8c62fd7cadef5fdbd69.js} +60 -60
- package/dist/server/web-ui/_expo/static/js/web/startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{startRecording-1bb242d6754dee4266ba9a09a252ccea.js.map.gz → startRecording-b249a152512ee8c62fd7cadef5fdbd69.js.map.gz} +0 -0
- package/dist/server/web-ui/index.html +1 -1
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/package.json +6 -6
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-7849a27fe21660d450f204d0cabd4cbe.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-7849a27fe21660d450f204d0cabd4cbe.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-7849a27fe21660d450f204d0cabd4cbe.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.gz +0 -0
- 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])},
|
|
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])},
|
|
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"))}},
|
|
4
|
-
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-
|
|
5
|
-
//# debugId=
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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}'.`)}},
|
|
2
|
-
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-
|
|
3
|
-
//# debugId=
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|