@tuongaz/seeflow 0.1.109 → 0.1.111

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 (75) hide show
  1. package/dist/web/assets/{architectureDiagram-3BPJPVTR-CvIAMnMC.js → architectureDiagram-3BPJPVTR-C-2fCGRP.js} +1 -1
  2. package/dist/web/assets/{blockDiagram-GPEHLZMM-C55itdvA.js → blockDiagram-GPEHLZMM-Br3qZBhv.js} +1 -1
  3. package/dist/web/assets/{c4Diagram-AAUBKEIU-BUJz6OcY.js → c4Diagram-AAUBKEIU-C4uX4ZH4.js} +1 -1
  4. package/dist/web/assets/channel-qhQeh_4Q.js +1 -0
  5. package/dist/web/assets/{chart-Ck4M6xxI.js → chart-9kjHxc0V.js} +1 -1
  6. package/dist/web/assets/{chunk-2J33WTMH-CYHRe8M7.js → chunk-2J33WTMH-2Fn5NN7i.js} +1 -1
  7. package/dist/web/assets/{chunk-4BX2VUAB-0G6VpCw_.js → chunk-4BX2VUAB-Df_7ccfg.js} +1 -1
  8. package/dist/web/assets/{chunk-55IACEB6-YeyA7Efg.js → chunk-55IACEB6-DdU4dw35.js} +1 -1
  9. package/dist/web/assets/{chunk-727SXJPM-irL9oAdE.js → chunk-727SXJPM-1at9fA5f.js} +1 -1
  10. package/dist/web/assets/{chunk-AQP2D5EJ-DB0ZGTqs.js → chunk-AQP2D5EJ-CPe9M1hv.js} +1 -1
  11. package/dist/web/assets/{chunk-FMBD7UC4-Z48rYWhG.js → chunk-FMBD7UC4-DCUEmPvJ.js} +1 -1
  12. package/dist/web/assets/{chunk-ND2GUHAM-BgYSDKdi.js → chunk-ND2GUHAM-tE2Ii-jJ.js} +1 -1
  13. package/dist/web/assets/{chunk-QZHKN3VN-CzcjFmi-.js → chunk-QZHKN3VN-Db5o8Kzv.js} +1 -1
  14. package/dist/web/assets/classDiagram-4FO5ZUOK-BCHg-KrI.js +1 -0
  15. package/dist/web/assets/classDiagram-v2-Q7XG4LA2-BCHg-KrI.js +1 -0
  16. package/dist/web/assets/{code-block-BwE8Ip6V.js → code-block-CTINSk3z.js} +1 -1
  17. package/dist/web/assets/{cose-bilkent-S5V4N54A-DtufDmle.js → cose-bilkent-S5V4N54A-D7tNx5-t.js} +1 -1
  18. package/dist/web/assets/{dagre-BM42HDAG-DwYVzLme.js → dagre-BM42HDAG-Cdb53Asb.js} +1 -1
  19. package/dist/web/assets/{diagram-2AECGRRQ-DDw_qvjI.js → diagram-2AECGRRQ-HS6pnGrL.js} +1 -1
  20. package/dist/web/assets/{diagram-5GNKFQAL-BYG2VdwF.js → diagram-5GNKFQAL-c9k4swAt.js} +1 -1
  21. package/dist/web/assets/{diagram-KO2AKTUF-Drp2zu_G.js → diagram-KO2AKTUF-CB3k4xVS.js} +1 -1
  22. package/dist/web/assets/{diagram-LMA3HP47-CXmAihfn.js → diagram-LMA3HP47-XKAfR3DB.js} +1 -1
  23. package/dist/web/assets/{diagram-OG6HWLK6-i6-iKnAU.js → diagram-OG6HWLK6-18dGr0GC.js} +1 -1
  24. package/dist/web/assets/{erDiagram-TEJ5UH35-Bo96y9hO.js → erDiagram-TEJ5UH35-9DnFE7wo.js} +1 -1
  25. package/dist/web/assets/{flowDiagram-I6XJVG4X-D9fneMTu.js → flowDiagram-I6XJVG4X-CglLanUO.js} +1 -1
  26. package/dist/web/assets/{ganttDiagram-6RSMTGT7-Cbefa8NE.js → ganttDiagram-6RSMTGT7-_zKCXbXg.js} +1 -1
  27. package/dist/web/assets/{gitGraphDiagram-PVQCEYII-BHYd5nUs.js → gitGraphDiagram-PVQCEYII-D6axSpL3.js} +1 -1
  28. package/dist/web/assets/{iconify-BuhA_8An.js → iconify-CF3Xx8Oq.js} +1 -1
  29. package/dist/web/assets/index-BTL8cVgF.js +8629 -0
  30. package/dist/web/assets/{index.es-pImjWTGX.js → index.es-DyQqI4EJ.js} +1 -1
  31. package/dist/web/assets/{infoDiagram-5YYISTIA-Bw7MIIwj.js → infoDiagram-5YYISTIA-BfnEVJMR.js} +1 -1
  32. package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-CySt1i7t.js → ishikawaDiagram-YF4QCWOH-C-CbbOkc.js} +1 -1
  33. package/dist/web/assets/{journeyDiagram-JHISSGLW-q4YV61wv.js → journeyDiagram-JHISSGLW-CxcYZYhO.js} +1 -1
  34. package/dist/web/assets/{jspdf.es.min-B95ptK5L.js → jspdf.es.min-BoDPBXoT.js} +3 -3
  35. package/dist/web/assets/{kanban-definition-UN3LZRKU-C1oN-zoM.js → kanban-definition-UN3LZRKU-Dw9dGj5D.js} +1 -1
  36. package/dist/web/assets/{linear-DPSv7VcC.js → linear-DJLoiaYn.js} +1 -1
  37. package/dist/web/assets/{markdown-btlM2PIA.js → markdown-BXIhHJY7.js} +1 -1
  38. package/dist/web/assets/{mermaid.core-Cmch2GTm.js → mermaid.core-CTeg8SMj.js} +4 -4
  39. package/dist/web/assets/{mindmap-definition-RKZ34NQL--XOTWr6e.js → mindmap-definition-RKZ34NQL-DG4pYeYK.js} +1 -1
  40. package/dist/web/assets/{pieDiagram-4H26LBE5-DxZgtzul.js → pieDiagram-4H26LBE5-qPHgJ6_d.js} +1 -1
  41. package/dist/web/assets/{quadrantDiagram-W4KKPZXB-bbV2bAO3.js → quadrantDiagram-W4KKPZXB-C-yiyax0.js} +1 -1
  42. package/dist/web/assets/{requirementDiagram-4Y6WPE33-CiJM8hio.js → requirementDiagram-4Y6WPE33-vBgnScGl.js} +1 -1
  43. package/dist/web/assets/{sankeyDiagram-5OEKKPKP-DABBnuaB.js → sankeyDiagram-5OEKKPKP-H-Yoexss.js} +1 -1
  44. package/dist/web/assets/{sequenceDiagram-3UESZ5HK-BTQJk7bM.js → sequenceDiagram-3UESZ5HK-B0PUqbDC.js} +1 -1
  45. package/dist/web/assets/{stateDiagram-AJRCARHV-yL0tAd3x.js → stateDiagram-AJRCARHV-LHZJU6NT.js} +1 -1
  46. package/dist/web/assets/stateDiagram-v2-BHNVJYJU-Jjcvv867.js +1 -0
  47. package/dist/web/assets/{time-hCZUKGxT.js → time-CytNQj8l.js} +1 -1
  48. package/dist/web/assets/{timeline-definition-PNZ67QCA-CG6k16Wj.js → timeline-definition-PNZ67QCA-CNYtzzkX.js} +1 -1
  49. package/dist/web/assets/{vennDiagram-CIIHVFJN-BVH530xf.js → vennDiagram-CIIHVFJN-CR3j3MfQ.js} +1 -1
  50. package/dist/web/assets/{wardley-L42UT6IY-BYVkFMrL.js → wardley-L42UT6IY-DsRtYkk3.js} +1 -1
  51. package/dist/web/assets/{wardleyDiagram-YWT4CUSO-BGMuHejP.js → wardleyDiagram-YWT4CUSO-Bkiae0No.js} +1 -1
  52. package/dist/web/assets/{xychartDiagram-2RQKCTM6-D6MSlnJD.js → xychartDiagram-2RQKCTM6-DFoBCrdz.js} +1 -1
  53. package/dist/web/index.html +1 -1
  54. package/package.json +1 -1
  55. package/src/api.ts +0 -291
  56. package/src/server.ts +0 -20
  57. package/dist/web/assets/channel-DtcQ9fhj.js +0 -1
  58. package/dist/web/assets/classDiagram-4FO5ZUOK-BjYXB41E.js +0 -1
  59. package/dist/web/assets/classDiagram-v2-Q7XG4LA2-BjYXB41E.js +0 -1
  60. package/dist/web/assets/index-08hmlCqO.js +0 -8644
  61. package/dist/web/assets/stateDiagram-v2-BHNVJYJU-BzWj6i1l.js +0 -1
  62. package/src/share/sse-frame.ts +0 -85
  63. package/src/share/sse-outbound-queue.ts +0 -173
  64. package/src/share/sse-rate-limit.ts +0 -205
  65. package/src/share/sse-tap.ts +0 -183
  66. package/src/share-audit.ts +0 -267
  67. package/src/share-envelope.ts +0 -155
  68. package/src/share-file-request.ts +0 -399
  69. package/src/share-file-resolver.ts +0 -68
  70. package/src/share-file-upload.ts +0 -595
  71. package/src/share-files-manifest.ts +0 -232
  72. package/src/share-ratelimit.ts +0 -69
  73. package/src/share-rpc-schema.ts +0 -249
  74. package/src/share-transport.ts +0 -205
  75. package/src/share.ts +0 -1663
