@alexkroman1/aai-ui 6.7.1 → 6.8.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.
- package/dist/_upload-files.d.ts +67 -0
- package/dist/_upload-session.d.ts +99 -0
- package/dist/components/_form-readiness.d.ts +56 -0
- package/dist/components/upload-progress.d.ts +14 -1
- package/dist/default-client/assets/index-DTLrhtTF.css +2 -0
- package/dist/default-client/index.html +2 -2
- package/dist/index.js +508 -149
- package/dist/use-workflow-form.d.ts +25 -0
- package/dist/use-workflow-stream.d.ts +32 -6
- package/package.json +2 -2
- package/dist/default-client/assets/index-BZlePk3y.css +0 -2
- /package/dist/default-client/assets/{index-CepvxbNU.js → index-DXODx_9r.js} +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a form's `File`s into stored upload ids, pauses and all.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `use-workflow-form.ts` for the 500-line cap, and the seam is a
|
|
5
|
+
* real one: that module is the two HOOKS and the state between them, where this
|
|
6
|
+
* is the walk over a submitted input — which is the only part of it that knows
|
|
7
|
+
* what a `File` is, holds a loop, and survives being re-entered.
|
|
8
|
+
*
|
|
9
|
+
* `_`-internal. `useWorkflowSubmit` is the only caller; `useWorkflowStream` sends
|
|
10
|
+
* one file rather than walking an input and shares only the gate underneath both
|
|
11
|
+
* (`_upload-session.ts`).
|
|
12
|
+
*/
|
|
13
|
+
import type { UploadParallel } from "@alexkroman1/aai/workflow-api";
|
|
14
|
+
import { type UploadGate } from "./_upload-session.ts";
|
|
15
|
+
import type { UploadStatus } from "./use-workflow-form.ts";
|
|
16
|
+
import type { WorkflowApi } from "./workflow-client.ts";
|
|
17
|
+
/**
|
|
18
|
+
* What one submission's uploads know about themselves, across pauses.
|
|
19
|
+
*
|
|
20
|
+
* Held by the hook rather than by the walk below, because the walk RE-RUNS: a
|
|
21
|
+
* pause unwinds nothing, so resuming re-enters `uploadFiles` with the same input
|
|
22
|
+
* and the same session, and every file whose bytes are already in is skipped by
|
|
23
|
+
* `stored` rather than sent again.
|
|
24
|
+
*
|
|
25
|
+
* Which is also why the ids live here. A resumable upload is one whose id
|
|
26
|
+
* outlives the attempt that began it — that is the whole mechanism — so an id
|
|
27
|
+
* minted per attempt would make each round a fresh upload of the whole file.
|
|
28
|
+
*/
|
|
29
|
+
export type UploadSession = {
|
|
30
|
+
/** The id each file is being stored under, minted once. */
|
|
31
|
+
ids: Map<File, string>;
|
|
32
|
+
/** Files whose every byte has landed, by the id they landed under. */
|
|
33
|
+
stored: Map<File, string>;
|
|
34
|
+
/** Files that have had an attempt, so the next one must claim the id as its own. */
|
|
35
|
+
tried: Set<File>;
|
|
36
|
+
/** The person's pause. */
|
|
37
|
+
gate: UploadGate;
|
|
38
|
+
};
|
|
39
|
+
/** A fresh session for one submission. */
|
|
40
|
+
export declare function createUploadSession(): UploadSession;
|
|
41
|
+
/**
|
|
42
|
+
* Replace every `File` in a submitted form with the id of a stored upload,
|
|
43
|
+
* reporting how far each one has got.
|
|
44
|
+
*
|
|
45
|
+
* Sequential rather than `Promise.all`: these are large bodies, and a form with
|
|
46
|
+
* two 200 MB recordings should send them one after another rather than compete
|
|
47
|
+
* for the same connection. That is also what makes a single bar honest — one
|
|
48
|
+
* file is in flight at a time, and `index`/`count` say which.
|
|
49
|
+
*
|
|
50
|
+
* Anything that is not a `File` (or an array of them) passes through untouched,
|
|
51
|
+
* so this is invisible to every form that has none — including one whose values
|
|
52
|
+
* are not an object at all, which `submit` accepts.
|
|
53
|
+
*
|
|
54
|
+
* ## `uploadStream`, not `upload`, and the id is the reason
|
|
55
|
+
*
|
|
56
|
+
* The difference between the two calls is only who mints the id — and that is
|
|
57
|
+
* exactly what decides whether an interrupted upload can be picked up again. An
|
|
58
|
+
* `upload` mints its own at the END and hands it back, so a caller whose upload
|
|
59
|
+
* died has nothing to name what was stored and no choice but to send the file
|
|
60
|
+
* again. A `uploadStream` is told the id up front, so the windows already in the
|
|
61
|
+
* store are addressable, which is what both a pause and a server restart need.
|
|
62
|
+
*
|
|
63
|
+
* Nothing else about the submission changes: the run is still started after the
|
|
64
|
+
* last byte lands, so the incomplete record a streamed upload leaves along the
|
|
65
|
+
* way is one nobody reads.
|
|
66
|
+
*/
|
|
67
|
+
export declare function uploadFiles(api: WorkflowApi, input: unknown, report: (status: UploadStatus) => void, parallel: UploadParallel | undefined, session: UploadSession): Promise<unknown>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driving ONE resumable upload from a page: its id, and the gate a person can
|
|
3
|
+
* close.
|
|
4
|
+
*
|
|
5
|
+
* The SDK already survives the server going away — a round that fails for a
|
|
6
|
+
* reason that looks like an outage re-enters itself with `resume: true` and sends
|
|
7
|
+
* only the windows that are missing (`aai/sdk/_upload-resume.ts`). This is the
|
|
8
|
+
* same mechanism turned around and handed to the PERSON: pausing is an outage
|
|
9
|
+
* they caused, resuming is the round after it, and the store cannot tell the two
|
|
10
|
+
* apart because there is nothing to tell apart.
|
|
11
|
+
*
|
|
12
|
+
* ## Why a gate rather than a boolean
|
|
13
|
+
*
|
|
14
|
+
* Pausing has to do two things that a `paused` flag cannot: stop the bytes that
|
|
15
|
+
* are already on the wire, and hold the loop that would send the next ones. So it
|
|
16
|
+
* is an `AbortController` and a promise — abort what is in flight, and park the
|
|
17
|
+
* uploader on `settle()` until somebody opens the gate again.
|
|
18
|
+
*
|
|
19
|
+
* The controller is REPLACED on resume rather than reused, because an aborted
|
|
20
|
+
* signal stays aborted; a caller therefore has to read {@link UploadGate.signal}
|
|
21
|
+
* fresh for each attempt rather than capturing it once.
|
|
22
|
+
*
|
|
23
|
+
* ## The loop this is built for
|
|
24
|
+
*
|
|
25
|
+
* ```ts no-check
|
|
26
|
+
* while (!gate.cancelled) {
|
|
27
|
+
* await gate.settle();
|
|
28
|
+
* if (gate.cancelled) break;
|
|
29
|
+
* try {
|
|
30
|
+
* await api.uploadStream(id, file, { signal: gate.signal, resume: tried });
|
|
31
|
+
* break;
|
|
32
|
+
* } catch (err) {
|
|
33
|
+
* // An abort that is not a cancel is a PAUSE: go back and wait.
|
|
34
|
+
* if (!isAbort(err) || gate.cancelled) throw err;
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* **The catch keys off the abort, not off `gate.paused`,** and that is the one
|
|
40
|
+
* subtle part. Pausing and immediately resuming — a double-click, or a person
|
|
41
|
+
* changing their mind inside the round trip — resolves the gate before the
|
|
42
|
+
* rejection this abort caused has even landed, so a `paused` check would read
|
|
43
|
+
* `false` and rethrow an `AbortError` as though the upload had failed. Every
|
|
44
|
+
* abort reaching that catch was caused by this gate, so every one of them is a
|
|
45
|
+
* pause unless the gate was cancelled outright.
|
|
46
|
+
*/
|
|
47
|
+
/** A person's pause, as the uploader sees it. */
|
|
48
|
+
export type UploadGate = {
|
|
49
|
+
/** Whether the gate is currently closed. For rendering, not for control flow. */
|
|
50
|
+
readonly paused: boolean;
|
|
51
|
+
/** Whether the upload was abandoned. A cancelled gate never opens again. */
|
|
52
|
+
readonly cancelled: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The signal for the NEXT attempt. Re-read it per attempt: resuming installs a
|
|
55
|
+
* fresh controller, and the previous one stays aborted forever.
|
|
56
|
+
*/
|
|
57
|
+
readonly signal: AbortSignal;
|
|
58
|
+
/** Stop the bytes in flight and hold the uploader. A no-op when already closed. */
|
|
59
|
+
pause: () => void;
|
|
60
|
+
/** Open the gate and install a fresh signal. A no-op when not paused. */
|
|
61
|
+
resume: () => void;
|
|
62
|
+
/**
|
|
63
|
+
* Abandon the upload for good.
|
|
64
|
+
*
|
|
65
|
+
* Distinct from a pause in exactly one way that matters to the loop above: it
|
|
66
|
+
* releases the gate rather than holding it, so an uploader parked on `settle()`
|
|
67
|
+
* wakes up and leaves instead of waiting for a resume that is not coming. What
|
|
68
|
+
* a caller does with a cancelled upload's stored windows is its own business —
|
|
69
|
+
* they stay in the store, addressable by an id only the caller has.
|
|
70
|
+
*/
|
|
71
|
+
cancel: () => void;
|
|
72
|
+
/** Resolves as soon as the gate is open — immediately, when it already is. */
|
|
73
|
+
settle: () => Promise<void>;
|
|
74
|
+
};
|
|
75
|
+
/** Whether this rejection is an abort, in either of the two shapes runtimes throw. */
|
|
76
|
+
export declare function isAbortError(err: unknown): boolean;
|
|
77
|
+
/** A fresh upload id: a capability, so it is random rather than derived. */
|
|
78
|
+
export declare function randomUploadId(): string;
|
|
79
|
+
/**
|
|
80
|
+
* Send one file, waiting out however many pauses the person takes.
|
|
81
|
+
*
|
|
82
|
+
* The loop from the module doc, written once: both hooks need exactly this and a
|
|
83
|
+
* second copy of it is a second place for the abort/pause distinction to be got
|
|
84
|
+
* wrong. `send` is handed whether this attempt must CLAIM the id as its own —
|
|
85
|
+
* false the first time, since a fresh id has nothing to resume and saying
|
|
86
|
+
* otherwise waives the refusal that makes a caller-chosen id safe.
|
|
87
|
+
*
|
|
88
|
+
* Throws whatever `send` threw, except an abort the gate caused. A cancelled gate
|
|
89
|
+
* throws too: the caller distinguishes it by reading `gate.cancelled`, which is
|
|
90
|
+
* how an abandoned submission unwinds without being reported as a failure.
|
|
91
|
+
*/
|
|
92
|
+
export declare function sendThroughGate(gate: UploadGate, send: (resume: boolean) => Promise<void>): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* A gate, open.
|
|
95
|
+
*
|
|
96
|
+
* One per upload rather than one per hook: the id and the windows already stored
|
|
97
|
+
* belong to a file, so a gate that outlived its file would resume something else.
|
|
98
|
+
*/
|
|
99
|
+
export declare function createUploadGate(): UploadGate;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a form's own fields exist yet.
|
|
3
|
+
*
|
|
4
|
+
* `<Form>` leans entirely on NATIVE validation — it is a real `<form>` with no
|
|
5
|
+
* `noValidate`, so a `required` field is what stops an empty submit, and the
|
|
6
|
+
* module doc next door says so. That has one hole, and it is the whole reason
|
|
7
|
+
* this exists: a field set declared REMOTELY is not in the DOM while its
|
|
8
|
+
* declaration is in flight, so there is nothing for the browser to validate and
|
|
9
|
+
* an empty submit sails through.
|
|
10
|
+
*
|
|
11
|
+
* It is not theoretical. `<WorkflowFields>` renders `null` until the workflow
|
|
12
|
+
* listing lands, so the transcription desk's first click — before the one-request
|
|
13
|
+
* lookup answered — submitted a form holding only its button. The browser was
|
|
14
|
+
* happy, the payload was `{}`, and the run was refused by the agent with
|
|
15
|
+
* `Invalid input for workflow "transcribeStream": recording: Invalid input`: a
|
|
16
|
+
* schema complaint about a field the person had not been shown, naming a workflow
|
|
17
|
+
* they did not choose by name, for a file picker that appeared a moment later.
|
|
18
|
+
*
|
|
19
|
+
* ## Readiness is DECLARED by the children, because only they know
|
|
20
|
+
*
|
|
21
|
+
* `Form` cannot ask. It renders `{children}` and reads the DOM on submit, and a
|
|
22
|
+
* pending fetch leaves no trace in the DOM at all — which is exactly the
|
|
23
|
+
* difference from `data-aai-read`, the other thing a child tells the form: that
|
|
24
|
+
* one describes an element that EXISTS. So this is a context rather than an
|
|
25
|
+
* attribute, and it carries the one fact a DOM read cannot recover.
|
|
26
|
+
*
|
|
27
|
+
* A form with no such children is ready by definition — `useFormFieldsPending`
|
|
28
|
+
* outside a provider reports nothing pending, so every hand-written form is
|
|
29
|
+
* unaffected and `Form` keeps working outside this package.
|
|
30
|
+
*/
|
|
31
|
+
/** What a child calls to say whether its own fields are ready. */
|
|
32
|
+
type Readiness = (key: string, pending: boolean) => void;
|
|
33
|
+
export declare const FormReadinessProvider: import("react").Provider<Readiness | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Track which children are still waiting for their fields.
|
|
36
|
+
*
|
|
37
|
+
* A SET keyed by the child's own `useId`, not a counter: a child that re-renders
|
|
38
|
+
* while pending must not increment twice, and one that unmounts mid-flight must
|
|
39
|
+
* not leave the form disabled forever. Both are the ordinary lifecycle here — a
|
|
40
|
+
* page that switches workflows swaps one `<WorkflowFields>` for another.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useFormReadiness(): {
|
|
43
|
+
pending: boolean;
|
|
44
|
+
declare: Readiness;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Declare from a child that its fields are, or are no longer, still loading.
|
|
48
|
+
*
|
|
49
|
+
* Reports through an EFFECT rather than during render, because this writes to a
|
|
50
|
+
* parent's state — doing it in the render body is the "cannot update a component
|
|
51
|
+
* while rendering a different component" warning, and under StrictMode it is a
|
|
52
|
+
* double report the parent has to be idempotent about anyway. The cleanup
|
|
53
|
+
* releases the claim, so an unmounted field set never holds the form shut.
|
|
54
|
+
*/
|
|
55
|
+
export declare function useDeclareFieldsPending(pending: boolean): void;
|
|
56
|
+
export {};
|
|
@@ -22,6 +22,14 @@ import type { UploadStatus } from "../use-workflow-form.ts";
|
|
|
22
22
|
* - **The file is NAMED, and counted when there is more than one.** Files are
|
|
23
23
|
* sent one after another, so a single bar otherwise appears to restart from
|
|
24
24
|
* zero partway through with nothing to say why.
|
|
25
|
+
* - **A paused upload SAYS SO, rather than being a bar that stopped.** Those look
|
|
26
|
+
* identical, which is the whole reason `UploadStatus.paused` exists, and the
|
|
27
|
+
* fill stops animating so the difference is visible without reading.
|
|
28
|
+
*
|
|
29
|
+
* The pause control appears only when a handler for it is passed. That is not
|
|
30
|
+
* politeness about props: a button whose press does nothing is worse than no
|
|
31
|
+
* button, and a page holding an `upload` it did not produce (a saved status, a
|
|
32
|
+
* parent's state) has nothing to pause.
|
|
25
33
|
*
|
|
26
34
|
* @example
|
|
27
35
|
* ```tsx
|
|
@@ -41,12 +49,17 @@ import type { UploadStatus } from "../use-workflow-form.ts";
|
|
|
41
49
|
*
|
|
42
50
|
* @param upload - What `useWorkflowSubmit` reports. `undefined` renders nothing,
|
|
43
51
|
* so a page may pass its state straight through.
|
|
52
|
+
* @param onPause - The hook's `pauseUpload`. Pass it together with `onResume` to
|
|
53
|
+
* get the control; pass neither for a bar that only reports.
|
|
54
|
+
* @param onResume - The hook's `resumeUpload`.
|
|
44
55
|
* @param className - Replaces the default classes rather than extending them,
|
|
45
56
|
* so a custom chrome is not fighting a default it did not ask for.
|
|
46
57
|
*
|
|
47
58
|
* @public
|
|
48
59
|
*/
|
|
49
|
-
export declare function UploadProgressBar({ upload, className, }: {
|
|
60
|
+
export declare function UploadProgressBar({ upload, onPause, onResume, className, }: {
|
|
50
61
|
upload?: UploadStatus | undefined;
|
|
62
|
+
onPause?: (() => void) | undefined;
|
|
63
|
+
onResume?: (() => void) | undefined;
|
|
51
64
|
className?: string | undefined;
|
|
52
65
|
}): ReactNode;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--font-aai:"Monument Grotesk", "ABC Monument Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-aai-serif:"Source Serif 4", "Source Serif Pro", Charter, "Iowan Old Style", Georgia, serif;--font-aai-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;--radius-aai:4px}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}html,body{margin:0;padding:0}}@layer components;@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.order-last{order:9999}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-auto{margin-inline:auto}.my-0\.5{margin-block:calc(var(--spacing) * .5)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2\.5{margin-block:calc(var(--spacing) * 2.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.box-border{box-sizing:border-box}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-9{height:calc(var(--spacing) * 9)}.h-11{height:calc(var(--spacing) * 11)}.h-\[7px\]{height:7px}.h-full{height:100%}.h-screen{height:100vh}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-\[40vh\]{max-height:40vh}.min-h-0{min-height:0}.min-h-5{min-height:calc(var(--spacing) * 5)}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-4{width:calc(var(--spacing) * 4)}.w-\[7px\]{width:7px}.w-fit{width:fit-content}.w-full{width:100%}.max-w-75{max-width:calc(var(--spacing) * 75)}.max-w-105{max-width:calc(var(--spacing) * 105)}.max-w-190{max-width:calc(var(--spacing) * 190)}.max-w-\[82\%\]{max-width:82%}.max-w-\[min\(78\%\,64ch\)\]{max-width:min(78%,64ch)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-full{flex-basis:100%}.border-collapse{border-collapse:collapse}.rotate-90{rotate:90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.resize{resize:both}.\[scrollbar-width\:none\]{scrollbar-width:none}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded-aai{border-radius:var(--radius-aai)}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-none{--tw-border-style:none;border-style:none}.border-\(--aai-btn-bd\){border-color:var(--aai-btn-bd)}.bg-\(--aai-btn-bg\){background-color:var(--aai-btn-bg)}.bg-transparent{background-color:#0000}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-4{padding:calc(var(--spacing) * 4)}.p-7{padding:calc(var(--spacing) * 7)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-7{padding-inline:calc(var(--spacing) * 7)}.px-10{padding-inline:calc(var(--spacing) * 10)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pl-1\.5{padding-left:calc(var(--spacing) * 1.5)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.font-aai{font-family:var(--font-aai)}.font-aai-mono{font-family:var(--font-aai-mono)}.font-aai-serif{font-family:var(--font-aai-serif)}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.625rem\]{font-size:.625rem}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[22px\]{font-size:22px}.text-\[32px\]{font-size:32px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-\[1\.15\]{--tw-leading:1.15;line-height:1.15}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[23px\]{--tw-leading:23px;line-height:23px}.leading-\[130\%\]{--tw-leading:130%;line-height:130%}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.2px\]{--tw-tracking:-.2px;letter-spacing:-.2px}.tracking-\[1\.2px\]{--tw-tracking:1.2px;letter-spacing:1.2px}.tracking-\[1\.4px\]{--tw-tracking:1.4px;letter-spacing:1.4px}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-balance{text-wrap:balance}.wrap-break-word{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\(--aai-btn-fg\){color:var(--aai-btn-fg)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.file\:mr-3::file-selector-button{margin-right:calc(var(--spacing) * 3)}.file\:cursor-pointer::file-selector-button{cursor:pointer}.file\:rounded-aai::file-selector-button{border-radius:var(--radius-aai)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:px-3::file-selector-button{padding-inline:calc(var(--spacing) * 3)}.file\:py-1\.5::file-selector-button{padding-block:calc(var(--spacing) * 1.5)}.file\:font-aai::file-selector-button{font-family:var(--font-aai)}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:\[color\:var\(--aai-file-button-fg\)\]::file-selector-button{color:var(--aai-file-button-fg)}.file\:\[background\:var\(--aai-file-button-bg\)\]::file-selector-button{background:var(--aai-file-button-bg)}.first\:mt-0:first-child{margin-top:0}.last\:mb-0:last-child{margin-bottom:0}.focus-visible\:\[outline\:2px_solid\]:focus-visible{outline:2px solid}.focus-visible\:\[outline-offset\:2px\]:focus-visible{outline-offset:2px}@media (hover:hover){.enabled\:hover\:border-\(--aai-btn-bd-hover\):enabled:hover{border-color:var(--aai-btn-bd-hover)}.enabled\:hover\:bg-\(--aai-btn-bg-hover\):enabled:hover{background-color:var(--aai-btn-bg-hover)}.enabled\:hover\:text-\(--aai-btn-fg-hover\):enabled:hover{color:var(--aai-btn-fg-hover)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=40rem){.sm\:ml-auto{margin-left:auto}.sm\:max-w-\[60\%\]{max-width:60%}.sm\:basis-auto{flex-basis:auto}.sm\:px-16{padding-inline:calc(var(--spacing) * 16)}.sm\:py-14{padding-block:calc(var(--spacing) * 14)}}@media (width>=48rem){.md\:order-none{order:0}.md\:h-screen{height:100vh}.md\:max-h-none{max-height:none}.md\:w-\(--aai-sidebar-w\){width:var(--aai-sidebar-w)}.md\:flex-row{flex-direction:row}.md\:border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.md\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.md\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.md\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}}}@keyframes aai-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.82)}}@keyframes aai-bounce{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}@keyframes aai-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.tool-shimmer{-webkit-text-fill-color:transparent;background:linear-gradient(90deg,currentColor 25%,#0000 50%,currentColor 75%) 0 0/200% 100%;-webkit-background-clip:text;background-clip:text;animation:2s infinite aai-shimmer}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
<title>aai</title>
|
|
7
7
|
<link rel="icon" href="./favicon.ico" />
|
|
8
8
|
<style>html, body { background: #FBF8F2; margin: 0; }</style>
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-DXODx_9r.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/client-audio-constants-Ck0IJO4c.js">
|
|
11
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
11
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DTLrhtTF.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<main id="app"></main>
|