@hyperdrive.bot/fleet-server 0.3.99 → 0.3.101
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/composio/gateway.js +6 -1
- package/dist/server/server/ingestion/pipedream/gateway.js +7 -0
- package/dist/server/server/ingestion/service.d.ts +31 -0
- package/dist/server/server/ingestion/service.js +81 -4
- package/dist/server/server/ingestion/types.d.ts +9 -0
- package/dist/server/server/session/ingestion/source-session.d.ts +10 -0
- package/dist/server/server/session/ingestion/source-session.js +25 -0
- package/dist/server/server/session.js +11 -3
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js → desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js} +5 -5
- 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-6888615a6b700f975c1f78501ad8577c.js → desktop-attachment-store-7a589090b52127457319ba733fcca36f.js} +3 -3
- 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-dc1e81e7cbad84d30a01c48dcc9a5a3e.js → index-cd94e627d4feefdc781faccc3da11ade.js} +30 -29
- package/dist/server/web-ui/_expo/static/js/web/index-cd94e627d4feefdc781faccc3da11ade.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-cd94e627d4feefdc781faccc3da11ade.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-cd94e627d4feefdc781faccc3da11ade.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.map.gz → index-cd94e627d4feefdc781faccc3da11ade.js.map.gz} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js → indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js} +3 -3
- 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-fdb4d787a259ce350f76280ca0e2bfa2.js → native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js} +5 -5
- 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-9502a8e721925a6353ec45f7613f537e.js → profiler-d61e032c3f43b3aa19e02fb97c3f7331.js} +11 -11
- 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-4ed5094aa059a0fc724f5ae70dd2f693.js → startRecording-1bb242d6754dee4266ba9a09a252ccea.js} +60 -60
- 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
- package/dist/server/web-ui/_expo/static/js/web/{startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.map.gz → startRecording-1bb242d6754dee4266ba9a09a252ccea.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-67f19cbfce758da6aa23c38c2dbd6a33.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.map.br +0 -0
|
@@ -375,7 +375,12 @@ export function createComposioGateway(config) {
|
|
|
375
375
|
if (!item.id) {
|
|
376
376
|
continue;
|
|
377
377
|
}
|
|
378
|
-
|
|
378
|
+
// Composio's connected-account payload carries no email or display
|
|
379
|
+
// name for the authorized account - `user_id` is the caller-supplied
|
|
380
|
+
// external id, which is the daemon's own tenant string here and so
|
|
381
|
+
// identifies nothing about the user. Null rather than a value that
|
|
382
|
+
// would look like an identity and not be one.
|
|
383
|
+
accounts.push({ id: item.id, status: normalizeStatus(item.status), label: null });
|
|
379
384
|
}
|
|
380
385
|
return accounts;
|
|
381
386
|
},
|
|
@@ -181,6 +181,13 @@ export function createPipedreamGateway(config) {
|
|
|
181
181
|
accounts.push({
|
|
182
182
|
id: account.id,
|
|
183
183
|
status: account.healthy === false ? "inactive" : "active",
|
|
184
|
+
// Pipedream's `name` is the account's custom name, which for an OAuth
|
|
185
|
+
// app is normally the address the user authorized with. It is
|
|
186
|
+
// optional in the SDK type, so it is coalesced rather than assumed -
|
|
187
|
+
// an absent label renders as "Not linked to an account", never as the
|
|
188
|
+
// opaque `apn_...` id, which would be an identifier pretending to be
|
|
189
|
+
// an identity.
|
|
190
|
+
label: account.name ?? null,
|
|
184
191
|
});
|
|
185
192
|
}
|
|
186
193
|
return accounts;
|
|
@@ -137,6 +137,37 @@ export declare class IngestionService {
|
|
|
137
137
|
* uniformly cheerful `true`.
|
|
138
138
|
*/
|
|
139
139
|
deleteFilter(filterId: string): Promise<boolean>;
|
|
140
|
+
/**
|
|
141
|
+
* The catalogue's own name and icon for an app slug.
|
|
142
|
+
*
|
|
143
|
+
* Best-effort by design: a catalogue call that fails or returns no match must
|
|
144
|
+
* not fail a connect whose OAuth handoff already succeeded, so it degrades to
|
|
145
|
+
* exactly what this method replaced (the raw slug, no icon) rather than
|
|
146
|
+
* throwing. `imgSrc` stays `""` in that case, matching what every source
|
|
147
|
+
* written before this change already holds on disk.
|
|
148
|
+
*/
|
|
149
|
+
private resolvePresentation;
|
|
150
|
+
/**
|
|
151
|
+
* Forget a source and every filter bound to it.
|
|
152
|
+
*
|
|
153
|
+
* LOCAL ONLY. The aggregator keeps the grant, so this is "paseo stops
|
|
154
|
+
* watching", not "the provider forgot you" - and the confirm copy must say
|
|
155
|
+
* that, because promising a revoke paseo does not perform is the same class
|
|
156
|
+
* of lie as the connect sheet's old "it updates on its own".
|
|
157
|
+
*
|
|
158
|
+
* Filters CASCADE rather than being orphaned. A filter whose `sourceId` no
|
|
159
|
+
* longer resolves is not inert: it resolves to `SOURCE_MISSING` and shows up
|
|
160
|
+
* as a broken row forever, so leaving them would trade one piece of
|
|
161
|
+
* unremovable state for another.
|
|
162
|
+
*
|
|
163
|
+
* The in-flight connect poll is cancelled FIRST. It writes health on a timer,
|
|
164
|
+
* so deleting the record underneath a live poll would let it recreate state
|
|
165
|
+
* for a source the user just removed.
|
|
166
|
+
*/
|
|
167
|
+
disconnect(sourceId: string): Promise<{
|
|
168
|
+
removed: boolean;
|
|
169
|
+
removedFilterIds: string[];
|
|
170
|
+
}>;
|
|
140
171
|
/**
|
|
141
172
|
* Field by field on purpose. A `...stored` spread would mean a field added to
|
|
142
173
|
* StoredSource later reaches the wire the day it is added, with no diff on
|
|
@@ -104,13 +104,25 @@ export class IngestionService {
|
|
|
104
104
|
const gateway = this.resolveGateway(kind);
|
|
105
105
|
const handoff = await gateway.connect(this.externalUserId, appSlug);
|
|
106
106
|
const timestamp = this.now().toISOString();
|
|
107
|
+
// The catalogue already knows this app as "Google Calendar" with a real
|
|
108
|
+
// icon, and the client rendered exactly that one tap earlier. Writing the
|
|
109
|
+
// raw slug threw both away at the moment of persisting, so every row read
|
|
110
|
+
// "google_calendar" with no icon forever after.
|
|
111
|
+
//
|
|
112
|
+
// Resolved daemon-side rather than accepted from the client: a client that
|
|
113
|
+
// could supply displayName and imgSrc could write the strings the row
|
|
114
|
+
// renders, and store.test.ts already guards against exactly that shape.
|
|
115
|
+
// Best-effort - a catalogue hiccup must not fail a connect that otherwise
|
|
116
|
+
// succeeded, so it falls back to the previous behaviour.
|
|
117
|
+
const presentation = await this.resolvePresentation(gateway, appSlug);
|
|
107
118
|
const source = await this.store.create({
|
|
108
119
|
kind,
|
|
109
120
|
appSlug,
|
|
110
|
-
displayName:
|
|
111
|
-
imgSrc:
|
|
121
|
+
displayName: presentation.displayName,
|
|
122
|
+
imgSrc: presentation.imgSrc,
|
|
112
123
|
externalUserId: this.externalUserId,
|
|
113
124
|
externalAccountId: null,
|
|
125
|
+
accountLabel: null,
|
|
114
126
|
status: "connecting",
|
|
115
127
|
createdAt: timestamp,
|
|
116
128
|
updatedAt: timestamp,
|
|
@@ -205,7 +217,7 @@ export class IngestionService {
|
|
|
205
217
|
}
|
|
206
218
|
const active = accounts.find((account) => account.status === "active");
|
|
207
219
|
if (active) {
|
|
208
|
-
await this.persistHealth(source.id, { status: "active", lastError: null }, active.id);
|
|
220
|
+
await this.persistHealth(source.id, { status: "active", lastError: null }, active.id, active.label);
|
|
209
221
|
return;
|
|
210
222
|
}
|
|
211
223
|
await this.sleep(CONNECT_POLL_INTERVAL_MS, state);
|
|
@@ -254,7 +266,7 @@ export class IngestionService {
|
|
|
254
266
|
* Re-reads the record first so a source deleted while a poll or a sweep was
|
|
255
267
|
* in flight is not resurrected by a stale write.
|
|
256
268
|
*/
|
|
257
|
-
async persistHealth(sourceId, health, externalAccountId) {
|
|
269
|
+
async persistHealth(sourceId, health, externalAccountId, accountLabel) {
|
|
258
270
|
const current = await this.store.get(sourceId);
|
|
259
271
|
if (!current) {
|
|
260
272
|
return null;
|
|
@@ -267,6 +279,7 @@ export class IngestionService {
|
|
|
267
279
|
lastCheckedAt: timestamp,
|
|
268
280
|
updatedAt: timestamp,
|
|
269
281
|
...(externalAccountId !== undefined ? { externalAccountId } : {}),
|
|
282
|
+
...(accountLabel !== undefined ? { accountLabel } : {}),
|
|
270
283
|
};
|
|
271
284
|
await this.store.put(next);
|
|
272
285
|
return next;
|
|
@@ -340,6 +353,69 @@ export class IngestionService {
|
|
|
340
353
|
await this.filterStore.delete(filterId);
|
|
341
354
|
return true;
|
|
342
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* The catalogue's own name and icon for an app slug.
|
|
358
|
+
*
|
|
359
|
+
* Best-effort by design: a catalogue call that fails or returns no match must
|
|
360
|
+
* not fail a connect whose OAuth handoff already succeeded, so it degrades to
|
|
361
|
+
* exactly what this method replaced (the raw slug, no icon) rather than
|
|
362
|
+
* throwing. `imgSrc` stays `""` in that case, matching what every source
|
|
363
|
+
* written before this change already holds on disk.
|
|
364
|
+
*/
|
|
365
|
+
async resolvePresentation(gateway, appSlug) {
|
|
366
|
+
try {
|
|
367
|
+
const page = await gateway.listSources(appSlug);
|
|
368
|
+
const match = page.items.find((entry) => entry.slug === appSlug);
|
|
369
|
+
if (match) {
|
|
370
|
+
return { displayName: match.name, imgSrc: match.imgSrc };
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
// Logged, never swallowed silently: if this degrades in production the
|
|
375
|
+
// symptom is a row that says "google_calendar", and a bare catch would
|
|
376
|
+
// make that indistinguishable from an aggregator that simply has no
|
|
377
|
+
// catalogue entry.
|
|
378
|
+
this.logger.warn({ err: error, appSlug }, "Catalogue lookup failed; falling back to slug");
|
|
379
|
+
}
|
|
380
|
+
return { displayName: appSlug, imgSrc: "" };
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Forget a source and every filter bound to it.
|
|
384
|
+
*
|
|
385
|
+
* LOCAL ONLY. The aggregator keeps the grant, so this is "paseo stops
|
|
386
|
+
* watching", not "the provider forgot you" - and the confirm copy must say
|
|
387
|
+
* that, because promising a revoke paseo does not perform is the same class
|
|
388
|
+
* of lie as the connect sheet's old "it updates on its own".
|
|
389
|
+
*
|
|
390
|
+
* Filters CASCADE rather than being orphaned. A filter whose `sourceId` no
|
|
391
|
+
* longer resolves is not inert: it resolves to `SOURCE_MISSING` and shows up
|
|
392
|
+
* as a broken row forever, so leaving them would trade one piece of
|
|
393
|
+
* unremovable state for another.
|
|
394
|
+
*
|
|
395
|
+
* The in-flight connect poll is cancelled FIRST. It writes health on a timer,
|
|
396
|
+
* so deleting the record underneath a live poll would let it recreate state
|
|
397
|
+
* for a source the user just removed.
|
|
398
|
+
*/
|
|
399
|
+
async disconnect(sourceId) {
|
|
400
|
+
const existing = await this.store.get(sourceId);
|
|
401
|
+
if (existing === null) {
|
|
402
|
+
return { removed: false, removedFilterIds: [] };
|
|
403
|
+
}
|
|
404
|
+
// Cancel BEFORE deleting. The poll writes health on a 2s timer, so
|
|
405
|
+
// removing the record underneath a live poll lets it persist state for a
|
|
406
|
+
// source the user just removed. `cancel()` also wakes the sleep, so the
|
|
407
|
+
// loop exits at its next check rather than after the full interval; the
|
|
408
|
+
// poll's own `finally` removes the map entry.
|
|
409
|
+
this.connectPolls.get(sourceId)?.cancel();
|
|
410
|
+
const filters = await this.filterStore.list();
|
|
411
|
+
const bound = filters.filter((filter) => filter.sourceId === sourceId);
|
|
412
|
+
for (const filter of bound) {
|
|
413
|
+
await this.filterStore.delete(filter.id);
|
|
414
|
+
}
|
|
415
|
+
await this.store.delete(sourceId);
|
|
416
|
+
this.logger.info({ sourceId, removedFilters: bound.length }, "Source disconnected and its filters removed");
|
|
417
|
+
return { removed: true, removedFilterIds: bound.map((filter) => filter.id) };
|
|
418
|
+
}
|
|
343
419
|
/**
|
|
344
420
|
* Field by field on purpose. A `...stored` spread would mean a field added to
|
|
345
421
|
* StoredSource later reaches the wire the day it is added, with no diff on
|
|
@@ -353,6 +429,7 @@ export class IngestionService {
|
|
|
353
429
|
displayName: source.displayName,
|
|
354
430
|
imgSrc: source.imgSrc,
|
|
355
431
|
externalAccountId: source.externalAccountId,
|
|
432
|
+
accountLabel: source.accountLabel,
|
|
356
433
|
status: source.status,
|
|
357
434
|
createdAt: source.createdAt,
|
|
358
435
|
updatedAt: source.updatedAt,
|
|
@@ -55,6 +55,15 @@ export interface SourceConnectHandoff {
|
|
|
55
55
|
export interface SourceAccount {
|
|
56
56
|
id: string;
|
|
57
57
|
status: "active" | "pending" | "inactive";
|
|
58
|
+
/**
|
|
59
|
+
* The human name of the account, when the aggregator gives one - typically
|
|
60
|
+
* the email for an OAuth app. Null when it does not.
|
|
61
|
+
*
|
|
62
|
+
* Both gateways already receive this on a call they already make and drop it
|
|
63
|
+
* on the floor, which is why a connected row could only ever say "gmail" and
|
|
64
|
+
* never WHICH gmail.
|
|
65
|
+
*/
|
|
66
|
+
label: string | null;
|
|
58
67
|
}
|
|
59
68
|
export interface PipedreamConfig {
|
|
60
69
|
clientId?: string | undefined;
|
|
@@ -74,5 +74,15 @@ export declare class SourceSession {
|
|
|
74
74
|
handleIngestionFilterDeleteRequest(request: Extract<SessionInboundMessage, {
|
|
75
75
|
type: "ingestion/filter/delete";
|
|
76
76
|
}>): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Forget a source and the filters bound to it.
|
|
79
|
+
*
|
|
80
|
+
* `removed: false` with `error: null` says the id resolved to nothing, which
|
|
81
|
+
* is an answer: disconnecting twice is idempotent, and reporting the second
|
|
82
|
+
* call as a failure would make a double-tap look like a broken daemon.
|
|
83
|
+
*/
|
|
84
|
+
handleSourceDisconnectRequest(request: Extract<SessionInboundMessage, {
|
|
85
|
+
type: "source/disconnect";
|
|
86
|
+
}>): Promise<void>;
|
|
77
87
|
}
|
|
78
88
|
//# sourceMappingURL=source-session.d.ts.map
|
|
@@ -187,5 +187,30 @@ export class SourceSession {
|
|
|
187
187
|
this.emitSourceRpcError(request, error);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Forget a source and the filters bound to it.
|
|
192
|
+
*
|
|
193
|
+
* `removed: false` with `error: null` says the id resolved to nothing, which
|
|
194
|
+
* is an answer: disconnecting twice is idempotent, and reporting the second
|
|
195
|
+
* call as a failure would make a double-tap look like a broken daemon.
|
|
196
|
+
*/
|
|
197
|
+
async handleSourceDisconnectRequest(request) {
|
|
198
|
+
try {
|
|
199
|
+
const result = await this.ingestionService.disconnect(request.sourceId);
|
|
200
|
+
this.host.emit({
|
|
201
|
+
type: "source/disconnect/response",
|
|
202
|
+
payload: {
|
|
203
|
+
requestId: request.requestId,
|
|
204
|
+
sourceId: request.sourceId,
|
|
205
|
+
removed: result.removed,
|
|
206
|
+
removedFilterIds: result.removedFilterIds,
|
|
207
|
+
error: null,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
this.emitSourceRpcError(request, error);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
190
215
|
}
|
|
191
216
|
//# sourceMappingURL=source-session.js.map
|
|
@@ -1747,6 +1747,8 @@ export class Session {
|
|
|
1747
1747
|
return this.sourceSession.handleSourceListRequest(msg);
|
|
1748
1748
|
case "source/check":
|
|
1749
1749
|
return this.sourceSession.handleSourceCheckRequest(msg);
|
|
1750
|
+
case "source/disconnect":
|
|
1751
|
+
return this.sourceSession.handleSourceDisconnectRequest(msg);
|
|
1750
1752
|
// Epic 7 filter authoring. Routed to SourceSession rather than
|
|
1751
1753
|
// ChatIngestionSession because these need no chat context: they are
|
|
1752
1754
|
// store CRUD, and SourceSession is already the source-scoped surface.
|
|
@@ -3420,9 +3422,15 @@ export class Session {
|
|
|
3420
3422
|
if (!normalized.cwd) {
|
|
3421
3423
|
throw new Error("Import requires cwd from the selected provider session");
|
|
3422
3424
|
}
|
|
3423
|
-
//
|
|
3424
|
-
//
|
|
3425
|
-
|
|
3425
|
+
// Look before you mint. This used to call createWorkspaceForDirectory
|
|
3426
|
+
// unconditionally, so importing a session whose cwd ALREADY had a workspace
|
|
3427
|
+
// produced a second one and the imported agent surfaced there instead of in
|
|
3428
|
+
// the workspace on screen. Same class as the palette (0.3.38),
|
|
3429
|
+
// resolveOrCreateWorkspaceIdForCreateAgent (MR !44) and
|
|
3430
|
+
// ensureWorkspaceForCreate (MR !80); import was the last call site still
|
|
3431
|
+
// minting. findOrCreateWorkspaceForDirectory keeps the never-seen-cwd case
|
|
3432
|
+
// minting, which is the only case where a new workspace is correct.
|
|
3433
|
+
const workspace = await this.workspaceProvisioning.findOrCreateWorkspaceForDirectory(normalized.cwd);
|
|
3426
3434
|
const { snapshot, timelineSize } = await importProviderSession({
|
|
3427
3435
|
request: normalized,
|
|
3428
3436
|
workspaceId: workspace.workspaceId,
|
|
@@ -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])},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
|
|
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}'.`)}},4921,[4593]);
|
|
2
|
+
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map
|
|
3
|
+
//# debugId=950ba5c5-7992-4432-ad49-c7f52c12d7e4
|
|
Binary file
|
|
Binary file
|
|
Binary file
|