package/src/api.ts CHANGED
@@ -47,8 +47,6 @@ import {
47
47
  } from './schema-catalog.ts';
48
48
  import type { ComponentAction, SeeflowManifest } from './schema.ts';
49
49
  import { FlowIdPattern, FlowSchema, ResolvedFlowSchema } from './schema.ts';
50
- import type { RpcOp } from './share-rpc-schema.ts';
51
- import type { AttributionEvent, RpcDispatchOutcome, ShareController, ShareState } from './share.ts';
52
50
  import { type Spawner, defaultSpawner } from './shellout.ts';
53
51
  import { ID_TYPES, MAX_ID_COUNT, generateIds, isIdType } from './short-id.ts';
54
52
  import type { StatusRunner } from './status-runner.ts';
@@ -238,14 +236,8 @@ export interface ApiOptions {
238
236
  /** Override the icon installer fetcher. Production uses fetchWithProgress;
239
237
  * integration tests inject a fixture-returning closure. */
240
238
  iconFetcher?: IconFetcher;
241
- /** Live Share controller. The studio bootstrap instantiates one per process
242
- * (see server.ts); tests inject a fake to drive the /api/share/* routes
243
- * without touching the relay or a real WebSocket. */
244
- share?: ShareController;
245
239
  }
246
240
 
