@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/dist/row.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, never-throwing decoders of `useQuery` cells: a select is a
|
|
3
|
+
* `{ key, label }[]`, a date/datetime a timezone-less `YYYY-MM-DD[THH:mm…]`
|
|
4
|
+
* wall-clock string, a number or boolean itself.
|
|
5
|
+
*/
|
|
6
|
+
/** The column a predicted row carries, so no surface opens a row the server has not answered for. */
|
|
7
|
+
export declare const PENDING = "__pending";
|
|
8
|
+
/** Select → first option key; `readSelect` for every option. */
|
|
9
|
+
declare function opt(v: unknown): string | null;
|
|
10
|
+
/** Numbers stringified; anything else non-string is "". */
|
|
11
|
+
declare function text(v: unknown): string;
|
|
12
|
+
/** `null` for an empty or non-finite cell — empty is not 0; write `?? 0` where it is. */
|
|
13
|
+
declare function num(v: unknown): number | null;
|
|
14
|
+
/**
|
|
15
|
+
* `null` for an unanswered cell, which is not a "no". Write `=== true` where
|
|
16
|
+
* only yes acts, `?? false` where false is the safe reading.
|
|
17
|
+
*/
|
|
18
|
+
declare function bool(v: unknown): boolean | null;
|
|
19
|
+
/**
|
|
20
|
+
* The stored day at local midnight, so placement never shifts across zones. A
|
|
21
|
+
* reduced-precision value ("2026-05") decodes to its period start.
|
|
22
|
+
*/
|
|
23
|
+
declare function date(v: unknown): Date | null;
|
|
24
|
+
/**
|
|
25
|
+
* A local Date keeping the stored wall-clock time verbatim, with no UTC
|
|
26
|
+
* conversion; a missing month/day is 1 and a missing time midnight.
|
|
27
|
+
*/
|
|
28
|
+
declare function datetime(v: unknown): Date | null;
|
|
29
|
+
export interface ResolvedLink {
|
|
30
|
+
/** A `rec_…` id, to correlate or filter. */
|
|
31
|
+
id: string;
|
|
32
|
+
/** The primary-field value, to render. */
|
|
33
|
+
display: string;
|
|
34
|
+
}
|
|
35
|
+
/** The first linked record, or null; `readLinks` for all. */
|
|
36
|
+
declare function link(v: unknown): ResolvedLink | null;
|
|
37
|
+
/**
|
|
38
|
+
* Every linked record. A lookup of a link arrives one level deeper (one link
|
|
39
|
+
* cell per linked row); it is flattened here, in order, each id once.
|
|
40
|
+
*/
|
|
41
|
+
export declare function readLinks(v: unknown): ResolvedLink[];
|
|
42
|
+
/** A files cell entry; `url`/`thumbnail_url` are presigned (24h) and load from the sandboxed frame. */
|
|
43
|
+
export interface AppFile {
|
|
44
|
+
id: string;
|
|
45
|
+
filename: string;
|
|
46
|
+
mime_type: string;
|
|
47
|
+
url: string;
|
|
48
|
+
thumbnail_url?: string;
|
|
49
|
+
/** Bytes; absent on older files — sort by the raw number, format at display. */
|
|
50
|
+
size?: number | null;
|
|
51
|
+
/** ISO upload timestamp. */
|
|
52
|
+
created_at?: string;
|
|
53
|
+
/** The document template the file was generated from (`dtl_…`); absent on a file a person brought. */
|
|
54
|
+
document_template_id?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The presigned files, skipping any without a `url`; `toDisplayFile`
|
|
58
|
+
* (`@lotics/ui/file_thumbnail`) converts one for the kit. A lookup arrives one
|
|
59
|
+
* level deeper, flattened as in {@link readLinks}.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readFiles(v: unknown): AppFile[];
|
|
62
|
+
/**
|
|
63
|
+
* Whether the row's record is locked (`__source_locked`), so edits must go
|
|
64
|
+
* through `request_locked_field_change`. Pass the whole row; absent is unlocked.
|
|
65
|
+
*/
|
|
66
|
+
export declare function readLocked(rowValue: unknown): boolean;
|
|
67
|
+
/** `__created_at` of the row's record; null on a grouped row. Pass the whole row. */
|
|
68
|
+
export declare function readCreatedAt(rowValue: unknown): Date | null;
|
|
69
|
+
/** `__updated_at`, as {@link readCreatedAt}. */
|
|
70
|
+
export declare function readUpdatedAt(rowValue: unknown): Date | null;
|
|
71
|
+
export declare const row: {
|
|
72
|
+
opt: typeof opt;
|
|
73
|
+
text: typeof text;
|
|
74
|
+
num: typeof num;
|
|
75
|
+
bool: typeof bool;
|
|
76
|
+
date: typeof date;
|
|
77
|
+
datetime: typeof datetime;
|
|
78
|
+
link: typeof link;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Rows counted per value of one column — what the query RPC's `count_by`
|
|
82
|
+
* answers, over rows already in hand. A cell holding several values (a
|
|
83
|
+
* multi-select) is counted under each, a cell holding none under nothing: the
|
|
84
|
+
* same rows a `has_any_of` on each value keeps.
|
|
85
|
+
*/
|
|
86
|
+
export declare function countsOf(rows: ReadonlyArray<Record<string, unknown>>, by: string): Record<string, number>;
|
|
87
|
+
export {};
|
package/dist/rpc.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { AskUserChoiceOutput } from "./agent_stream.js";
|
|
2
|
+
import { type UrlParams, type UrlParamsPatch } from "./url_params.js";
|
|
3
|
+
/**
|
|
4
|
+
* The app's RPC bridge. Bridged (`?lotics_host=` present): ops go over
|
|
5
|
+
* postMessage and the host, holding the member's session, calls the API.
|
|
6
|
+
* Standalone: the public `/v1/apps/{id}/*` endpoints are called directly, with
|
|
7
|
+
* no credentials. The bridged wire must match `app_iframe_host.tsx`:
|
|
8
|
+
* app → host: { id, op, payload }
|
|
9
|
+
* host → app: { id, type: "result", data } | { id, type: "error", message }
|
|
10
|
+
*/
|
|
11
|
+
export type RpcOp = "query" | "field_options" | "workflow" | "agentRuns" | "agentRun.get" | "agentRun.cancel" | "upload" | "file.rename" | "members" | "context" | "write_model" | "prediction_miss" | "openExternal" | "openApp" | "askAi" | "urlState.get" | "urlState.set" | "folder.get" | "folder.set" | "comments.list" | "comments.create" | "comments.update" | "comments.delete" | "comments.counts" | "recording.start" | "recording.stop";
|
|
12
|
+
export interface AgentRunPayload {
|
|
13
|
+
alias: string;
|
|
14
|
+
session_id: string;
|
|
15
|
+
input: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface AgentRunHandle {
|
|
18
|
+
done: Promise<void>;
|
|
19
|
+
abort: () => void;
|
|
20
|
+
}
|
|
21
|
+
/** Passed through unresolved; the member's chat agent acts on it only under their IAM. */
|
|
22
|
+
export interface AiContextRecordRef {
|
|
23
|
+
table_id: string;
|
|
24
|
+
record_id: string;
|
|
25
|
+
}
|
|
26
|
+
/** What the app rendered on the current screen, pushed to the member's chat agent. */
|
|
27
|
+
export interface AiContextValue {
|
|
28
|
+
/** Enters the agent prompt as data. Host-capped to 1000 chars. */
|
|
29
|
+
description: string;
|
|
30
|
+
/** Host-capped to 20. */
|
|
31
|
+
records?: AiContextRecordRef[];
|
|
32
|
+
/** Dropped past the host's size cap, keeping the description. */
|
|
33
|
+
data?: unknown;
|
|
34
|
+
}
|
|
35
|
+
/** An error the app did not handle; `reportAppError` builds it. */
|
|
36
|
+
export interface AppErrorReport {
|
|
37
|
+
type: "report_error";
|
|
38
|
+
kind: "uncaught" | "rejection" | "spec";
|
|
39
|
+
/** `spec` when the page carries a JSON app's inlined spec, so the hosted runtime drew it. */
|
|
40
|
+
served: "spec" | "bundle";
|
|
41
|
+
/** The error's class, or the `typeof` of a non-Error throw. */
|
|
42
|
+
name: string;
|
|
43
|
+
message: string;
|
|
44
|
+
/** The first frame, with no origin, query or fragment. */
|
|
45
|
+
stack_top: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** One-way, app → host: no id, no reply. */
|
|
48
|
+
export type HostNotification = {
|
|
49
|
+
type: "aiContext";
|
|
50
|
+
slot: string;
|
|
51
|
+
context: AiContextValue | null;
|
|
52
|
+
} | AppErrorReport;
|
|
53
|
+
/** The app's identity: the host's context when bridged, `/by-subdomain` (no member) standalone. */
|
|
54
|
+
export interface AppContext {
|
|
55
|
+
member_id: string | null;
|
|
56
|
+
/** The app declared `comments`; `useComments` also needs a signed-in member. */
|
|
57
|
+
comments_enabled: boolean;
|
|
58
|
+
/** The IANA zone every instant is dated in; absent from an older host, which
|
|
59
|
+
* reads in the viewer's zone. */
|
|
60
|
+
timezone?: string;
|
|
61
|
+
/** The ISO 4217 code uncoded money is counted in; absent from an older host,
|
|
62
|
+
* which refuses such money rather than guess a currency. */
|
|
63
|
+
default_currency?: string;
|
|
64
|
+
/** True only from a host with `recording.*`, for a signed-in member, on an
|
|
65
|
+
* instance that transcribes; absent reads as false. */
|
|
66
|
+
recording_enabled?: boolean;
|
|
67
|
+
/** This app's recordings the host still tracks, by alias. */
|
|
68
|
+
recordings?: Record<string, unknown>;
|
|
69
|
+
}
|
|
70
|
+
/** Whether a Lotics host embeds the app, rather than it standing alone on its own origin. */
|
|
71
|
+
export declare function isEmbedded(): boolean;
|
|
72
|
+
export declare function rpc<T = unknown>(op: RpcOp, payload: unknown): Promise<T>;
|
|
73
|
+
export declare function getUrlParams(): Promise<UrlParams>;
|
|
74
|
+
/** A key set to `undefined` is cleared; every other param is kept, and no history entry added. */
|
|
75
|
+
export declare function setUrlParams(patch: UrlParamsPatch): Promise<void>;
|
|
76
|
+
/** Synchronous first-paint snapshot; `{}` when embedded, which hydrates on mount. */
|
|
77
|
+
export declare function peekUrlParams(): UrlParams;
|
|
78
|
+
/** Back/forward and edited URLs: the host's `url-state` embedded, `popstate` standalone. */
|
|
79
|
+
export declare function subscribeUrlParams(cb: (params: UrlParams) => void): () => void;
|
|
80
|
+
/** No-ops standalone. */
|
|
81
|
+
export declare function postHostNotification(message: HostNotification): void;
|
|
82
|
+
/**
|
|
83
|
+
* The host's `queriesChanged` push, naming the aliases whose tables moved. The
|
|
84
|
+
* host owns the realtime socket because the frame holds no credentials; inert
|
|
85
|
+
* standalone.
|
|
86
|
+
*/
|
|
87
|
+
export declare function subscribeQueriesChanged(cb: (aliases: string[]) => void): () => void;
|
|
88
|
+
export declare function registerQueryAlias(alias: string): () => void;
|
|
89
|
+
/**
|
|
90
|
+
* Re-read after this app's own write — the realtime push is too slow for it.
|
|
91
|
+
* `reads` names the queries the write changed, where the caller knows them;
|
|
92
|
+
* absent, every mounted query, since a hand-written app cannot know which
|
|
93
|
+
* tables a workflow touched.
|
|
94
|
+
*/
|
|
95
|
+
export declare function notifyLocalWrite(reads?: readonly string[]): void;
|
|
96
|
+
/** Hands each raw SSE chunk to `onText`; `done` settles when the stream ends. */
|
|
97
|
+
export declare function rpcAgentRun(payload: AgentRunPayload, onText: (chunk: string) => void, onRunId?: (runId: string) => void): AgentRunHandle;
|
|
98
|
+
export interface AgentRunContinuePayload {
|
|
99
|
+
run_id: string;
|
|
100
|
+
tool_call_id: string;
|
|
101
|
+
output: AskUserChoiceOutput;
|
|
102
|
+
}
|
|
103
|
+
/** Continue a parked run with the answer to its `ask_user_choice`, streamed like `rpcAgentRun`. */
|
|
104
|
+
export declare function rpcAgentRunContinue(payload: AgentRunContinuePayload, onText: (chunk: string) => void): AgentRunHandle;
|
|
105
|
+
/**
|
|
106
|
+
* Not `Authorization`: the token proves the shared link password, not an
|
|
107
|
+
* identity, and the auth middleware would reject it as an unknown bearer
|
|
108
|
+
* before the password gate runs. Mirrored server-side.
|
|
109
|
+
*/
|
|
110
|
+
export declare const APP_PUBLIC_SESSION_HEADER = "x-lotics-app-session";
|
|
111
|
+
/** Mirrored server-side. */
|
|
112
|
+
export declare const APP_AGENT_RUN_TOKEN_HEADER = "x-app-agent-run-token";
|
|
113
|
+
/** A stream refused before its first byte: the body's `message`, never its raw text. */
|
|
114
|
+
export declare function streamStartError(res: Response): Promise<Error>;
|
package/dist/select.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** The server resolves each `select` cell to `ResolvedOption[]` before the app sees it. */
|
|
2
|
+
export interface ResolvedOption {
|
|
3
|
+
key: string;
|
|
4
|
+
/** The key, for an option deleted after the cell was written. */
|
|
5
|
+
label: string;
|
|
6
|
+
/**
|
|
7
|
+
* A palette token (`"blue"`), from `useFieldOptions` only — a cell carries
|
|
8
|
+
* key and label. `@lotics/ui` `Status` takes the option whole.
|
|
9
|
+
*/
|
|
10
|
+
color?: string;
|
|
11
|
+
/** A brand or icon mark, from `useFieldOptions` only; `Status` draws it in the dot's place. */
|
|
12
|
+
mark?: {
|
|
13
|
+
kind: "brand";
|
|
14
|
+
name: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "icon";
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `[]` for an empty or malformed cell; a bare string (options unresolved
|
|
22
|
+
* server-side) becomes `{ key, label: key }`; malformed entries are dropped.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readSelect(value: unknown): ResolvedOption[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@lotics/shared` types this SDK's declarations name — generated by
|
|
3
|
+
* `scripts/build_sdk.mjs`, because that package is private and ships in no
|
|
4
|
+
* tarball. Written at every build, never edited.
|
|
5
|
+
*/
|
|
6
|
+
export type QueryAggregate = { by?: readonly string[]; day?: string; sum?: string; };
|
|
7
|
+
export type TableField = { key: string; name: string; description: string; type: "number"; format: "number" | "currency" | "percentage"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; currency?: string | null | undefined; unit?: string | null | undefined; unit_field?: string | null | undefined; currency_field?: string | null | undefined; default_value?: number | null | undefined; } | { key: string; name: string; description: string; type: "text"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; unique?: boolean | undefined; format?: "text" | "link" | "markdown" | undefined; default_value?: string | null | undefined; } | { key: string; name: string; description: string; type: "date"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; format?: "date" | "datetime" | "date_range" | "datetime_range" | undefined; timezone?: string | undefined; derive_from?: "created_at" | "updated_at" | undefined; default_value?: string | null | undefined; } | { key: string; name: string; description: string; type: "boolean"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; default_value?: boolean | null | undefined; } | { key: string; name: string; description: string; type: "select"; options: { key: string; name: string; color: "red" | "orange" | "amber" | "yellow" | "lime" | "green" | "emerald" | "teal" | "cyan" | "sky" | "blue" | "indigo" | "violet" | "purple" | "fuchsia" | "pink" | "rose" | "slate" | "gray" | "zinc" | "neutral" | "stone"; mark?: { kind: string; name: string; } | undefined; }[]; confirm_before_update?: boolean | undefined; required?: boolean | undefined; multi?: boolean | undefined; default_value?: string[] | null | undefined; } | { key: string; name: string; description: string; type: "select_member"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; multi?: boolean | undefined; default_value?: string[] | null | undefined; } | { key: string; name: string; description: string; type: "select_record_link"; table_id: string; display_field_keys: string[]; confirm_before_update?: boolean | undefined; required?: boolean | undefined; display_field_widths?: Record<string, number> | undefined; paired_field_key?: string | undefined; cardinality?: "one" | "many" | undefined; } | { key: string; name: string; description: string; type: "rollup"; source_field_key: string; aggregate_option: { operation: "count"; field_key?: string | undefined; } | { operation: "unique" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique"; field_key: string; } | { operation: "min" | "unique" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique" | "sum" | "avg" | "median" | "max" | "range"; field_key: string; } | { operation: "unique" | "date_range" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique" | "earliest" | "latest"; field_key: string; } | { operation: "unique" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique" | "selected"; field_key: string; } | { operation: "unique" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique" | "selected"; field_key: string; } | { operation: "empty" | "filled" | "percent_empty" | "percent_filled" | "selected"; field_key: string; } | { operation: "checked" | "unchecked" | "percent_checked" | "percent_unchecked"; field_key: string; } | { operation: "empty" | "filled" | "percent_empty" | "percent_filled" | "selected"; field_key: string; } | { operation: "min" | "unique" | "date_range" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique" | "sum" | "avg" | "median" | "max" | "range" | "earliest" | "latest" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked"; field_key: string; } | { operation: "min" | "unique" | "date_range" | "empty" | "filled" | "percent_empty" | "percent_filled" | "percent_unique" | "sum" | "avg" | "median" | "max" | "range" | "earliest" | "latest"; field_key: string; }; confirm_before_update?: boolean | undefined; required?: boolean | undefined; filter?: TableRecordFiltersGroupNode | undefined; aggregate_field_type?: "number" | "boolean" | "text" | "date" | "select" | "select_member" | "select_record_link" | "rollup" | "files" | "formula" | "lookup" | "button" | "autonumber" | undefined; aggregate_field_format?: string | undefined; aggregate_field_currency?: string | undefined; aggregate_field_unit?: string | undefined; aggregate_field_unit_field?: string | undefined; aggregate_field_currency_field?: string | undefined; } | { key: string; name: string; description: string; type: "lookup"; source_field_key: string; lookup_field_key: string; confirm_before_update?: boolean | undefined; required?: boolean | undefined; lookup_field_type?: "number" | "boolean" | "text" | "date" | "select" | "select_member" | "select_record_link" | "rollup" | "files" | "formula" | "lookup" | "button" | "autonumber" | undefined; lookup_field_format?: string | undefined; lookup_field_currency?: string | undefined; lookup_field_unit?: string | undefined; lookup_field_options?: { key: string; name: string; color?: string | undefined; mark?: { kind: string; name: string; } | undefined; }[] | undefined; order_by?: { field_key: string; direction: "asc" | "desc"; } | undefined; } | { key: string; name: string; description: string; type: "files"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; } | { key: string; name: string; description: string; type: "formula"; formula: { expression: string; format?: "number" | "currency" | "percentage" | "link" | undefined; currency?: string | undefined; unit?: string | undefined; unit_field?: string | undefined; currency_field?: string | undefined; output_type?: "number" | "boolean" | "text" | "date" | "datetime" | undefined; volatile?: boolean | undefined; }; confirm_before_update?: boolean | undefined; required?: boolean | undefined; } | { key: string; name: string; description: string; type: "button"; text: string; confirm_before_update?: boolean | undefined; required?: boolean | undefined; workflow_id?: string | null | undefined; } | { key: string; name: string; description: string; type: "autonumber"; confirm_before_update?: boolean | undefined; required?: boolean | undefined; prefix?: string | undefined; padding?: number | undefined; template?: string | undefined; };
|
|
8
|
+
export type TableRecordFilters = TableRecordFiltersConditionNode | TableRecordFiltersTraversalNode | TableRecordFiltersGroupNode;
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** How a key is read: from when the request was sent and the answer it holds now (a feed grows from it). */
|
|
2
|
+
export type Fetcher<T> = (askedAt: number, current: T | undefined) => Promise<T>;
|
|
3
|
+
/** The read clock: every request stamps when it was sent, so an answer is known to carry what settled before it. */
|
|
4
|
+
export declare function tick(): number;
|
|
5
|
+
/** Ask again every key reading one of `aliases` — every query key where none is named; an unmounted one on its next mount. */
|
|
6
|
+
export declare function refetchReads(aliases: readonly string[] | undefined): void;
|
|
7
|
+
export interface Held<T> {
|
|
8
|
+
/** The answer shown: each staged value over it, else the answer; the last key's while a new key is first asked. */
|
|
9
|
+
data: T | undefined;
|
|
10
|
+
/** When the answer shown was asked; 0 for a staged value or none. */
|
|
11
|
+
askedAt: number;
|
|
12
|
+
error: Error | null;
|
|
13
|
+
/** A first answer is awaited, and none is shown. */
|
|
14
|
+
loading: boolean;
|
|
15
|
+
/** A request for this key is in flight. */
|
|
16
|
+
validating: boolean;
|
|
17
|
+
refetch: () => void;
|
|
18
|
+
}
|
|
19
|
+
export interface KeyOptions<T> {
|
|
20
|
+
/** `false` asks nothing on focus or a reconnect. Default `true`. */
|
|
21
|
+
focus?: boolean;
|
|
22
|
+
/** `false` asks nothing when a key already answered is mounted again. Default `true`. */
|
|
23
|
+
arrival?: boolean;
|
|
24
|
+
/** The query aliases the key reads. */
|
|
25
|
+
aliases?: readonly string[];
|
|
26
|
+
/** An answer known without asking — a design-time fixture's — shown from the first render. */
|
|
27
|
+
known?: (askedAt: number) => T | undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Whether a screen reads a key now. */
|
|
30
|
+
export declare function mountedKey(key: string): boolean;
|
|
31
|
+
/** A key's answer, asked on mount; `null` asks nothing and shows nothing. */
|
|
32
|
+
export declare function useKey<T>(key: string | null, fetcher: Fetcher<T>, opts?: KeyOptions<T>): Held<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Show `next` over a key while `write` runs. A failed write drops it and throws; a successful one keeps it
|
|
35
|
+
* until the read it asks for next — asked after the write — answers with what the server stored.
|
|
36
|
+
*/
|
|
37
|
+
export declare function stageKey<T>(key: string, next: (current: T | undefined) => T, write: () => Promise<unknown>): Promise<void>;
|
|
38
|
+
/** A key's answer outside a render: the one held, else the request in flight, else a new one — so a key read here and on screen is asked once. */
|
|
39
|
+
export declare function readKey<T>(key: string, fetcher: Fetcher<T>): Promise<T>;
|
|
40
|
+
/** Replace a key's answer with what the app knows it now is, asking nothing. */
|
|
41
|
+
export declare function setKey(key: string, answer: unknown): void;
|
|
42
|
+
/** Test seam: forget every answer. */
|
|
43
|
+
export declare function resetStore(): void;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen augments these empty interfaces per app, so an undeclared alias is a
|
|
3
|
+
* compile error. `AppWorkflows`: alias → input shape (`Record<string, never>`
|
|
4
|
+
* for none).
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* // .lotics/app_workflows.d.ts (generated)
|
|
8
|
+
* import "@lotics/app-sdk";
|
|
9
|
+
* declare module "@lotics/app-sdk" {
|
|
10
|
+
* interface AppWorkflows {
|
|
11
|
+
* "issueInvoiceStorageDrop": { record_id: string };
|
|
12
|
+
* "issueInvoiceReuseLift": Record<string, never>;
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export interface AppWorkflows {
|
|
18
|
+
}
|
|
19
|
+
/** Alias → its `return({ data })` type from declared `outputs`; absent ⇒ `unknown`. */
|
|
20
|
+
export interface AppWorkflowResults {
|
|
21
|
+
}
|
|
22
|
+
/** Alias → param shape (`Record<string, never>` for none). */
|
|
23
|
+
export interface AppQueries {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Alias → the union of its projected column names; absent where the AST names
|
|
27
|
+
* none (a bare `from_table`), whose keys stay `string`.
|
|
28
|
+
*/
|
|
29
|
+
export interface AppQueryColumns {
|
|
30
|
+
}
|
|
31
|
+
/** Agent alias → input shape. */
|
|
32
|
+
export interface AppAgents {
|
|
33
|
+
}
|
|
34
|
+
/** Agent alias → its declared `outputs`; absent ⇒ `unknown`. */
|
|
35
|
+
export interface AppAgentResults {
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side image downscaling to JPEG before upload, per fidelity; any
|
|
3
|
+
* other file, or any browser API gap, passes the original through.
|
|
4
|
+
*/
|
|
5
|
+
/** An ordinal scale, so a caller knows what it costs; `@lotics/shared/image_policy` carries the reasoning. */
|
|
6
|
+
export type ImageFidelity = "original" | "high" | "standard";
|
|
7
|
+
/**
|
|
8
|
+
* Mirrors `@lotics/shared/image_policy`, which the published declarations may
|
|
9
|
+
* not name; a test fails on drift. `high`, since most unconsidered uploads carry text.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_IMAGE_FIDELITY: ImageFidelity;
|
|
12
|
+
export interface ImagePolicy {
|
|
13
|
+
maxDimensionPx: number;
|
|
14
|
+
jpegQuality: number;
|
|
15
|
+
}
|
|
16
|
+
/** For the drift test only. */
|
|
17
|
+
export declare const IMAGE_POLICIES_FOR_TEST: Record<"high" | "standard", ImagePolicy>;
|
|
18
|
+
export type OptimizationReason = "optimized" | "skipped_original" | "skipped_unsupported_format" | "skipped_environment_unsupported" | "skipped_decode_unavailable" | "skipped_invalid_dimensions" | "skipped_small_dimensions" | "skipped_canvas_unavailable" | "skipped_canvas_type_mismatch" | "skipped_canvas_no_data";
|
|
19
|
+
export interface OptimizationResult {
|
|
20
|
+
file: File;
|
|
21
|
+
optimized: boolean;
|
|
22
|
+
reason: OptimizationReason;
|
|
23
|
+
originalSizeBytes: number;
|
|
24
|
+
optimizedSizeBytes: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
targetWidth: number;
|
|
28
|
+
targetHeight: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function optimizeImageForUpload(file: File, fidelity?: ImageFidelity): Promise<OptimizationResult>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Upload: optimize (images) → presigned URL → PUT with retry → complete. */
|
|
2
|
+
import { type ImageFidelity } from "./optimize.js";
|
|
3
|
+
interface UploadInitResponse {
|
|
4
|
+
upload_url: string;
|
|
5
|
+
file_id: string;
|
|
6
|
+
file_storage_key: string;
|
|
7
|
+
}
|
|
8
|
+
interface CompleteResponseFile {
|
|
9
|
+
id: string;
|
|
10
|
+
filename: string;
|
|
11
|
+
mime_type: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
thumbnail_url?: string;
|
|
14
|
+
preview_url?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Injected, so the pipeline stays free of the SDK's auth and bootstrap. */
|
|
17
|
+
export interface UploadRpc {
|
|
18
|
+
initUpload(input: {
|
|
19
|
+
filename: string;
|
|
20
|
+
mime_type: string;
|
|
21
|
+
file_size: number;
|
|
22
|
+
}): Promise<UploadInitResponse>;
|
|
23
|
+
completeUpload(input: {
|
|
24
|
+
file_id: string;
|
|
25
|
+
file_storage_key: string;
|
|
26
|
+
filename: string;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
file: CompleteResponseFile;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface RunUploadPipelineOptions {
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
fidelity?: ImageFidelity;
|
|
34
|
+
}
|
|
35
|
+
export declare function runUploadPipeline(file: File, rpc: UploadRpc, options?: RunUploadPipelineOptions): Promise<CompleteResponseFile>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload transport: a per-request timeout, since a bare `fetch` can hang
|
|
3
|
+
* forever, and exponential-backoff retry for the storage PUT, the most
|
|
4
|
+
* failure-prone step on mobile.
|
|
5
|
+
*/
|
|
6
|
+
export declare const UPLOAD_TIMEOUT_MS: number;
|
|
7
|
+
export declare class UploadTimeoutError extends Error {
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly timeoutMs: number;
|
|
10
|
+
readonly name = "UploadTimeoutError";
|
|
11
|
+
constructor(url: string, timeoutMs: number);
|
|
12
|
+
}
|
|
13
|
+
export declare class UploadAbortedError extends Error {
|
|
14
|
+
readonly name = "UploadAbortedError";
|
|
15
|
+
constructor();
|
|
16
|
+
}
|
|
17
|
+
export declare function fetchWithTimeout(url: string, init: RequestInit, timeoutMs: number): Promise<Response>;
|
|
18
|
+
/** Retries network errors, timeouts and 5xx; a 4xx is returned as is, and an abort propagates. */
|
|
19
|
+
export declare function putToStorageWithRetry(uploadUrl: string, file: File, signal: AbortSignal | undefined): Promise<Response>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed query-string codecs behind `useUrlState`. A `.withDefault(d)` value
|
|
3
|
+
* equal to its default is omitted from the URL; only declared keys are read or
|
|
4
|
+
* written, and every other param is preserved on merge.
|
|
5
|
+
*/
|
|
6
|
+
/** An array for a repeated key (`?tag=a&tag=b`). */
|
|
7
|
+
export type UrlParamValue = string | string[];
|
|
8
|
+
export type UrlParams = Record<string, UrlParamValue>;
|
|
9
|
+
/** `undefined` clears a key; keys not present are preserved. */
|
|
10
|
+
export type UrlParamsPatch = Record<string, UrlParamValue | undefined>;
|
|
11
|
+
/** Methods, not function properties, so `UrlParamCodec<string>` stays assignable to `UrlParamCodec<unknown>`. */
|
|
12
|
+
export interface UrlParamCodec<T> {
|
|
13
|
+
decode(raw: UrlParamValue | undefined): T;
|
|
14
|
+
/** `undefined` omits the key. */
|
|
15
|
+
encode(value: T): UrlParamValue | undefined;
|
|
16
|
+
}
|
|
17
|
+
export interface OptionalUrlParamCodec<T> extends UrlParamCodec<T | undefined> {
|
|
18
|
+
/** An absent key decodes to `fallback`; a value equal to it is omitted. */
|
|
19
|
+
withDefault(fallback: T): UrlParamCodec<T>;
|
|
20
|
+
}
|
|
21
|
+
declare function enumCodec<const V extends readonly string[]>(values: V): OptionalUrlParamCodec<V[number]>;
|
|
22
|
+
declare function arrayOf<T>(inner: UrlParamCodec<T | undefined>): OptionalUrlParamCodec<T[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Each builder is optional; `.withDefault(v)` makes it required.
|
|
25
|
+
*
|
|
26
|
+
* useUrlState({
|
|
27
|
+
* q: urlParam.string.withDefault(""),
|
|
28
|
+
* status: urlParam.enum(["open", "won", "lost"]), // optional
|
|
29
|
+
* tags: urlParam.arrayOf(urlParam.string).withDefault([]),
|
|
30
|
+
* from: urlParam.isoDate, // optional Date
|
|
31
|
+
* page: urlParam.number.withDefault(1),
|
|
32
|
+
* })
|
|
33
|
+
*/
|
|
34
|
+
export declare const urlParam: {
|
|
35
|
+
readonly string: OptionalUrlParamCodec<string>;
|
|
36
|
+
readonly number: OptionalUrlParamCodec<number>;
|
|
37
|
+
readonly boolean: OptionalUrlParamCodec<boolean>;
|
|
38
|
+
readonly isoDate: OptionalUrlParamCodec<Date>;
|
|
39
|
+
readonly enum: typeof enumCodec;
|
|
40
|
+
readonly arrayOf: typeof arrayOf;
|
|
41
|
+
};
|
|
42
|
+
export declare function decodeAll<D extends Record<string, UrlParamCodec<unknown>>>(defs: D, params: UrlParams): {
|
|
43
|
+
[K in keyof D]: D[K] extends UrlParamCodec<infer T> ? T : never;
|
|
44
|
+
};
|
|
45
|
+
/** Only the keys present in `values` are emitted, so the write merges. */
|
|
46
|
+
export declare function encodePatch<D extends Record<string, UrlParamCodec<unknown>>>(defs: D, values: Partial<{
|
|
47
|
+
[K in keyof D]: D[K] extends UrlParamCodec<infer T> ? T : never;
|
|
48
|
+
}>): UrlParamsPatch;
|
|
49
|
+
export declare function parseSearch(search: string): UrlParams;
|
|
50
|
+
/** The merged query string, without the leading `?`. */
|
|
51
|
+
export declare function serializeMerge(search: string, patch: UrlParamsPatch): string;
|
|
52
|
+
export declare function applyPatch(params: UrlParams, patch: UrlParamsPatch): UrlParams;
|
|
53
|
+
/** Drops an echo of the app's own write. */
|
|
54
|
+
export declare function paramsEqual(a: UrlParams, b: UrlParams): boolean;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RecentsApi<T> {
|
|
2
|
+
/** Deduped by `keyOf`, capped at `max`. */
|
|
3
|
+
recents: T[];
|
|
4
|
+
/** Call on select. */
|
|
5
|
+
remember: (item: T) => void;
|
|
6
|
+
forget: (item: T) => void;
|
|
7
|
+
clear: () => void;
|
|
8
|
+
}
|
|
9
|
+
export interface RecentsOptions<T> {
|
|
10
|
+
/** Default `JSON.stringify`; pass an id for objects you recreate. */
|
|
11
|
+
keyOf?: (item: T) => string;
|
|
12
|
+
/** Default 5. */
|
|
13
|
+
max?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function useRecents<T>(key: string, options?: RecentsOptions<T>): RecentsApi<T>;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { type UrlParamCodec } from "./url_params.js";
|
|
2
|
-
/** A `useUrlState` shape: a map of param key → codec. */
|
|
3
2
|
export type UrlStateShape = Record<string, UrlParamCodec<unknown>>;
|
|
4
|
-
/** The decoded, typed values for a shape. */
|
|
5
3
|
export type UrlStateValues<D extends UrlStateShape> = {
|
|
6
4
|
[K in keyof D]: D[K] extends UrlParamCodec<infer T> ? T : never;
|
|
7
5
|
};
|
package/dist/viewer.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type AppContext } from "./rpc.js";
|
|
2
|
+
/** The store key the host's context is held under, read by every screen and by the write model alike. */
|
|
3
|
+
export declare const APP_CONTEXT_KEY = "app-context";
|
|
4
|
+
export declare function readContext(): Promise<AppContext>;
|
|
5
|
+
/**
|
|
6
|
+
* The host's context, read once and shared. `settled` once it answered or
|
|
7
|
+
* failed; on `failure` every fact is unknown, so draw the failure rather than
|
|
8
|
+
* guess.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useAppContext(): {
|
|
11
|
+
memberId: string | null;
|
|
12
|
+
commentsEnabled: boolean;
|
|
13
|
+
recordingEnabled: boolean;
|
|
14
|
+
timezone: string | undefined;
|
|
15
|
+
currency: string | undefined;
|
|
16
|
+
resolved: boolean;
|
|
17
|
+
settled: boolean;
|
|
18
|
+
failure: {
|
|
19
|
+
message: string;
|
|
20
|
+
retry: () => void;
|
|
21
|
+
} | null;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The IANA zone an instant (`__created_at`, a comment's time) is dated in; a
|
|
25
|
+
* date cell is a wall clock and needs none. `undefined` until resolved.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useWorkspaceTimezone(): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The ISO 4217 code for money whose field states none — pass it as `currency`,
|
|
30
|
+
* or the kit prints its home market. `undefined` until resolved.
|
|
31
|
+
*/
|
|
32
|
+
export declare function useWorkspaceCurrency(): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* The viewing member — the view-as target under "View as" — or `null` for a
|
|
35
|
+
* public visitor, while `loading`, or on failure. Row scoping needs no viewer:
|
|
36
|
+
* use an `is_current_member` query filter.
|
|
37
|
+
*/
|
|
38
|
+
export declare function useViewer(): {
|
|
39
|
+
memberId: string | null;
|
|
40
|
+
loading: boolean;
|
|
41
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type BodyTable } from "./shared_types.js";
|
|
2
|
+
import type { TableField } from "./shared_types.js";
|
|
3
|
+
import { type QueryWriteShape } from "./shared_types.js";
|
|
4
|
+
export type Row = Record<string, unknown>;
|
|
5
|
+
/** A predicted write in the shape rows store it: an option as `["opt_…"]`, a link as `[{ id, display }]`. */
|
|
6
|
+
export type Staged = {
|
|
7
|
+
kind: "update" | "create";
|
|
8
|
+
table_id: string;
|
|
9
|
+
record_id: string;
|
|
10
|
+
cells: Record<string, unknown>;
|
|
11
|
+
unknown: readonly string[];
|
|
12
|
+
} | {
|
|
13
|
+
kind: "remove";
|
|
14
|
+
table_id: string;
|
|
15
|
+
record_id: string;
|
|
16
|
+
};
|
|
17
|
+
/** The org's members as the roster answers them: a face for a member no read has drawn yet. */
|
|
18
|
+
export declare function noteMembers(roster: readonly {
|
|
19
|
+
id: string;
|
|
20
|
+
}[]): void;
|
|
21
|
+
/** A record as a write leaves it: its stored cells, then each staged write over it, in order. */
|
|
22
|
+
export declare function recordAfter(recordId: string, staged: readonly Staged[]): {
|
|
23
|
+
cells: Map<string, unknown>;
|
|
24
|
+
unknown: Set<string>;
|
|
25
|
+
gone: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** A write staged before its run answers, and the ids minted for the rows it makes — the run is sent them. */
|
|
28
|
+
export interface StagedWrite {
|
|
29
|
+
token: number;
|
|
30
|
+
minted: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Stage what `workflow` will write with `inputs`, before its run is sent. Null where nothing can be said: no
|
|
34
|
+
* model yet, a workflow that writes no record, or a guard the client can read refusing it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function stageWrite(workflow: string, inputs: Readonly<Record<string, unknown>>): Promise<StagedWrite | null>;
|
|
37
|
+
export declare function dropWrite(token: number): void;
|
|
38
|
+
/** The server kept the write: every read asked from now on carries it. */
|
|
39
|
+
export declare function settleWrite(token: number): void;
|
|
40
|
+
/** Whether a run of `workflow` writes records — every run while the model is unread. */
|
|
41
|
+
export declare function writesRecords(workflow: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Note a read's answer: its rows as stored, and when it was asked — or, for a key holding pages asked at
|
|
44
|
+
* different times, when its oldest was (`since`).
|
|
45
|
+
*/
|
|
46
|
+
export declare function noteAnswer(key: string, alias: string, askedAt: number, rows: readonly Row[], since?: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* The queries a successful run of `workflow` re-reads: those over a table its body names. Undefined — every
|
|
49
|
+
* mounted query — until the model is read, or where a write names a table only at run time.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readsAfter(workflow: string, token: number | null): string[] | undefined;
|
|
52
|
+
/** What overlaying one read needs: the model, what this app has read, and the writes live over that read. */
|
|
53
|
+
export interface Over {
|
|
54
|
+
field: (tableId: string, key: string) => TableField | undefined;
|
|
55
|
+
table: (tableId: string) => BodyTable | undefined;
|
|
56
|
+
held: (recordId: string) => Map<string, unknown> | undefined;
|
|
57
|
+
member: (id: string) => unknown;
|
|
58
|
+
memberId: string | null;
|
|
59
|
+
timezone: string | undefined;
|
|
60
|
+
staged: readonly Staged[];
|
|
61
|
+
/** The rows of writes the server has kept, which open as any other. */
|
|
62
|
+
kept: ReadonlySet<string>;
|
|
63
|
+
/** A write over these tables is in flight, or wrote rows of one its prediction could not name. */
|
|
64
|
+
pending: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** A query the model describes, with every table its answer depends on. */
|
|
67
|
+
export declare function shapeOf(alias: string): {
|
|
68
|
+
shape: QueryWriteShape;
|
|
69
|
+
tables: ReadonlySet<string>;
|
|
70
|
+
} | undefined;
|
|
71
|
+
/** The writes live over a read asked at `askedAt` of `tables` — asked before each settled — or null where none touches it. */
|
|
72
|
+
export declare function writesOver(tables: ReadonlySet<string>, askedAt: number): Over | null;
|
|
73
|
+
/** Whether a write in flight touches what an alias reads. */
|
|
74
|
+
export declare function pendingRead(alias: string): boolean;
|
|
75
|
+
export declare function useWrittenVersion(): number;
|
|
76
|
+
/** Test seam: forget everything read and staged. */
|
|
77
|
+
export declare function resetWritten(): void;
|