@lotics/app-sdk 0.100.0 → 0.101.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/AGENTS.md +32 -47
- package/dist/agent_stream.d.ts +131 -0
- package/dist/ask_ai.d.ts +27 -0
- package/dist/attachments.d.ts +58 -0
- package/dist/chunk-ARV5FAU5.js +1132 -0
- package/dist/comments.d.ts +89 -0
- package/dist/error_report.d.ts +9 -0
- package/dist/folder_pick.d.ts +8 -0
- package/dist/geolocation.d.ts +42 -0
- package/dist/hooks.d.ts +251 -0
- package/dist/{src/index.d.ts → index.d.ts} +13 -22
- package/dist/index.js +31309 -0
- package/dist/index.js.LEGAL.txt +11 -0
- package/dist/members.d.ts +32 -0
- package/dist/mock.d.ts +37 -0
- package/dist/mount.d.ts +19 -0
- package/dist/new_record.d.ts +37 -0
- package/dist/open_app.d.ts +12 -0
- package/dist/open_external.d.ts +10 -0
- package/dist/overlay.d.ts +25 -0
- package/dist/queries.d.ts +231 -0
- package/dist/recording.d.ts +47 -0
- package/dist/recording_state.d.ts +43 -0
- package/dist/rename_file.d.ts +13 -0
- package/dist/router.d.ts +10 -0
- package/dist/router.js +97 -0
- package/dist/row.d.ts +87 -0
- package/dist/rpc.d.ts +114 -0
- package/dist/select.d.ts +24 -0
- package/dist/shared_types.d.ts +8 -0
- package/dist/store.d.ts +43 -0
- package/dist/types.d.ts +36 -0
- package/dist/upload/optimize.d.ts +30 -0
- package/dist/upload/pipeline.d.ts +36 -0
- package/dist/upload/transport.d.ts +19 -0
- package/dist/url_params.d.ts +55 -0
- package/dist/use_recents.d.ts +15 -0
- package/dist/{src/use_url_state.d.ts → use_url_state.d.ts} +0 -2
- package/dist/viewer.d.ts +41 -0
- package/dist/written.d.ts +77 -0
- package/docs/ai.md +74 -133
- package/docs/data_fetching.md +209 -290
- package/docs/files.md +61 -51
- package/docs/members_and_options.md +93 -63
- package/docs/mutations.md +135 -205
- package/docs/navigation_and_state.md +26 -35
- package/docs/queries.md +144 -207
- package/docs/recipes.md +21 -45
- package/docs/runtime.md +74 -137
- package/docs/security.md +8 -11
- package/docs/workflows.md +189 -174
- package/package.json +27 -28
- package/dist/src/agent_stream.d.ts +0 -200
- package/dist/src/agent_stream.js +0 -314
- package/dist/src/ask_ai.d.ts +0 -40
- package/dist/src/ask_ai.js +0 -35
- package/dist/src/attachments.d.ts +0 -68
- package/dist/src/attachments.js +0 -93
- package/dist/src/comments.d.ts +0 -127
- package/dist/src/comments.js +0 -192
- package/dist/src/download.js +0 -54
- package/dist/src/geolocation.d.ts +0 -64
- package/dist/src/geolocation.js +0 -96
- package/dist/src/hooks.d.ts +0 -781
- package/dist/src/hooks.js +0 -860
- package/dist/src/index.js +0 -34
- package/dist/src/members.d.ts +0 -105
- package/dist/src/members.js +0 -62
- package/dist/src/mock.d.ts +0 -118
- package/dist/src/mock.js +0 -124
- package/dist/src/mount.d.ts +0 -47
- package/dist/src/mount.js +0 -34
- package/dist/src/new_record.d.ts +0 -74
- package/dist/src/new_record.js +0 -117
- package/dist/src/open_app.d.ts +0 -15
- package/dist/src/open_app.js +0 -18
- package/dist/src/open_external.d.ts +0 -16
- package/dist/src/open_external.js +0 -19
- package/dist/src/recording.d.ts +0 -59
- package/dist/src/recording.js +0 -30
- package/dist/src/recording_state.d.ts +0 -59
- package/dist/src/recording_state.js +0 -94
- package/dist/src/router.d.ts +0 -17
- package/dist/src/router.js +0 -144
- package/dist/src/row.d.ts +0 -159
- package/dist/src/row.js +0 -254
- package/dist/src/rpc.d.ts +0 -207
- package/dist/src/rpc.js +0 -904
- package/dist/src/select.d.ts +0 -34
- package/dist/src/select.js +0 -40
- package/dist/src/types.d.ts +0 -115
- package/dist/src/types.js +0 -1
- package/dist/src/upload/optimize.d.ts +0 -54
- package/dist/src/upload/optimize.js +0 -207
- package/dist/src/upload/pipeline.d.ts +0 -55
- package/dist/src/upload/pipeline.js +0 -52
- package/dist/src/upload/transport.d.ts +0 -42
- package/dist/src/upload/transport.js +0 -128
- package/dist/src/url_params.d.ts +0 -93
- package/dist/src/url_params.js +0 -215
- package/dist/src/use_optimistic.d.ts +0 -27
- package/dist/src/use_optimistic.js +0 -27
- package/dist/src/use_recents.d.ts +0 -19
- package/dist/src/use_recents.js +0 -71
- package/dist/src/use_url_state.js +0 -73
- package/dist/src/viewer.d.ts +0 -26
- package/dist/src/viewer.js +0 -47
- /package/dist/{src/download.d.ts → download.d.ts} +0 -0
package/AGENTS.md
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
# @lotics/app-sdk — the
|
|
1
|
+
# @lotics/app-sdk — the custom-app reference index
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
fetches/mutates, `@lotics/ui` draws.
|
|
3
|
+
**A custom-code Lotics app reads and writes through this package.** `@lotics/app-sdk` is the typed
|
|
4
|
+
hooks over the host bridge, the cell readers and `mount()`; `@lotics/app-sdk/router` is
|
|
5
|
+
`AppRouter`. Data and RPC only — no component. What the app draws is its own.
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
**`@lotics/ui` and its engines are not on npm.** The component kit is installed only inside a
|
|
8
|
+
sandbox session's working tree; an app scaffolded on your machine draws with its own components.
|
|
9
|
+
Where a doc pairs an SDK value with a kit component, that pairing applies in a sandbox session.
|
|
10
|
+
|
|
11
|
+
This file is the index. The **exact type** of anything is its shipped declaration,
|
|
12
|
+
`dist/<name>.d.ts` for a hook or reader — **never guess a shape; open the file.**
|
|
12
13
|
|
|
13
14
|
## The area references
|
|
14
15
|
|
|
15
16
|
| Doc | Read it for |
|
|
16
17
|
|---|---|
|
|
17
|
-
| [docs/
|
|
18
|
-
| [docs/queries.md](./docs/queries.md) | **The query engine
|
|
19
|
-
| [docs/
|
|
20
|
-
| [docs/
|
|
21
|
-
| [docs/
|
|
22
|
-
| [docs/files.md](./docs/files.md) | Files end to end — `useFileUpload
|
|
23
|
-
| [docs/members_and_options.md](./docs/members_and_options.md) | People
|
|
24
|
-
| [docs/navigation_and_state.md](./docs/navigation_and_state.md) | `AppRouter` (embedded/standalone URL model), `useUrlState` + `urlParam` codecs, `useRecents`. |
|
|
25
|
-
| [docs/ai.md](./docs/ai.md) | `useAgentRun` (structured vs free-text, streaming
|
|
26
|
-
| [docs/security.md](./docs/security.md) | **Read before shipping** — the owner-principal model, `is_current_member` scoping, write attribution, group gates, public-app bounds,
|
|
27
|
-
| [docs/runtime.md](./docs/runtime.md) | `mount()
|
|
18
|
+
| [docs/data_fetching.md](./docs/data_fetching.md) | The reads: `useQuery(alias, params, opts)` — its rows (`limit`), numbered pages (`page`), a keyset feed (`more`), its `total` or the total alone, with `total: { by }` a count per value of one column — `useQueries` for reads known only at render, `queryAll` outside React; every hook answers one `QueryState`. The ROW type (`RowOf` — the alias's projected columns and nothing else), runtime `sort`/`filter` keys, cell readers (`row.*`, `readSelect`, `readMembers`, `readLinks`, `readFiles`, `readLocked`, `readCreatedAt`/`readUpdatedAt`), the SDK's own cache — **arrival revalidates** — **realtime push**, a write drawn on every read from the press, a count as its own full scan, and the search-as-you-type and record-picker patterns. |
|
|
19
|
+
| [docs/queries.md](./docs/queries.md) | **The query engine reference** — AST node kinds, per-field-type operators, filters/params/pruning, free-text search, combining tables, shaping (aggregates, date buckets, windows), runtime refinement bounds, limits and the efficiency playbook. |
|
|
20
|
+
| [docs/mutations.md](./docs/mutations.md) | `useWorkflow` (the ONLY write path; `useWorkflows` for writes that are data), the `WorkflowResult` resolve-never-throw contract (`field_errors`), typed inputs, every write drawn on every read from the press — predicted from the workflow's own steps, taken back on a refusal, `pending` meanwhile — the re-read a successful write triggers over the tables its body names, diff-before-update, locked records, `useNewRecord`, read-after-write ordering (`writesSettled()`), `useRecording`. |
|
|
21
|
+
| [docs/workflows.md](./docs/workflows.md) | **The workflow-BODY reference** — the JS subset a body may use, opaque `fld_*`/`opt_*` keys, every step form, the accepted sugar, helpers, record-write surfaces, the traps and the verify loop. |
|
|
22
|
+
| [docs/recipes.md](./docs/recipes.md) | Task-shaped how-tos — returning a generated file, returning structured data, parameterized lookups, composable optional filters, cell decoding, testing an AI action without spending credits. |
|
|
23
|
+
| [docs/files.md](./docs/files.md) | Files end to end — `useFileUpload` and its `fidelity`, `renameFile` (a new file over the same bytes), `useAttachments`/`useAttachmentPiles`, `readFiles` and presigned URLs (a bearer credential — never logged or persisted), workflow-generated files, naming a zip's entries, the delivery bounds. |
|
|
24
|
+
| [docs/members_and_options.md](./docs/members_and_options.md) | People, select options and comments — `useMembers`, `useFieldOptions`, `useViewer`, `useWorkspaceTimezone`/`useWorkspaceCurrency`, `useAppContext`, the workspace's zone at the root, `useComments`. |
|
|
25
|
+
| [docs/navigation_and_state.md](./docs/navigation_and_state.md) | `AppRouter` (embedded/standalone URL model), `useUrlState` + `urlParam` codecs, `useRecents`, `useFolderPick`. |
|
|
26
|
+
| [docs/ai.md](./docs/ai.md) | `useAgentRun` (structured vs free-text, streaming parts, the agent's ask-back), `askAi`, `useAiContext`, and what the member's own chat agent can do with the app while it is open. |
|
|
27
|
+
| [docs/security.md](./docs/security.md) | **Read before shipping** — the owner-principal model, `is_current_member` scoping, write attribution, group gates, public-app bounds, why a per-input bound is a tenancy floor rather than an authorization check. |
|
|
28
|
+
| [docs/runtime.md](./docs/runtime.md) | `mount()` and the errors it reports to the host (`reportAppError`), the two transports, the API address a standalone bundle reads out of its own page (`<meta name="lotics-api-base">`), `rpc()`, the mock harness (`fixture` + `?__mock=1`), `openExternal`/`openApp`/`downloadFile`, geofencing, the peer dependencies. |
|
|
28
29
|
|
|
29
30
|
## Non-negotiables (each detailed in its doc)
|
|
30
31
|
|
|
@@ -34,33 +35,17 @@ signature; open the file.**
|
|
|
34
35
|
A client-supplied member id is an IDOR. → [security](./docs/security.md)
|
|
35
36
|
- **Server data is never copied into `useState`** — hooks are the source of truth; derive with
|
|
36
37
|
`useMemo`. → [data_fetching](./docs/data_fetching.md)
|
|
37
|
-
- **A
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
→ [mutations](./docs/mutations.md)
|
|
43
|
-
- **`project` only what you render; filter server-side.**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- **Read only the columns the alias projects** — its option sets too, from the alias that CARRIES
|
|
48
|
-
the column. Anything else is `undefined`, which every reader draws as a blank cell, so the row
|
|
49
|
-
type and the option map are bounded to the projection. → [data_fetching](./docs/data_fetching.md)
|
|
50
|
-
- **Narrow `__source_record_id` / `__source_table_id` before use** — a grouped query emits neither,
|
|
51
|
-
so an unchecked read hands a workflow (or an AI record ref) `undefined`.
|
|
38
|
+
- **A write shows from the press, and the SDK does it, not the screen.** `useWorkflow` draws what
|
|
39
|
+
the workflow's own steps will write on every read before the server answers, takes it back on a
|
|
40
|
+
refusal, and re-reads the queries over the tables its body names on a success — so no screen
|
|
41
|
+
patches rows or calls `refetch()` after a write. → [mutations](./docs/mutations.md)
|
|
42
|
+
- **Update writes are diffs** — send only changed fields; an optional input clears with `null`
|
|
43
|
+
(never `""`). → [mutations](./docs/mutations.md)
|
|
44
|
+
- **`project` only what you render; filter server-side.** → [queries](./docs/queries.md)
|
|
45
|
+
- **Never hand-roll the serialization contract** — decode cells with the typed readers, and read
|
|
46
|
+
only the columns the alias projects. → [data_fetching](./docs/data_fetching.md)
|
|
47
|
+
- **Narrow `__source_record_id` / `__source_table_id` before use** — a grouped query emits neither.
|
|
52
48
|
→ [data_fetching](./docs/data_fetching.md)
|
|
53
49
|
- **A standalone app takes its API address from the page it was served in**, never from a
|
|
54
|
-
constant
|
|
55
|
-
none refuses instead of addressing someone else's instance. Nothing for an app to configure;
|
|
56
|
-
build against 0.90.2 or later. → [runtime](./docs/runtime.md)
|
|
50
|
+
constant. → [runtime](./docs/runtime.md)
|
|
57
51
|
- **Errors fail loud** — no swallowed catches, no silent fallbacks.
|
|
58
|
-
|
|
59
|
-
## Keeping this reference current
|
|
60
|
-
|
|
61
|
-
These docs are the published contract — agents build apps from `node_modules` and cannot read the
|
|
62
|
-
platform source, so a wrong or missing claim here becomes their bug. **Codify every new hook,
|
|
63
|
-
reader, pattern, or contract change into its OWNING area doc + the index line above in the same
|
|
64
|
-
change that adds it, and bump the package version** (publish CI fires on a version diff; `files`
|
|
65
|
-
ships only on publish). Each fact lives in exactly one doc — link, never duplicate. The
|
|
66
|
-
platform-internal model/IAM rationale stays in the repo's `docs/apps.md`.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folds the AI-SDK UI-message SSE stream into the `UIMessagePart[]` shape
|
|
3
|
+
* `@lotics/ui` `AgentRun` renders. `ai` is imported for types only, so no `ai`
|
|
4
|
+
* runtime enters the app bundle; unknown chunk types are ignored. A structured
|
|
5
|
+
* agent's `submit_result` input becomes `output`, never a part.
|
|
6
|
+
*/
|
|
7
|
+
import type { UIMessagePart, UIDataTypes, UITools } from "ai";
|
|
8
|
+
/** An ai-sdk message part — the render model, tool-set-agnostic. */
|
|
9
|
+
export type AgentUIPart = UIMessagePart<UIDataTypes, UITools>;
|
|
10
|
+
/** Mirrors the server's `INTERACTIVE_APP_TOOLS`; a call parks the run as `awaiting_input`. */
|
|
11
|
+
export declare const INTERACTIVE_TOOLS: ReadonlySet<string>;
|
|
12
|
+
export interface AgentRunState {
|
|
13
|
+
status: "streaming" | "awaiting_input" | "completed" | "error";
|
|
14
|
+
parts: AgentUIPart[];
|
|
15
|
+
/** `submit_result`'s input, never the free text — a consumer reading `output.<field>` would crash on a string. */
|
|
16
|
+
output?: unknown;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SettledAgentRun {
|
|
20
|
+
status: string;
|
|
21
|
+
output?: unknown;
|
|
22
|
+
error_message?: string | null;
|
|
23
|
+
/** On an `awaiting_input` row: rebuilds the ask for a client that lost the stream. */
|
|
24
|
+
pending_interactive?: {
|
|
25
|
+
tool_call_id: string;
|
|
26
|
+
tool_name: string;
|
|
27
|
+
input: unknown;
|
|
28
|
+
} | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fold a polled row into the stream's state, for a dropped or truncated stream.
|
|
32
|
+
* The row owns status and structured output; a free-text row's string output
|
|
33
|
+
* never enters `state.output`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function adoptSettledRun(state: AgentRunState, settled: SettledAgentRun): AgentRunState;
|
|
36
|
+
export type ChoiceOption = {
|
|
37
|
+
label: string;
|
|
38
|
+
description: string;
|
|
39
|
+
};
|
|
40
|
+
export type ChoiceQuestion = {
|
|
41
|
+
question: string;
|
|
42
|
+
options: ChoiceOption[];
|
|
43
|
+
allow_custom?: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type AskUserChoiceAnswer = {
|
|
46
|
+
type: "option";
|
|
47
|
+
question_index: number;
|
|
48
|
+
question_number: number;
|
|
49
|
+
question_text: string;
|
|
50
|
+
option_index: number;
|
|
51
|
+
option_letter: string;
|
|
52
|
+
option_label: string;
|
|
53
|
+
option_description: string;
|
|
54
|
+
} | {
|
|
55
|
+
type: "custom";
|
|
56
|
+
question_index: number;
|
|
57
|
+
question_number: number;
|
|
58
|
+
question_text: string;
|
|
59
|
+
text: string;
|
|
60
|
+
} | {
|
|
61
|
+
type: "skipped";
|
|
62
|
+
question_index: number;
|
|
63
|
+
question_number: number;
|
|
64
|
+
question_text: string;
|
|
65
|
+
};
|
|
66
|
+
export type AskUserChoiceOutput = {
|
|
67
|
+
answers: AskUserChoiceAnswer[];
|
|
68
|
+
skipped_by_user?: boolean;
|
|
69
|
+
};
|
|
70
|
+
export interface PendingChoice {
|
|
71
|
+
toolCallId: string;
|
|
72
|
+
questions: ChoiceQuestion[];
|
|
73
|
+
}
|
|
74
|
+
/** The pending `ask_user_choice`, non-null exactly while parked. */
|
|
75
|
+
export declare function pendingInteractiveCall(state: AgentRunState): PendingChoice | null;
|
|
76
|
+
/** `answers` align to `questions` by index (`ClarifyWizard`'s contract); a missing or empty one is skipped. */
|
|
77
|
+
export declare function buildChoiceOutput(questions: ChoiceQuestion[], answers: {
|
|
78
|
+
value: string;
|
|
79
|
+
custom: boolean;
|
|
80
|
+
}[]): AskUserChoiceOutput;
|
|
81
|
+
/** Settle the answered part and resume `streaming` for the continuation. */
|
|
82
|
+
export declare function applyInteractiveAnswer(state: AgentRunState, toolCallId: string, output: AskUserChoiceOutput): AgentRunState;
|
|
83
|
+
export declare function initialAgentRunState(): AgentRunState;
|
|
84
|
+
interface Chunk {
|
|
85
|
+
type?: string;
|
|
86
|
+
delta?: string;
|
|
87
|
+
/** `tool-input-delta` argument text, not prose. */
|
|
88
|
+
inputTextDelta?: string;
|
|
89
|
+
toolName?: string;
|
|
90
|
+
toolCallId?: string;
|
|
91
|
+
input?: unknown;
|
|
92
|
+
output?: unknown;
|
|
93
|
+
errorText?: string;
|
|
94
|
+
finishReason?: string;
|
|
95
|
+
}
|
|
96
|
+
export declare function reduceAgentChunk(state: AgentRunState, chunk: Chunk): AgentRunState;
|
|
97
|
+
/** Complete chunks so far and the partial frame to carry forward; `[DONE]` is dropped. */
|
|
98
|
+
export declare function parseSseChunks(buffer: string): {
|
|
99
|
+
chunks: Chunk[];
|
|
100
|
+
rest: string;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* How one run leg ended, discriminated so a caller never races the hook's
|
|
104
|
+
* uncommitted state. A run failure is data (`failed`); only API misuse and a
|
|
105
|
+
* refused answer (the run stays parked) reject.
|
|
106
|
+
*/
|
|
107
|
+
export type AgentRunLanding<TOutput> =
|
|
108
|
+
/** `output` is absent for a free-text agent, whose result is `text`. */
|
|
109
|
+
{
|
|
110
|
+
kind: "settled";
|
|
111
|
+
output?: TOutput;
|
|
112
|
+
text: string;
|
|
113
|
+
}
|
|
114
|
+
/** `pendingChoice` carries the question. */
|
|
115
|
+
| {
|
|
116
|
+
kind: "parked";
|
|
117
|
+
}
|
|
118
|
+
/** The error is user-facing. */
|
|
119
|
+
| {
|
|
120
|
+
kind: "failed";
|
|
121
|
+
error: string;
|
|
122
|
+
}
|
|
123
|
+
/** The client stopped listening; the run continues server-side — never a failure. */
|
|
124
|
+
| {
|
|
125
|
+
kind: "aborted";
|
|
126
|
+
};
|
|
127
|
+
export declare const ABORTED: AgentRunLanding<never>;
|
|
128
|
+
/** A free-text agent's result. */
|
|
129
|
+
export declare function proseOf(parts: readonly AgentUIPart[]): string;
|
|
130
|
+
export declare function landingOf(state: AgentRunState): AgentRunLanding<unknown>;
|
|
131
|
+
export {};
|
package/dist/ask_ai.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface AskAiArgs {
|
|
2
|
+
/** Prefilled only; nothing runs until the user sends. */
|
|
3
|
+
prompt?: string;
|
|
4
|
+
/** From `readFiles(cell)`; previewed beside the chat. */
|
|
5
|
+
file_ids?: string[];
|
|
6
|
+
/** The agent acts on them under the signed-in user's authority. */
|
|
7
|
+
record_ids?: string[];
|
|
8
|
+
/** Free-text grounding; the host adds the app's identity. */
|
|
9
|
+
context?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Open a fresh chat seeded with files, records and a prompt the user sends
|
|
13
|
+
* themselves. For judgment that commits back into the app, use `useAgentRun`
|
|
14
|
+
* — `askAi`'s outcome lands in chat.
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { askAi } from "@lotics/app-sdk";
|
|
18
|
+
* await askAi({
|
|
19
|
+
* file_ids: [file.id],
|
|
20
|
+
* record_ids: [row.id],
|
|
21
|
+
* prompt: "Update the header of this invoice to match our letterhead.",
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Rejects standalone.
|
|
26
|
+
*/
|
|
27
|
+
export declare function askAi(args: AskAiArgs): Promise<void>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ImageFidelity } from "./upload/optimize.js";
|
|
2
|
+
export interface AttachedFile {
|
|
3
|
+
/** Local; the React key and `remove(id)` handle. */
|
|
4
|
+
id: string;
|
|
5
|
+
filename: string;
|
|
6
|
+
mime_type: string;
|
|
7
|
+
/** A local object URL, available before upload. */
|
|
8
|
+
preview_url: string;
|
|
9
|
+
status: "uploading" | "ready" | "error";
|
|
10
|
+
/** Set once `ready`. */
|
|
11
|
+
file_id?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AttachmentsOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The stored ids the destination now holds; matching entries leave the queue
|
|
16
|
+
* with no gap on screen. Omitted, the queue accumulates until `clear`.
|
|
17
|
+
*/
|
|
18
|
+
landed?: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
export interface AttachmentsState {
|
|
21
|
+
/** Shared by every untouched pile, so never written through. */
|
|
22
|
+
files: readonly AttachedFile[];
|
|
23
|
+
/** Previews at once, uploads in the background; picking is the app's (`pickFiles`, paste, drop). */
|
|
24
|
+
add: (files: File[], options?: {
|
|
25
|
+
fidelity?: ImageFidelity;
|
|
26
|
+
}) => void;
|
|
27
|
+
/**
|
|
28
|
+
* `add`, resolving with every stored id in order — what a write waits on.
|
|
29
|
+
* Rejects with the first refusal; each entry keeps its own status.
|
|
30
|
+
*/
|
|
31
|
+
attach: (files: File[], options?: {
|
|
32
|
+
fidelity?: ImageFidelity;
|
|
33
|
+
}) => Promise<string[]>;
|
|
34
|
+
remove: (id: string) => void;
|
|
35
|
+
clear: () => void;
|
|
36
|
+
/** Gate Send on it. */
|
|
37
|
+
uploading: boolean;
|
|
38
|
+
fileIds: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface AttachmentPilesOptions {
|
|
41
|
+
/** {@link AttachmentsOptions.landed} by pile; a pile it omits accumulates until cleared. */
|
|
42
|
+
landed?: Readonly<Record<string, readonly string[]>>;
|
|
43
|
+
}
|
|
44
|
+
export interface AttachmentPiles {
|
|
45
|
+
/** The pile's queue, empty until something is added to it; its verbs are stable per pile. */
|
|
46
|
+
of: (pile: string) => AttachmentsState;
|
|
47
|
+
/** Every pile's queue at once. */
|
|
48
|
+
clearAll: () => void;
|
|
49
|
+
}
|
|
50
|
+
type Upload = (file: File, options?: {
|
|
51
|
+
fidelity?: ImageFidelity;
|
|
52
|
+
}) => Promise<{
|
|
53
|
+
id: string;
|
|
54
|
+
}>;
|
|
55
|
+
/** One queue per pile in one hook, so a caller holding a list of piles never calls a hook in a loop. */
|
|
56
|
+
export declare function useAttachmentPileQueues(upload: Upload, options?: AttachmentPilesOptions): AttachmentPiles;
|
|
57
|
+
export declare function useAttachmentQueue(upload: Upload, options?: AttachmentsOptions): AttachmentsState;
|
|
58
|
+
export {};
|