247
- const KickBodySchema = z.object({ peerId: z.string().min(1) });
248
-
249
241
  /**
250
242
  * Thin call-through wrapper around the proxy.ts module exports. Lets tests
251
243
  * inject a recording fake to observe runPlay invocations — the play-run map
@@ -269,25 +261,6 @@ export function createApi(options: ApiOptions): Hono {
269
261
  const ops = createOperations({ registry, watcher });
270
262
  const api = new Hono();
271
263
 
272
- // Fan-out helper for host-originated edits (US-039). Every node/connector
273
- // mutation endpoint below funnels through this after a successful op so the
274
- // live-share peers receive a `node-patched` envelope and can apply the diff
275
- // to their local snapshot. No-op when the share controller is absent or the
276
- // session is not active. Wrapped in try/catch defensively — broadcast
277
- // failures must NEVER fail the local HTTP request. The share controller
278
- // normalizes flat `patchNode` bodies into a peer-applicable wire shape via
279
- // its own `canonicalizePatchNode` helper before broadcasting.
280
- const share = options.share;
281
- const broadcastEdit = (op: RpcOp, result: { kind: string; data?: unknown }): void => {
282
- if (!share) return;
283
- if (result.kind !== 'ok') return;
284
- try {
285
- share.broadcastHostEdit(op, result as RpcDispatchOutcome);
286
- } catch (err) {
287
- console.warn('[api] share broadcastHostEdit failed:', err);
288
- }
289
- };
290
-
291
264
  const iconJobs = options.iconJobs ?? createJobRegistry();
292
265
  api.route(
293
266
  '/icons',
@@ -1690,7 +1663,6 @@ export function createApi(options: ApiOptions): Hono {
1690
1663
  const result = await ops.moveNode(id, nodeId, parsed.data);
1691
1664
  switch (result.kind) {
1692
1665
  case 'ok':
1693
- broadcastEdit({ op: 'moveNode', flowId: id, nodeId, position: parsed.data }, result);
1694
1666
  return c.json({ ok: true, position: result.data.position });
1695
1667
  case 'flowNotFound':
1696
1668
  return c.json({ error: 'unknown demo' }, 404);
@@ -1734,7 +1706,6 @@ export function createApi(options: ApiOptions): Hono {
1734
1706
  const result = await ops.reorderNode(id, nodeId, parsed.data);
1735
1707
  switch (result.kind) {
1736
1708
  case 'ok':
1737
- broadcastEdit({ op: 'reorderNode', flowId: id, nodeId, reorder: parsed.data }, result);
1738
1709
  return c.json({ ok: true });
1739
1710
  case 'flowNotFound':
1740
1711
  return c.json({ error: 'unknown demo' }, 404);
@@ -1778,7 +1749,6 @@ export function createApi(options: ApiOptions): Hono {
1778
1749
  const result = await ops.patchNode(id, nodeId, parsed.data);
1779
1750
  switch (result.kind) {
1780
1751
  case 'ok':
1781
- broadcastEdit({ op: 'patchNode', flowId: id, nodeId, patch: parsed.data }, result);
1782
1752
  return c.json({ ok: true });
1783
1753
  case 'flowNotFound':
1784
1754
  return c.json({ error: 'unknown demo' }, 404);
@@ -1816,10 +1786,6 @@ export function createApi(options: ApiOptions): Hono {
1816
1786
  const result = await ops.addNode(id, body as Record<string, unknown>);
1817
1787
  switch (result.kind) {
1818
1788
  case 'ok':
1819
- broadcastEdit(
1820
- { op: 'addNode', flowId: id, node: result.data.node as Record<string, unknown> },
1821
- result,
1822
- );
1823
1789
  return c.json({ ok: true, id: result.data.id, node: result.data.node });
1824
1790
  case 'flowNotFound':
1825
1791
  return c.json({ error: 'unknown demo' }, 404);
@@ -1860,15 +1826,6 @@ export function createApi(options: ApiOptions): Hono {
1860
1826
  const result = await ops.addBulk(id, parsed.data);
1861
1827
  switch (result.kind) {
1862
1828
  case 'ok':
1863
- broadcastEdit(
1864
- {
1865
- op: 'addBulk',
1866
- flowId: id,
1867
- ...(parsed.data.nodes ? { nodes: parsed.data.nodes } : {}),
1868
- ...(parsed.data.connectors ? { connectors: parsed.data.connectors } : {}),
1869
- },
1870
- result,
1871
- );
1872
1829
  return c.json({
1873
1830
  ok: true,
1874
1831
  nodes: result.data.nodes,
@@ -1910,7 +1867,6 @@ export function createApi(options: ApiOptions): Hono {
1910
1867
  const result = await ops.deleteNode(id, nodeId);
1911
1868
  switch (result.kind) {
1912
1869
  case 'ok':
1913
- broadcastEdit({ op: 'deleteNode', flowId: id, nodeId }, result);
1914
1870
  return c.json({ ok: true });
1915
1871
  case 'flowNotFound':
1916
1872
  return c.json({ error: 'unknown demo' }, 404);
@@ -1954,10 +1910,6 @@ export function createApi(options: ApiOptions): Hono {
1954
1910
  const result = await ops.patchConnector(id, connId, parsed.data);
1955
1911
  switch (result.kind) {
1956
1912
  case 'ok':
1957
- broadcastEdit(
1958
- { op: 'patchConnector', flowId: id, connectorId: connId, patch: parsed.data },
1959
- result,
1960
- );
1961
1913
  return c.json({ ok: true });
1962
1914
  case 'flowNotFound':
1963
1915
  return c.json({ error: 'unknown demo' }, 404);
@@ -1996,14 +1948,6 @@ export function createApi(options: ApiOptions): Hono {
1996
1948
  const result = await ops.addConnector(id, body as Record<string, unknown>);
1997
1949
  switch (result.kind) {
1998
1950
  case 'ok':
1999
- broadcastEdit(
2000
- {
2001
- op: 'addConnector',
2002
- flowId: id,
2003
- connector: { ...(body as Record<string, unknown>), id: result.data.id },
2004
- },
2005
- result,
2006
- );
2007
1951
  return c.json({ ok: true, id: result.data.id });
2008
1952
  case 'flowNotFound':
2009
1953
  return c.json({ error: 'unknown demo' }, 404);
@@ -2029,7 +1973,6 @@ export function createApi(options: ApiOptions): Hono {
2029
1973
  const result = await ops.deleteConnector(id, connId);
2030
1974
  switch (result.kind) {
2031
1975
  case 'ok':
2032
- broadcastEdit({ op: 'deleteConnector', flowId: id, connectorId: connId }, result);
2033
1976
  return c.json({ ok: true });
2034
1977
  case 'flowNotFound':
2035
1978
  return c.json({ error: 'unknown demo' }, 404);
@@ -2147,240 +2090,6 @@ export function createApi(options: ApiOptions): Hono {
2147
2090
  });
2148
2091
  });
2149
2092
 
2150
- // Live Share local API. Five routes that delegate to the injected
2151
- // ShareController. The controller is optional — when absent (e.g. tests
2152
- // that don't exercise share) every endpoint returns 503 so misconfigured
2153
- // deployments fail visibly instead of silently 404ing. `share` is defined
2154
- // at the top of createApi together with `broadcastEdit`.
2155
-
2156
- // Map a controller rejection to an HTTP status + error body. share-not-active
2157
- // and share-peer-not-found are the two domain-specific reasons; everything
2158
- // else surfaces as 500 with the raw message so misconfigurations (bad relay
2159
- // URL, network failures, etc.) are debuggable from the response.
2160
- const shareErrorStatus = (err: unknown): { status: 400 | 404 | 409 | 500; error: string } => {
2161
- const msg = err instanceof Error ? err.message : String(err);
2162
- if (msg === 'share-not-active') return { status: 409, error: msg };
2163
- if (msg === 'share-peer-not-found') return { status: 404, error: msg };
2164
- if (msg === 'share-already-active') return { status: 409, error: msg };
2165
- return { status: 500, error: msg };
2166
- };
2167
-
2168
- api.post('/share/start', async (c) => {
2169
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2170
- try {
2171
- const result = await share.start();
2172
- return c.json(result);
2173
- } catch (err) {
2174
- const mapped = shareErrorStatus(err);
2175
- return c.json({ error: mapped.error }, mapped.status);
2176
- }
2177
- });
2178
-
2179
- api.post('/share/stop', async (c) => {
2180
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2181
- try {
2182
- await share.stop();
2183
- return c.body(null, 204);
2184
- } catch (err) {
2185
- const mapped = shareErrorStatus(err);
2186
- return c.json({ error: mapped.error }, mapped.status);
2187
- }
2188
- });
2189
-
2190
- api.post('/share/kick', async (c) => {
2191
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2192
- let body: unknown;
2193
- try {
2194
- body = await c.req.json();
2195
- } catch {
2196
- return c.json({ error: 'Body must be valid JSON' }, 400);
2197
- }
2198
- const parsed = KickBodySchema.safeParse(body);
2199
- if (!parsed.success) {
2200
- return c.json({ error: 'Invalid kick body', issues: parsed.error.issues }, 400);
2201
- }
2202
- try {
2203
- await share.kick(parsed.data.peerId);
2204
- return c.body(null, 204);
2205
- } catch (err) {
2206
- const mapped = shareErrorStatus(err);
2207
- return c.json({ error: mapped.error }, mapped.status);
2208
- }
2209
- });
2210
-
2211
- api.post('/share/rotate', async (c) => {
2212
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2213
- try {
2214
- const result = await share.rotateUrl();
2215
- return c.json(result);
2216
- } catch (err) {
2217
- const mapped = shareErrorStatus(err);
2218
- return c.json({ error: mapped.error }, mapped.status);
2219
- }
2220
- });
2221
-
2222
- // POST /api/share/kill-all — host kill-switch (US-081). Revokes every
2223
- // session this studio has tracked in `active.json`, not just the active
2224
- // one. Local-only by the cors.ts middleware. Returns the counts surfaced
2225
- // by the controller so the UI toast can show "Ended N live sessions".
2226
- api.post('/share/kill-all', async (c) => {
2227
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2228
- try {
2229
- const result = await share.killAll();
2230
- return c.json(result);
2231
- } catch (err) {
2232
- const mapped = shareErrorStatus(err);
2233
- return c.json({ error: mapped.error }, mapped.status);
2234
- }
2235
- });
2236
-
2237
- // GET /api/share/audit — page through the per-session AuditEntry JSONL log.
2238
- // Local-only by virtue of the cors.ts middleware. Requires an active session
2239
- // — when the controller is idle there is no logger to read from, so respond
2240
- // 400 rather than silently returning an empty page (consumers can use the
2241
- // status code to distinguish "no entries yet" from "no session").
2242
- api.get('/share/audit', async (c) => {
2243
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2244
- if (share.state().status !== 'active') {
2245
- return c.json({ error: 'share-not-active' }, 400);
2246
- }
2247
- const limitRaw = c.req.query('limit');
2248
- const cursorRaw = c.req.query('cursor');
2249
- const limit = limitRaw !== undefined ? Number.parseInt(limitRaw, 10) : undefined;
2250
- const cursor = cursorRaw !== undefined ? Number.parseInt(cursorRaw, 10) : undefined;
2251
- const opts: { limit?: number; cursor?: number } = {};
2252
- if (typeof limit === 'number' && Number.isFinite(limit)) opts.limit = limit;
2253
- if (typeof cursor === 'number' && Number.isFinite(cursor)) opts.cursor = cursor;
2254
- try {
2255
- const page = await share.audit.list(opts);
2256
- return c.json(page);
2257
- } catch (err) {
2258
- const message = err instanceof Error ? err.message : String(err);
2259
- return c.json({ error: message }, 500);
2260
- }
2261
- });
2262
-
2263
- // GET /api/share/state — SSE stream of ShareState transitions. Initial frame
2264
- // is the current state; subsequent frames are pushed on each controller
2265
- // subscribe callback. Mirrors the /api/events shape (queue + wake + heartbeat)
2266
- // so the UI can use the same EventSource handling.
2267
- api.get('/share/state', (c) => {
2268
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2269
- const controller = share;
2270
-
2271
- return streamSSE(c, async (stream) => {
2272
- let active = true;
2273
- const queue: Array<{ event: string; data: string }> = [];
2274
- let resume: (() => void) | null = null;
2275
-
2276
- const wake = () => {
2277
- if (resume) {
2278
- const r = resume;
2279
- resume = null;
2280
- r();
2281
- }
2282
- };
2283
-
2284
- const enqueue = (s: ShareState) => {
2285
- queue.push({ event: 'state', data: JSON.stringify(s) });
2286
- wake();
2287
- };
2288
-
2289
- // subscribe() invokes fn synchronously with the current state, so the
2290
- // initial frame lands in the queue automatically — no explicit prologue.
2291
- const unsubscribe = controller.subscribe(enqueue);
2292
-
2293
- stream.onAbort(() => {
2294
- active = false;
2295
- unsubscribe();
2296
- wake();
2297
- });
2298
-
2299
- try {
2300
- while (active) {
2301
- while (queue.length > 0) {
2302
- const next = queue.shift();
2303
- if (!next) break;
2304
- await stream.writeSSE(next);
2305
- }
2306
- if (!active) break;
2307
- let heartbeat: ReturnType<typeof setTimeout> | null = null;
2308
- const reason = await new Promise<'event' | 'heartbeat'>((r) => {
2309
- resume = () => r('event');
2310
- heartbeat = setTimeout(() => r('heartbeat'), SSE_HEARTBEAT_MS);
2311
- });
2312
- if (heartbeat) clearTimeout(heartbeat);
2313
- resume = null;
2314
- if (reason === 'heartbeat' && active) {
2315
- await stream.write(': ping\n\n');
2316
- }
2317
- }
2318
- } finally {
2319
- unsubscribe();
2320
- }
2321
- });
2322
- });
2323
-
2324
- // GET /api/share/attributions — SSE stream of `node-patched` attribution
2325
- // events for the host studio's apps/web UI (US-053). Fires once per accepted
2326
- // op (peer-originated AND host-originated), carrying `{flowId, op, diff,
2327
- // version, attributedTo, ts}`. No initial replay — the toast stack is for
2328
- // live activity only.
2329
- api.get('/share/attributions', (c) => {
2330
- if (!share) return c.json({ error: 'share controller not configured' }, 503);
2331
- const controller = share;
2332
-
2333
- return streamSSE(c, async (stream) => {
2334
- let active = true;
2335
- const queue: Array<{ event: string; data: string }> = [];
2336
- let resume: (() => void) | null = null;
2337
-
2338
- const wake = () => {
2339
- if (resume) {
2340
- const r = resume;
2341
- resume = null;
2342
- r();
2343
- }
2344
- };
2345
-
2346
- const enqueue = (event: AttributionEvent) => {
2347
- queue.push({ event: 'attribution', data: JSON.stringify(event) });
2348
- wake();
2349
- };
2350
-
2351
- const unsubscribe = controller.subscribeAttributions(enqueue);
2352
-
2353
- stream.onAbort(() => {
2354
- active = false;
2355
- unsubscribe();
2356
- wake();
2357
- });
2358
-
2359
- try {
2360
- while (active) {
2361
- while (queue.length > 0) {
2362
- const next = queue.shift();
2363
- if (!next) break;
2364
- await stream.writeSSE(next);
2365
- }
2366
- if (!active) break;
2367
- let heartbeat: ReturnType<typeof setTimeout> | null = null;
2368
- const reason = await new Promise<'event' | 'heartbeat'>((r) => {
2369
- resume = () => r('event');
2370
- heartbeat = setTimeout(() => r('heartbeat'), SSE_HEARTBEAT_MS);
2371
- });
2372
- if (heartbeat) clearTimeout(heartbeat);
2373
- resume = null;
2374
- if (reason === 'heartbeat' && active) {
2375
- await stream.write(': ping\n\n');
2376
- }
2377
- }
2378
- } finally {
2379
- unsubscribe();
2380
- }
2381
- });
2382
- });
2383
-
2384
2093
  // Global registry channel — broadcasts `registry:reload` when an external
2385
2094
  // process (e.g. the CLI) writes to ~/.seeflow/registry.json. Subscribers
2386
2095
  // re-fetch the flow list. The channel id is the internal sentinel from
package/src/server.ts CHANGED
@@ -14,7 +14,6 @@ import { seeflowHome } from './paths.ts';
14
14
  import { type ProcessSpawner, defaultProcessSpawner } from './process-spawner.ts';
15
15
  import { type RegistryWatcher, createRegistryWatcher } from './registry-watcher.ts';
16
16
  import { type Registry, createRegistry, manifestOnlyEntryFilter } from './registry.ts';
17
- import { type ShareController, createShareController, resolveHostDisplayName } from './share.ts';
18
17
  import type { Spawner } from './shellout.ts';
19
18
  import { type StatusRunner, createStatusRunner } from './status-runner.ts';
20
19
  import { type FlowWatcher, createWatcher } from './watcher.ts';
@@ -80,16 +79,8 @@ export interface CreateAppOptions {
80
79
  /** Override the icon installer's fetcher. Production uses fetchWithProgress
81
80
  * (real network); integration tests inject a fixture-returning closure. */
