@tangle-network/blueprint-ui 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -81,6 +81,80 @@ export type ChainChanged = {
81
81
  chainId: number;
82
82
  };
83
83
 
84
+ // ─── Service context (parent → iframe) ──────────────────────────────────────
85
+ //
86
+ // Iframe blueprints embedded by Tangle Cloud need to know which service +
87
+ // blueprint they're rendering for, plus which operators are quoted. The
88
+ // parent broadcasts this on mount and on every change (mode picker swap,
89
+ // new service activation, operator delta). The iframe just reads — it
90
+ // doesn't query the chain itself.
91
+ //
92
+ // The thin-iframe SDK exposes this as `useTangleService()`. Iframes that
93
+ // use the full wagmi connector path can still listen to `serviceContext`
94
+ // for routing convenience.
95
+
96
+ export type ServiceContextOperator = {
97
+ readonly address: Address;
98
+ readonly rpcAddress: string | undefined;
99
+ readonly status: 'active' | 'inactive' | 'unknown';
100
+ };
101
+
102
+ export type ServiceContextJob = {
103
+ readonly index: number;
104
+ readonly name: string;
105
+ readonly inputSchema?: unknown;
106
+ };
107
+
108
+ export type ServiceContextBroadcast = {
109
+ kind: 'tangle.app.serviceContext';
110
+ readonly blueprintId: string;
111
+ readonly serviceId: string | null;
112
+ readonly operators: readonly ServiceContextOperator[];
113
+ readonly jobs: readonly ServiceContextJob[];
114
+ readonly mode: string | null;
115
+ };
116
+
117
+ // ─── Job invocation (iframe ↔ parent) ────────────────────────────────────────
118
+ //
119
+ // Instead of the iframe wiring up its own EIP-712 quote / sign / submit
120
+ // flow, it sends a single CallJob request upstream. The parent does the
121
+ // whole dance (fetch RFQ quote, build typed data, request user signature,
122
+ // submit on-chain) and streams results back. The iframe never touches
123
+ // chain logic.
124
+
125
+ export type JobInputs = Readonly<Record<string, unknown>>;
126
+
127
+ export type CallJobRequest = {
128
+ kind: 'tangle.app.callJob';
129
+ correlationId: string;
130
+ /** Job index within the blueprint, e.g. 0 for the primary entry-point. */
131
+ jobIndex: number;
132
+ /** Free-form inputs validated by the parent against the on-chain ABI. */
133
+ inputs: JobInputs;
134
+ /**
135
+ * Whether the publisher wants intermediate progress (streaming chunks)
136
+ * or just the terminal result. Streaming jobs (LLM generation, video
137
+ * encode) opt in; one-shots (embeddings, classifications) don't.
138
+ */
139
+ stream?: boolean;
140
+ };
141
+
142
+ export type JobResultStatus = 'pending' | 'streaming' | 'success' | 'error';
143
+
144
+ export type JobResultEvent = {
145
+ kind: 'tangle.app.jobResult';
146
+ correlationId: string;
147
+ status: JobResultStatus;
148
+ /** Present on `streaming` and `success`. Shape is publisher-defined. */
149
+ data?: unknown;
150
+ /** Present on `streaming` only — incremental chunk for live UI. */
151
+ chunk?: unknown;
152
+ /** Present on `error`. Human-readable. */
153
+ error?: string;
154
+ /** Optional progress metadata (e.g. `{ percent: 0.42, eta_ms: 8000 }`). */
155
+ progress?: { readonly percent?: number; readonly eta_ms?: number };
156
+ };
157
+
84
158
  export type ParentMessage =
85
159
  | HandshakeAck
86
160
  | ReadAccountResult
@@ -88,7 +162,17 @@ export type ParentMessage =
88
162
  | SignMessageResult
89
163
  | SignTransactionResult
90
164
  | AccountChanged
91
- | ChainChanged;
165
+ | ChainChanged
166
+ | ServiceContextBroadcast
167
+ | JobResultEvent;
168
+
169
+ export type IframeRequest =
170
+ | HandshakeRequest
171
+ | ReadAccountRequest
172
+ | SwitchChainRequest
173
+ | SignMessageRequest
174
+ | SignTransactionRequest
175
+ | CallJobRequest;
92
176
 
93
177
  // The zero address used by the parent when no wallet is connected. The parent
94
178
  // always responds to readAccount with an address; this sentinel means "no
@@ -15,6 +15,10 @@ import {
15
15
  NO_WALLET_ADDRESS,
16
16
  TANGLE_IFRAME_PROTOCOL_VERSION,
17
17
  type ParentMessage,
18
+ type ReadAccountResult,
19
+ type SignMessageResult,
20
+ type SignTransactionResult,
21
+ type SwitchChainResult,
18
22
  } from './parentBridgeProtocol';
19
23
 
20
24
  type EventName = 'accountsChanged' | 'chainChanged' | 'connect' | 'disconnect' | 'message';
@@ -316,7 +320,19 @@ export class ParentBridgeProvider {
316
320
  });
317
321
  }
318
322
 
319
- private resolvePending(message: Extract<ParentMessage, { correlationId: string }>): void {
323
+ /**
324
+ * Resolves wallet-shape responses (`{ ok, data | error }`). Job results
325
+ * use a different envelope (`{ status, data?, chunk?, error? }`) and are
326
+ * routed through a separate listener registered by `useCallJob` / the SDK
327
+ * — the provider doesn't double-handle them.
328
+ */
329
+ private resolvePending(
330
+ message:
331
+ | ReadAccountResult
332
+ | SwitchChainResult
333
+ | SignMessageResult
334
+ | SignTransactionResult,
335
+ ): void {
320
336
  const entry = this.pending.get(message.correlationId);
321
337
  if (!entry) return;
322
338
  this.pending.delete(message.correlationId);