@andco/sdk 0.0.2 → 0.0.4
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/LICENSE +1 -1
- package/README.md +96 -54
- package/dist/auth.d.ts +8 -3
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +32 -23
- package/dist/browser/controller.d.ts +55 -1
- package/dist/browser/controller.d.ts.map +1 -1
- package/dist/browser/controller.js +166 -9
- package/dist/browser/frame.d.ts +4 -3
- package/dist/browser/frame.d.ts.map +1 -1
- package/dist/browser/frame.js +12 -20
- package/dist/browser/index.d.ts +18 -6
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +64 -29
- package/dist/browser/popup.d.ts +6 -1
- package/dist/browser/popup.d.ts.map +1 -1
- package/dist/browser/popup.js +37 -8
- package/dist/cli/index.d.ts +4 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +10 -3
- package/dist/cli/server.d.ts +5 -0
- package/dist/cli/server.d.ts.map +1 -1
- package/dist/cli/server.js +5 -0
- package/dist/client.d.ts +66 -19
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +125 -74
- package/dist/config.d.ts +2 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/credentials.d.ts +58 -4
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +0 -0
- package/dist/errors.d.ts +23 -21
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -20
- package/dist/globals.d.ts +25 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +15 -0
- package/dist/grants-api.d.ts +34 -0
- package/dist/grants-api.d.ts.map +1 -0
- package/dist/grants-api.js +48 -0
- package/dist/grants.d.ts +16 -0
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +13 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/inflight.d.ts +31 -0
- package/dist/inflight.d.ts.map +1 -0
- package/dist/inflight.js +26 -0
- package/dist/intents.d.ts +386 -40
- package/dist/intents.d.ts.map +1 -1
- package/dist/intents.js +712 -53
- package/dist/oauth.d.ts +55 -6
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +86 -57
- package/dist/presenter.d.ts +59 -11
- package/dist/presenter.d.ts.map +1 -1
- package/dist/presenter.js +40 -1
- package/dist/resource.d.ts +109 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +151 -0
- package/dist/rest.d.ts +23 -4
- package/dist/rest.d.ts.map +1 -1
- package/dist/rest.js +46 -5
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server-metadata.generated.d.ts.map +1 -1
- package/dist/server-metadata.generated.js +8 -4
- package/dist/service.d.ts +109 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +241 -0
- package/dist/session-store.d.ts +12 -4
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +64 -14
- package/dist/storage.d.ts +16 -23
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +27 -25
- package/dist/tokens.d.ts +46 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +148 -0
- package/package.json +13 -3
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
import { ANDCO_ERROR_CODES as ANDCO_PROTOCOL_ERROR_CODES, ANDCO_RELEASE, callbackStateCreate } from "@andco/protocol";
|
|
2
2
|
import { ANDCO_ERROR_CODES, AndcoError } from "../errors.js";
|
|
3
3
|
import { AndcoButtonBridge } from "./frame.js";
|
|
4
|
+
/**
|
|
5
|
+
* Sandbox restrictions the hosted iframe grants: scripts to run, same-origin to reach its own
|
|
6
|
+
* storage, and a popup that may escape the sandbox because it is a separate top-level browsing
|
|
7
|
+
* context the sandbox does not otherwise constrain.
|
|
8
|
+
*
|
|
9
|
+
* This is a containment boundary, not a per-binding style choice, so it is declared exactly once
|
|
10
|
+
* here rather than copied into every framework binding.
|
|
11
|
+
*/
|
|
12
|
+
const IFRAME_SANDBOX = "allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox";
|
|
13
|
+
/** Keeps the Project's own URL out of the request the hosted iframe makes. */
|
|
14
|
+
const IFRAME_REFERRER_POLICY = "no-referrer";
|
|
15
|
+
/** The part of the default iframe style every binding shares regardless of size. */
|
|
16
|
+
const IFRAME_BASE_STYLE = { border: "0", display: "block" };
|
|
17
|
+
/**
|
|
18
|
+
* The hosted control's default box.
|
|
19
|
+
*
|
|
20
|
+
* A bare iframe is 300x150 with a border, and the hosted control fills whatever box it is given, so
|
|
21
|
+
* without a default an application sees a bordered grey slab. React, Vue, and Svelte apply this
|
|
22
|
+
* directly to the `<iframe>` they render.
|
|
23
|
+
*/
|
|
24
|
+
const DEFAULT_SIZE = { height: "3rem", width: "18rem" };
|
|
25
|
+
const IFRAME_DEFAULT_STYLE = { ...IFRAME_BASE_STYLE, ...DEFAULT_SIZE };
|
|
26
|
+
/** Renders a style record — property names only, no camelCase — as inline CSS text. */
|
|
27
|
+
function frameStyleText(style) {
|
|
28
|
+
return Object.entries(style)
|
|
29
|
+
.map(([property, value]) => `${property}:${value}`)
|
|
30
|
+
.join(";");
|
|
31
|
+
}
|
|
4
32
|
/**
|
|
5
33
|
* Coordinates one hosted Andco iframe without owning how a framework renders it.
|
|
6
34
|
*
|
|
@@ -11,6 +39,15 @@ import { AndcoButtonBridge } from "./frame.js";
|
|
|
11
39
|
* Render `snapshot.iframeURL` in your platform's own iframe element, then hand that element to
|
|
12
40
|
* `connect()` once it mounts.
|
|
13
41
|
*
|
|
42
|
+
* The frame's fixed attributes and default sizing are published as static data —
|
|
43
|
+
* {@link AndcoButtonController.IFRAME_SANDBOX}, {@link AndcoButtonController.IFRAME_REFERRER_POLICY},
|
|
44
|
+
* {@link AndcoButtonController.IFRAME_DEFAULT_STYLE}, and {@link AndcoButtonController.frameProps} for
|
|
45
|
+
* the snapshot-derived `src`/`hidden` pair — so every binding applies the same contract to its own
|
|
46
|
+
* element instead of redeclaring it. `sdk-script`'s custom element is the one exception on sizing: it
|
|
47
|
+
* sizes itself through a stylesheet layer (using {@link AndcoButtonController.DEFAULT_SIZE}, so the
|
|
48
|
+
* visible default stays the same) and stretches its internal iframe to fill it, so that an author's
|
|
49
|
+
* own CSS on `andco-button` wins without touching the iframe's inline style.
|
|
50
|
+
*
|
|
14
51
|
* @example
|
|
15
52
|
* ```ts
|
|
16
53
|
* const controller = new AndcoButtonController({ client: andco, onComplete: reload });
|
|
@@ -19,6 +56,31 @@ import { AndcoButtonBridge } from "./frame.js";
|
|
|
19
56
|
* ```
|
|
20
57
|
*/
|
|
21
58
|
export class AndcoButtonController {
|
|
59
|
+
/** @see {@link IFRAME_SANDBOX} */
|
|
60
|
+
static IFRAME_SANDBOX = IFRAME_SANDBOX;
|
|
61
|
+
/** @see {@link IFRAME_REFERRER_POLICY} */
|
|
62
|
+
static IFRAME_REFERRER_POLICY = IFRAME_REFERRER_POLICY;
|
|
63
|
+
/** @see {@link IFRAME_BASE_STYLE} */
|
|
64
|
+
static IFRAME_BASE_STYLE = IFRAME_BASE_STYLE;
|
|
65
|
+
/** @see {@link DEFAULT_SIZE} */
|
|
66
|
+
static DEFAULT_SIZE = DEFAULT_SIZE;
|
|
67
|
+
/** @see {@link IFRAME_DEFAULT_STYLE} */
|
|
68
|
+
static IFRAME_DEFAULT_STYLE = IFRAME_DEFAULT_STYLE;
|
|
69
|
+
/**
|
|
70
|
+
* Renders a style record as inline CSS text, for a binding that needs a string rather than an
|
|
71
|
+
* object — Svelte's `style` attribute and `sdk-script`'s `HTMLElement.style.cssText`.
|
|
72
|
+
*/
|
|
73
|
+
static frameStyleText = frameStyleText;
|
|
74
|
+
/**
|
|
75
|
+
* The two iframe attributes a snapshot drives, mapped from protocol terms to DOM ones.
|
|
76
|
+
*
|
|
77
|
+
* Every binding applies this on top of {@link AndcoButtonController.IFRAME_SANDBOX} and
|
|
78
|
+
* {@link AndcoButtonController.IFRAME_REFERRER_POLICY}: those two are fixed, this pair changes
|
|
79
|
+
* with the connection.
|
|
80
|
+
*/
|
|
81
|
+
static frameProps(snapshot) {
|
|
82
|
+
return { src: snapshot.iframeURL, hidden: !snapshot.ready };
|
|
83
|
+
}
|
|
22
84
|
#options;
|
|
23
85
|
#listeners = new Set();
|
|
24
86
|
#bridge;
|
|
@@ -26,6 +88,7 @@ export class AndcoButtonController {
|
|
|
26
88
|
#snapshot;
|
|
27
89
|
#pending;
|
|
28
90
|
#presentationId;
|
|
91
|
+
#intentId;
|
|
29
92
|
#generation = 0;
|
|
30
93
|
/** One automatic reconnect per `connect()` call, so a single slow network blip self-heals without
|
|
31
94
|
* bothering the app — but a persistently broken endpoint still surfaces as a visible `"error"`
|
|
@@ -50,7 +113,7 @@ export class AndcoButtonController {
|
|
|
50
113
|
connect(iframe) {
|
|
51
114
|
this.disconnect();
|
|
52
115
|
this.#iframe = iframe;
|
|
53
|
-
console.debug("[AndcoButtonController] connecting: %
|
|
116
|
+
console.debug("[AndcoButtonController] connecting: %s", this.#snapshot.iframeURL);
|
|
54
117
|
this.#publish({ status: "connecting", ready: false, error: null });
|
|
55
118
|
try {
|
|
56
119
|
this.#bridge = new AndcoButtonBridge(iframe, {
|
|
@@ -80,7 +143,7 @@ export class AndcoButtonController {
|
|
|
80
143
|
const timedOut = event.error.code === ANDCO_PROTOCOL_ERROR_CODES.HANDSHAKE_TIMEOUT;
|
|
81
144
|
if (timedOut && !this.#timedOutOnce && this.#iframe) {
|
|
82
145
|
this.#timedOutOnce = true;
|
|
83
|
-
console.debug("[AndcoButtonController] handshake timed out
|
|
146
|
+
console.debug("[AndcoButtonController] handshake timed out; reconnecting once");
|
|
84
147
|
this.connect(this.#iframe);
|
|
85
148
|
return;
|
|
86
149
|
}
|
|
@@ -93,6 +156,7 @@ export class AndcoButtonController {
|
|
|
93
156
|
}
|
|
94
157
|
return () => this.disconnect();
|
|
95
158
|
}
|
|
159
|
+
/** Detaches the iframe bridge while retaining listeners and the last iframe for reuse. */
|
|
96
160
|
disconnect() {
|
|
97
161
|
this.#bridge?.destroy();
|
|
98
162
|
this.#bridge = undefined;
|
|
@@ -108,25 +172,25 @@ export class AndcoButtonController {
|
|
|
108
172
|
restart() {
|
|
109
173
|
this.#generation += 1;
|
|
110
174
|
this.#pending = undefined;
|
|
175
|
+
this.#intentId = undefined;
|
|
111
176
|
if (this.#snapshot.status === "error" && this.#iframe) {
|
|
112
177
|
// A deliberate retry (the app calling this after showing the error) earns its own one-shot
|
|
113
178
|
// auto-reconnect on a future timeout, same as the very first connect did.
|
|
114
179
|
this.#timedOutOnce = false;
|
|
115
|
-
console.debug("[AndcoButtonController] restarting after an error, reconnecting: %
|
|
116
|
-
code: this.#snapshot.error?.code,
|
|
117
|
-
});
|
|
180
|
+
console.debug("[AndcoButtonController] restarting after an error, reconnecting: %O", this.#snapshot.error);
|
|
118
181
|
this.connect(this.#iframe);
|
|
119
182
|
return;
|
|
120
183
|
}
|
|
121
184
|
this.#publish({ status: this.#bridge ? "ready" : "idle", error: null });
|
|
122
185
|
}
|
|
186
|
+
/** Releases the bridge, iframe reference, and all snapshot listeners. */
|
|
123
187
|
destroy() {
|
|
124
188
|
this.disconnect();
|
|
125
189
|
this.#iframe = undefined;
|
|
126
190
|
this.#listeners.clear();
|
|
127
191
|
}
|
|
128
192
|
/**
|
|
129
|
-
* Prepares
|
|
193
|
+
* Prepares a presentation once the user has activated the hosted control.
|
|
130
194
|
*
|
|
131
195
|
* Deferred on purpose: the iframe holds the user activation and opens the popup synchronously,
|
|
132
196
|
* then asks for the URL. Preparing it earlier would waste a transaction on every render and,
|
|
@@ -135,19 +199,101 @@ export class AndcoButtonController {
|
|
|
135
199
|
async #authorize() {
|
|
136
200
|
const generation = ++this.#generation;
|
|
137
201
|
this.#publish({ status: "authorizing", error: null });
|
|
202
|
+
const presentationId = this.#presentationId;
|
|
138
203
|
// The hosted surface opens the popup, so the callback has to know to deliver its result there.
|
|
139
204
|
// Encoding that in the state is the protocol's own mechanism and the only one available: the
|
|
140
205
|
// callback document cannot read a cross-origin opener's location.
|
|
206
|
+
const state = callbackStateCreate(this.#options.client.config.endpoints.widget.origin, presentationId);
|
|
207
|
+
if (this.#options.flow === "intent")
|
|
208
|
+
return this.#presentIntent(generation, presentationId, state);
|
|
209
|
+
if (this.#options.presentation === "redirect")
|
|
210
|
+
return this.#presentRedirect(generation, presentationId);
|
|
141
211
|
const prepared = await this.#options.client.oauth.createAuthorizationRequest({
|
|
142
212
|
...(this.#options.authorization ?? {}),
|
|
143
|
-
state
|
|
213
|
+
state,
|
|
144
214
|
});
|
|
145
215
|
if (generation !== this.#generation)
|
|
146
216
|
return;
|
|
147
217
|
if (prepared.error)
|
|
148
218
|
return this.#fail(prepared.error);
|
|
149
219
|
this.#pending = prepared.data;
|
|
150
|
-
this.#bridge?.
|
|
220
|
+
this.#bridge?.resolvePresentation(presentationId, prepared.data.authorizationUrl.href);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Presents the authorization by replacing this document.
|
|
224
|
+
*
|
|
225
|
+
* The hosted surface cannot do it: its sandbox grants no top navigation, so a URL resolved back to
|
|
226
|
+
* the iframe would only reach a popup that was never opened. The instance's own sign-in already
|
|
227
|
+
* knows how to redirect — it prepares the request, persists the transaction for the next load, and
|
|
228
|
+
* assigns the location — so the control delegates to it rather than repeating those steps. Nothing
|
|
229
|
+
* settles here on success: the document is gone, and the session arrives through Callback
|
|
230
|
+
* Consumption on the next load.
|
|
231
|
+
*/
|
|
232
|
+
async #presentRedirect(generation, presentationId) {
|
|
233
|
+
console.debug("[AndcoButtonController] presenting by redirect: presentationId=%s", presentationId);
|
|
234
|
+
const signedIn = await this.#options.client.auth.signIn({
|
|
235
|
+
...(this.#options.authorization ?? {}),
|
|
236
|
+
presentation: "redirect",
|
|
237
|
+
});
|
|
238
|
+
if (generation !== this.#generation)
|
|
239
|
+
return;
|
|
240
|
+
if (signedIn.error) {
|
|
241
|
+
// Tell the surface the presentation is over so it leaves its busy state; there is no popup to close.
|
|
242
|
+
this.#bridge?.resolvePresentation(presentationId);
|
|
243
|
+
return this.#fail(signedIn.error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Resolves the Intent this control presents, reusing the instance's own URL construction.
|
|
248
|
+
*
|
|
249
|
+
* It does not build the URL itself. Two constructions of one presentation URL is exactly how the
|
|
250
|
+
* direct and hosted paths drifted before, which is why `intents.presentationURLFor` is published.
|
|
251
|
+
*/
|
|
252
|
+
async #presentIntent(generation, presentationId, state) {
|
|
253
|
+
const client = this.#options.client;
|
|
254
|
+
const intentId = this.#options.intentId;
|
|
255
|
+
if (!intentId) {
|
|
256
|
+
return this.#fail(new AndcoError(ANDCO_ERROR_CODES.INVALID_CONFIGURATION, {
|
|
257
|
+
message: 'a control with flow="intent" requires an intentId',
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
// Out of scope for now, and refused rather than silently resolving to nothing: an Intent result
|
|
261
|
+
// that comes back by redirect has no consumer yet, so the presentation would never settle.
|
|
262
|
+
if (this.#options.presentation === "redirect") {
|
|
263
|
+
return this.#fail(new AndcoError(ANDCO_ERROR_CODES.PRESENTATION_UNSUPPORTED, {
|
|
264
|
+
message: 'an Intent cannot be presented with presentation="redirect" yet',
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
267
|
+
const returnTo = client.config.redirectTo;
|
|
268
|
+
if (!returnTo) {
|
|
269
|
+
return this.#fail(new AndcoError(ANDCO_ERROR_CODES.INVALID_CONFIGURATION, {
|
|
270
|
+
message: "an Intent Presentation needs the instance's redirectTo",
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
let resolvedId;
|
|
274
|
+
try {
|
|
275
|
+
resolvedId = typeof intentId === "string" ? intentId : await intentId();
|
|
276
|
+
}
|
|
277
|
+
catch (cause) {
|
|
278
|
+
return this.#fail(AndcoError.from(cause, ANDCO_ERROR_CODES.INVALID_CONFIGURATION));
|
|
279
|
+
}
|
|
280
|
+
if (generation !== this.#generation) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const url = await client.intents.presentationURLFor(resolvedId, {
|
|
284
|
+
presentation: "popup",
|
|
285
|
+
returnTo,
|
|
286
|
+
errorReturnTo: returnTo,
|
|
287
|
+
state,
|
|
288
|
+
});
|
|
289
|
+
if (generation !== this.#generation) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
else if (url.error) {
|
|
293
|
+
return this.#fail(url.error);
|
|
294
|
+
}
|
|
295
|
+
this.#intentId = resolvedId;
|
|
296
|
+
this.#bridge?.resolvePresentation(presentationId, url.data.href);
|
|
151
297
|
}
|
|
152
298
|
async #settle(event) {
|
|
153
299
|
const generation = this.#generation;
|
|
@@ -170,13 +316,24 @@ export class AndcoButtonController {
|
|
|
170
316
|
}
|
|
171
317
|
if (generation !== this.#generation)
|
|
172
318
|
return;
|
|
319
|
+
// An Intent completion is a lifecycle fact. What it means financially is read, not relayed.
|
|
320
|
+
if (event.type === "intent.complete" && this.#intentId) {
|
|
321
|
+
const intent = await this.#options.client.intents.get(this.#intentId);
|
|
322
|
+
if (generation !== this.#generation)
|
|
323
|
+
return;
|
|
324
|
+
if (intent.error)
|
|
325
|
+
return this.#fail(intent.error);
|
|
326
|
+
this.#publish({ status: "complete", error: null });
|
|
327
|
+
this.#options.onComplete?.({ outcome: "complete", intent: intent.data });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
173
330
|
this.#publish({ status: "complete", error: null });
|
|
174
331
|
this.#options.onComplete?.();
|
|
175
332
|
}
|
|
176
333
|
#fail(error, event) {
|
|
177
334
|
// An app that never wired `onError` must not lose the failure entirely — a button that just sits
|
|
178
335
|
// there disabled, with nothing in the console, is what made the last one of these hard to find.
|
|
179
|
-
console.error("[AndcoButtonController] %
|
|
336
|
+
console.error("[AndcoButtonController] %O", error);
|
|
180
337
|
this.#publish({ status: "error", error });
|
|
181
338
|
this.#options.onError?.(error, event);
|
|
182
339
|
}
|
package/dist/browser/frame.d.ts
CHANGED
|
@@ -40,15 +40,16 @@ export declare class AndcoButtonBridge {
|
|
|
40
40
|
/** Sends a validated protocol message to the hosted iframe. */
|
|
41
41
|
private post;
|
|
42
42
|
/**
|
|
43
|
-
* Resolves a deferred
|
|
43
|
+
* Resolves a deferred presentation the hosted button asked this side to prepare — an
|
|
44
|
+
* authorization or an Intent, which is why it is not named after either.
|
|
44
45
|
* Omit the URL to close the pending popup after resolution fails.
|
|
45
46
|
*
|
|
46
47
|
* @example
|
|
47
48
|
* ```ts
|
|
48
|
-
* bridge.
|
|
49
|
+
* bridge.resolvePresentation(presentationId, "https://app.example.com/oauth/start");
|
|
49
50
|
* ```
|
|
50
51
|
*/
|
|
51
|
-
|
|
52
|
+
resolvePresentation(presentationId: string, url?: string | URL): void;
|
|
52
53
|
/**
|
|
53
54
|
* Forwards a validated same-origin host callback to the iframe that owns the popup.
|
|
54
55
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/browser/frame.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/browser/frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,eAAe,EAEpB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,gCAAgC,EACrC,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAErB,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAEhC,MAAM,iBAAiB,CAAC;AAGzB,iEAAiE;AACjE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,GAAG,uBAAuB,GAAG,wBAAwB,KAAK,IAAI,CAAC;IACpH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,GAAG,uBAAuB,KAAK,IAAI,CAAC;IAC9E,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC7D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IAY1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAZ1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,SAAS,CAAS;gBAGP,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,iBAAiB;IAkB7C,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,OAAO;IAmDf,OAAO,CAAC,QAAQ,CAAC,aAAa,CAM5B;IAEF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAgCzB;IAEF,OAAO,CAAC,QAAQ,CAAC,cAAc,CA2B7B;IAEF,+DAA+D;IAC/D,OAAO,CAAC,IAAI;IASZ;;;;;;;;;OASG;IACI,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG;IAWrE;;;;;;OAMG;IACI,0BAA0B,CAAC,OAAO,EAAE,gBAAgB;IAI3D,oEAAoE;IAC7D,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,WAAW,CAAC;IAU3F,0EAA0E;IACnE,OAAO;CASf"}
|
package/dist/browser/frame.js
CHANGED
|
@@ -34,7 +34,7 @@ export class AndcoButtonBridge {
|
|
|
34
34
|
if (this.url.origin === window.location.origin) {
|
|
35
35
|
throw new AndcoError(ANDCO_ERROR_CODES.SAME_ORIGIN_ENDPOINT, { details: { endpointButton: this.url.href } });
|
|
36
36
|
}
|
|
37
|
-
console.debug("[AndcoButtonBridge] created: %
|
|
37
|
+
console.debug("[AndcoButtonBridge] created: %s", this.url.href);
|
|
38
38
|
iframe.addEventListener("load", this.startHandshake);
|
|
39
39
|
this.startHandshake();
|
|
40
40
|
}
|
|
@@ -62,11 +62,7 @@ export class AndcoButtonBridge {
|
|
|
62
62
|
return;
|
|
63
63
|
this.settled = true;
|
|
64
64
|
this.stopHandshake();
|
|
65
|
-
console.debug("[AndcoButtonBridge] handshake settled:
|
|
66
|
-
attempts: this.handshakeAttempts,
|
|
67
|
-
transport: this.transport,
|
|
68
|
-
elapsedMs: Date.now() - this.handshakeStartedAt,
|
|
69
|
-
});
|
|
65
|
+
console.debug("[AndcoButtonBridge] handshake settled: attempts=%d transport=%s elapsedMs=%d", this.handshakeAttempts, this.transport, Date.now() - this.handshakeStartedAt);
|
|
70
66
|
this.options.onReady?.(message);
|
|
71
67
|
return;
|
|
72
68
|
}
|
|
@@ -75,7 +71,7 @@ export class AndcoButtonBridge {
|
|
|
75
71
|
this.settled = true;
|
|
76
72
|
this.stopHandshake();
|
|
77
73
|
}
|
|
78
|
-
console.warn("[AndcoButtonBridge] hosted surface reported an error: %
|
|
74
|
+
console.warn("[AndcoButtonBridge] hosted surface reported an error: %O", message.error);
|
|
79
75
|
this.options.onError?.(message);
|
|
80
76
|
return;
|
|
81
77
|
}
|
|
@@ -142,9 +138,7 @@ export class AndcoButtonBridge {
|
|
|
142
138
|
// makes the very first attempt throw a targetOrigin mismatch; the 250ms retry loop recovers
|
|
143
139
|
// once the iframe has actually navigated, so a transient failure here is not fatal — but it is
|
|
144
140
|
// worth a log line, since a run that never recovers looks identical to this from the outside.
|
|
145
|
-
console.debug("[AndcoButtonBridge] init attempt %d could not post yet, retrying: %
|
|
146
|
-
cause,
|
|
147
|
-
});
|
|
141
|
+
console.debug("[AndcoButtonBridge] init attempt %d could not post yet, retrying: %O", this.handshakeAttempts, cause);
|
|
148
142
|
}
|
|
149
143
|
};
|
|
150
144
|
startHandshake = () => {
|
|
@@ -160,10 +154,7 @@ export class AndcoButtonBridge {
|
|
|
160
154
|
this.settled = true;
|
|
161
155
|
this.stopHandshake();
|
|
162
156
|
this.closePort();
|
|
163
|
-
console.error("[AndcoButtonBridge] handshake timed out:
|
|
164
|
-
attempts: this.handshakeAttempts,
|
|
165
|
-
endpointButton: this.url.href,
|
|
166
|
-
});
|
|
157
|
+
console.error("[AndcoButtonBridge] handshake timed out: attempts=%d endpointButton=%s", this.handshakeAttempts, this.url.href);
|
|
167
158
|
const message = {
|
|
168
159
|
protocol: ANDCO_SDK_PROTOCOL,
|
|
169
160
|
version: ANDCO_PROTOCOL_VERSION,
|
|
@@ -185,21 +176,22 @@ export class AndcoButtonBridge {
|
|
|
185
176
|
this.iframe.contentWindow?.postMessage(message, this.url.origin);
|
|
186
177
|
}
|
|
187
178
|
/**
|
|
188
|
-
* Resolves a deferred
|
|
179
|
+
* Resolves a deferred presentation the hosted button asked this side to prepare — an
|
|
180
|
+
* authorization or an Intent, which is why it is not named after either.
|
|
189
181
|
* Omit the URL to close the pending popup after resolution fails.
|
|
190
182
|
*
|
|
191
183
|
* @example
|
|
192
184
|
* ```ts
|
|
193
|
-
* bridge.
|
|
185
|
+
* bridge.resolvePresentation(presentationId, "https://app.example.com/oauth/start");
|
|
194
186
|
* ```
|
|
195
187
|
*/
|
|
196
|
-
|
|
188
|
+
resolvePresentation(presentationId, url) {
|
|
197
189
|
const message = {
|
|
198
190
|
protocol: ANDCO_SDK_PROTOCOL,
|
|
199
191
|
version: ANDCO_PROTOCOL_VERSION,
|
|
200
|
-
type: "
|
|
192
|
+
type: "presentation-response",
|
|
201
193
|
presentationId,
|
|
202
|
-
|
|
194
|
+
url: url?.toString(),
|
|
203
195
|
};
|
|
204
196
|
this.post(message);
|
|
205
197
|
}
|
|
@@ -227,7 +219,7 @@ export class AndcoButtonBridge {
|
|
|
227
219
|
destroy() {
|
|
228
220
|
if (this.destroyed)
|
|
229
221
|
return;
|
|
230
|
-
console.debug("[AndcoButtonBridge] destroyed:
|
|
222
|
+
console.debug("[AndcoButtonBridge] destroyed: settled=%s attempts=%d", this.settled, this.handshakeAttempts);
|
|
231
223
|
this.destroyed = true;
|
|
232
224
|
window.removeEventListener("message", this.receiveWindow);
|
|
233
225
|
this.iframe.removeEventListener("load", this.startHandshake);
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { AndcoClient, type AndcoClientOptions } from "../client.js";
|
|
2
|
+
import { Result } from "../errors.js";
|
|
2
3
|
import type { AndcoAuthorizationRequest } from "../oauth.js";
|
|
3
|
-
import
|
|
4
|
+
import { AndcoPresenter, type AndcoPresentOptions } from "../presenter.js";
|
|
4
5
|
export { AndcoButtonController, type AndcoButtonControllerOptions, type AndcoButtonFlow, type AndcoButtonSnapshot, type AndcoButtonStatus, } from "./controller.js";
|
|
5
6
|
export { AndcoButtonBridge, type AndcoFrameOptions } from "./frame.js";
|
|
6
7
|
export { type AndcoPopupMessage, type AndcoPopupWindow, type AndcoRelayOutcome, andcoPopupPresentationId, isAndcoNativeHost, openAndcoPopup, openAndcoPopupWindow, relayAndcoPopupCallback, } from "./popup.js";
|
|
7
8
|
/**
|
|
8
|
-
* Presents an authorization in a browser.
|
|
9
|
+
* Presents an authorization or an Intent in a browser.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* A browser treats both alike — one window, one callback — so it reads `kind` only to refuse what
|
|
12
|
+
* it cannot do. It detects the first-party Andco Host and routes over the native bridge instead of
|
|
13
|
+
* opening a window, so a Miniapp runs the same build in a browser tab and inside the Host without
|
|
14
|
+
* branching on the platform. That is why there is no mobile presenter and no mobile builder.
|
|
15
|
+
*
|
|
16
|
+
* The window opens *before* the destination is resolved. A browser grants `window.open` only during
|
|
17
|
+
* a user activation, and both flows need a server round trip to learn where the window should go:
|
|
18
|
+
* an authorization may be pushed, and an Intent is created on demand. Resolving first is what got
|
|
19
|
+
* the window blocked.
|
|
13
20
|
*/
|
|
14
|
-
export declare
|
|
21
|
+
export declare class AndcoPresenterBrowser extends AndcoPresenter {
|
|
22
|
+
#private;
|
|
23
|
+
focus(presentationId: string): void;
|
|
24
|
+
present(options: AndcoPresentOptions): Promise<Result<URL | null>>;
|
|
25
|
+
}
|
|
26
|
+
/** Public-client options for browser sign-in, callback relay, and transaction recovery. */
|
|
15
27
|
export type AndcoBrowserOptions = Omit<AndcoClientOptions, "presenter" | "source" | "clientSecret"> & {
|
|
16
28
|
/** Rejected by type: a confidential credential must never reach a browser. */
|
|
17
29
|
clientSecret?: never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGpE,OAAO,EAAqB,MAAM,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,yBAAyB,EAAc,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAI3E,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,SAAQ,cAAc;;IAI9C,KAAK,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAKtC,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;CA8CzE;AAED,2FAA2F;AAC3F,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,kBAAkB,EAAE,WAAW,GAAG,QAAQ,GAAG,cAAc,CAAC,GAAG;IACpG,8EAA8E;IAC9E,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,iGAAiG;IACjG,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,mBAAmB,GAAG,WAAW,CAkBvF;AA0CD,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAMnH"}
|
package/dist/browser/index.js
CHANGED
|
@@ -1,40 +1,75 @@
|
|
|
1
1
|
import { AndcoClient } from "../client.js";
|
|
2
2
|
import { ANDCO_ERROR_CODES, Result } from "../errors.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { AndcoPresenter } from "../presenter.js";
|
|
4
|
+
import { LocalStorage } from "../storage.js";
|
|
5
|
+
import { andcoPopupPresentationId, isAndcoNativeHost, openAndcoPopupWindow, relayAndcoPopupCallback } from "./popup.js";
|
|
5
6
|
export { AndcoButtonController, } from "./controller.js";
|
|
6
7
|
export { AndcoButtonBridge } from "./frame.js";
|
|
7
8
|
export { andcoPopupPresentationId, isAndcoNativeHost, openAndcoPopup, openAndcoPopupWindow, relayAndcoPopupCallback, } from "./popup.js";
|
|
8
9
|
/**
|
|
9
|
-
* Presents an authorization in a browser.
|
|
10
|
+
* Presents an authorization or an Intent in a browser.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* A browser treats both alike — one window, one callback — so it reads `kind` only to refuse what
|
|
13
|
+
* it cannot do. It detects the first-party Andco Host and routes over the native bridge instead of
|
|
14
|
+
* opening a window, so a Miniapp runs the same build in a browser tab and inside the Host without
|
|
15
|
+
* branching on the platform. That is why there is no mobile presenter and no mobile builder.
|
|
16
|
+
*
|
|
17
|
+
* The window opens *before* the destination is resolved. A browser grants `window.open` only during
|
|
18
|
+
* a user activation, and both flows need a server round trip to learn where the window should go:
|
|
19
|
+
* an authorization may be pushed, and an Intent is created on demand. Resolving first is what got
|
|
20
|
+
* the window blocked.
|
|
14
21
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
export class AndcoPresenterBrowser extends AndcoPresenter {
|
|
23
|
+
/** Windows still open, by Presentation ID, so {@link AndcoPresenterBrowser.focus} can find them. */
|
|
24
|
+
#open = new Map();
|
|
25
|
+
focus(presentationId) {
|
|
26
|
+
console.debug("[AndcoPresenterBrowser.focus] %s open=%s", presentationId, this.#open.has(presentationId));
|
|
27
|
+
this.#open.get(presentationId)?.focus();
|
|
28
|
+
}
|
|
29
|
+
async present(options) {
|
|
30
|
+
if (typeof window === "undefined")
|
|
31
|
+
return Result.fail(ANDCO_ERROR_CODES.BROWSER_REQUIRED);
|
|
32
|
+
if (options.presentation === "redirect") {
|
|
33
|
+
const resolved = await AndcoPresenter.present(options.url);
|
|
34
|
+
if (resolved.error) {
|
|
35
|
+
console.error("[AndcoPresenterBrowser] for options %O got error: %O", options, resolved.error);
|
|
36
|
+
return Result.fail(resolved.error);
|
|
29
37
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
console.debug("[AndcoPresenterBrowser] will window location assign: %s", resolved.data.href);
|
|
39
|
+
window.location.assign(resolved.data.href);
|
|
40
|
+
// The document is being replaced. The result arrives on the next load, not here.
|
|
41
|
+
return Result.ok(null);
|
|
42
|
+
}
|
|
43
|
+
if (isAndcoNativeHost() && window["__ANDCO_NATIVE_POPUP_HANDLER__"] !== true) {
|
|
44
|
+
return Result.fail(ANDCO_ERROR_CODES.PRESENTATION_UNSUPPORTED, {
|
|
45
|
+
message: "the native Host cannot present a popup without navigating the Miniapp",
|
|
35
46
|
});
|
|
36
|
-
}
|
|
37
|
-
|
|
47
|
+
}
|
|
48
|
+
const popup = openAndcoPopupWindow({
|
|
49
|
+
presentationId: options.presentationId,
|
|
50
|
+
expectedOrigin: options.returnTo.origin,
|
|
51
|
+
signal: options.signal,
|
|
52
|
+
target: options.kind === "intent" && options.presentation === "newtab" ? "newtab" : "popup",
|
|
53
|
+
});
|
|
54
|
+
// Abandon before the server work: a blocked window that still started an authorization or
|
|
55
|
+
// created an Intent would leave a transaction nobody can complete.
|
|
56
|
+
if (popup.blocked) {
|
|
57
|
+
return Result.fail(ANDCO_ERROR_CODES.POPUP_BLOCKED);
|
|
58
|
+
}
|
|
59
|
+
this.#open.set(options.presentationId, popup);
|
|
60
|
+
try {
|
|
61
|
+
const resolved = await AndcoPresenter.present(options.url);
|
|
62
|
+
if (resolved.error) {
|
|
63
|
+
popup.close();
|
|
64
|
+
return Result.fail(resolved.error);
|
|
65
|
+
}
|
|
66
|
+
popup.navigate(resolved.data);
|
|
67
|
+
return await popup.result;
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
this.#open.delete(options.presentationId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
38
73
|
}
|
|
39
74
|
const TRANSACTION_KEY = "andco.transaction";
|
|
40
75
|
/**
|
|
@@ -59,8 +94,8 @@ const TRANSACTION_KEY = "andco.transaction";
|
|
|
59
94
|
* ```
|
|
60
95
|
*/
|
|
61
96
|
export function createAndcoInstanceForBrowser(options) {
|
|
62
|
-
const presenter = options.presenter ??
|
|
63
|
-
const storage = options.storage ?? (typeof window === "undefined" ? undefined : new
|
|
97
|
+
const presenter = options.presenter ?? new AndcoPresenterBrowser();
|
|
98
|
+
const storage = options.storage ?? (typeof window === "undefined" ? undefined : new LocalStorage());
|
|
64
99
|
// Annotated because `source` closes over `client`; the closure only runs on the first read.
|
|
65
100
|
const client = new AndcoClient({
|
|
66
101
|
...options,
|
package/dist/browser/popup.d.ts
CHANGED
|
@@ -41,7 +41,8 @@ export declare function isAndcoNativeHost(): boolean;
|
|
|
41
41
|
*/
|
|
42
42
|
export declare function andcoPopupPresentationId(): string | null;
|
|
43
43
|
/**
|
|
44
|
-
* Hands this document's callback to the window that
|
|
44
|
+
* Hands this document's callback — an authorization or an Intent outcome — to the window that
|
|
45
|
+
* opened it, then closes.
|
|
45
46
|
*
|
|
46
47
|
* The popup cannot complete the exchange itself: the PKCE verifier was generated by the opener and
|
|
47
48
|
* never left it. So this is a courier, not a consumer — it carries the callback URL back and dies.
|
|
@@ -73,6 +74,8 @@ export type AndcoPopupWindow = {
|
|
|
73
74
|
navigate(url: URL): void;
|
|
74
75
|
/** Settles with the relayed callback, `null` on dismissal, or an error. */
|
|
75
76
|
readonly result: Promise<Result<URL | null>>;
|
|
77
|
+
/** Brings the window to the front; a browser may decline when no user activation is current. */
|
|
78
|
+
focus(): void;
|
|
76
79
|
close(): void;
|
|
77
80
|
};
|
|
78
81
|
/**
|
|
@@ -94,6 +97,8 @@ export declare function openAndcoPopupWindow(options: {
|
|
|
94
97
|
expectedOrigin: string;
|
|
95
98
|
url?: URL;
|
|
96
99
|
signal?: AbortSignal;
|
|
100
|
+
/** `"newtab"` opens a tab instead of a sized window; the relay back is the same. Default `"popup"`. */
|
|
101
|
+
target?: "popup" | "newtab";
|
|
97
102
|
}): AndcoPopupWindow;
|
|
98
103
|
/** Opens a popup straight to its destination and waits for the relayed callback. */
|
|
99
104
|
export declare function openAndcoPopup(options: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popup.d.ts","sourceRoot":"","sources":["../../src/browser/popup.ts"],"names":[],"mappings":"AAOA,OAAO,EAAqB,UAAU,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAMrE,mGAAmG;AACnG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAC1B;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE9C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,uEAAuE;QACvE,qBAAqB,CAAC,EAAE,OAAO,CAAC;QAChC,sFAAsF;QACtF,8BAA8B,CAAC,EAAE,OAAO,CAAC;QACzC,kBAAkB,CAAC,EAAE;YAAE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAC;KAC7D;CACF;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,OAAO,CAM3C;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAMxD;AAED
|
|
1
|
+
{"version":3,"file":"popup.d.ts","sourceRoot":"","sources":["../../src/browser/popup.ts"],"names":[],"mappings":"AAOA,OAAO,EAAqB,UAAU,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAMrE,mGAAmG;AACnG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAC1B;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE9C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,uEAAuE;QACvE,qBAAqB,CAAC,EAAE,OAAO,CAAC;QAChC,sFAAsF;QACtF,8BAA8B,CAAC,EAAE,OAAO,CAAC;QACzC,kBAAkB,CAAC,EAAE;YAAE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAC;KAC7D;CACF;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,OAAO,CAM3C;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAMxD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,EACnC,OAAO,GAAE;IACP;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CACvB,GACL,iBAAiB,CAyCnB;AAoCD,sFAAsF;AACtF,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;IAC7C,gGAAgG;IAChG,KAAK,IAAI,IAAI,CAAC;IACd,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uGAAuG;IACvG,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B,GAAG,gBAAgB,CAsEnB;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,GAAG,EAAE,GAAG,CAAC;IACT,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAE9B"}
|