82
81
  iconFetcher?: IconFetcher;
83
- /** Inject a Live Share controller. Defaults to one pointed at
84
- * https://seeflow.dev (SEEFLOW_SHARE_RELAY_URL) with share URLs rooted at
85
- * https://seeflow.dev/share (SEEFLOW_SHARE_URL_BASE). Tests inject a fake
86
- * to exercise the /api/share/* routes without a real relay. */
87
- share?: ShareController;
88
82
  }
89
83
 
90
- const DEFAULT_SHARE_RELAY_URL = 'https://seeflow.dev';
91
- const DEFAULT_SHARE_URL_BASE = 'https://seeflow.dev/share';
92
-
93
84
  const DEFAULT_VITE_DEV_URL = 'http://localhost:5173';
94
85
  const DEFAULT_STATIC_ROOT = resolvePath(import.meta.dir, '../dist/web');
95
86
 
@@ -117,16 +108,6 @@ export function createApp(options: CreateAppOptions = {}): Hono {
117
108
  options.statusRunner ??
118
109
  createStatusRunner({ registry, events, spawner: defaultProcessSpawner });
119
110
  const iconJobs = options.iconJobs ?? createJobRegistry();
120
- const share =
121
- options.share ??
122
- createShareController({
123
- relayHttpUrl: process.env.SEEFLOW_SHARE_RELAY_URL ?? DEFAULT_SHARE_RELAY_URL,
124
- shareUrlBase: process.env.SEEFLOW_SHARE_URL_BASE ?? DEFAULT_SHARE_URL_BASE,
125
- eventBus: events,
126
- flowIdsForBroadcast: () => registry.list().map((e) => e.id),
127
- hostDisplayName: resolveHostDisplayName(),
128
- operationsDeps: { registry, ...(watcher ? { watcher } : {}) },
129
- });
130
111
 
131
112
  if (watcher && (options.watchAllOnBoot ?? true)) {
132
113
  watcher.watchAll();
@@ -190,7 +171,6 @@ export function createApp(options: CreateAppOptions = {}): Hono {
190
171
  iconJobs,
191
172
  iconCacheRoot: options.iconCacheRoot,
192
173
  iconFetcher: options.iconFetcher,
193
- share,
194
174
  }),
195
175
  );
196
176
 
@@ -1 +0,0 @@
1
- import{U as a,C as n}from"./mermaid.core-Cmch2GTm.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as e,C as t}from"./chunk-727SXJPM-irL9oAdE.js";import{a as i}from"./mermaid.core-Cmch2GTm.js";import"./index-08hmlCqO.js";import"./chunk-FMBD7UC4-Z48rYWhG.js";import"./chunk-ND2GUHAM-BgYSDKdi.js";import"./chunk-55IACEB6-YeyA7Efg.js";import"./chunk-2J33WTMH-CYHRe8M7.js";import"./purify.es-CLGrRn1w.js";import"./step-CWvwoXpJ.js";var b={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{b as diagram};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as e,C as t}from"./chunk-727SXJPM-irL9oAdE.js";import{a as i}from"./mermaid.core-Cmch2GTm.js";import"./index-08hmlCqO.js";import"./chunk-FMBD7UC4-Z48rYWhG.js";import"./chunk-ND2GUHAM-BgYSDKdi.js";import"./chunk-55IACEB6-YeyA7Efg.js";import"./chunk-2J33WTMH-CYHRe8M7.js";import"./purify.es-CLGrRn1w.js";import"./step-CWvwoXpJ.js";var b={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{b as diagram};