@lotics/app-sdk 0.123.11 → 0.124.1

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 CHANGED
@@ -14,17 +14,17 @@ This file is the index. The **exact type** of anything is its shipped declaratio
14
14
 
15
15
  | Doc | Read it for |
16
16
  |---|---|
17
- | [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 and `total: { where }` a count per named filter, from one scan — `useQueries` for reads known only at render, `queryAll` outside React, `exportQuery` for a file of them the server makes; 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** and `answeredAt` (the server answering again what a screen drew), 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. |
17
+ | [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 and `total: { where }` a count per named filter, from one scan — `useQueries` for reads known only at render, `queryAll` outside React, `exportQuery` for a file of them the server makes; 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`/`readLockedBy`, `readCreatedAt`/`readUpdatedAt`), the SDK's own cache — **arrival revalidates** — **realtime push** and `answeredAt` (the server answering again what a screen drew), 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. |
18
18
  | [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. |
19
19
  | [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`, `useRecordings` over several aliases. |
20
20
  | [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. |
21
21
  | [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. |
22
22
  | [docs/files.md](./docs/files.md) | Files end to end — `useFileUpload` and its `fidelity` and a photo's `place`, `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. |
23
- | [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`, a record's activity and the undo of one change (`useRecordActivity`, `undoRecordChange`). |
23
+ | [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`, a member's links to one record for a person with no seat (`useOutsideLinks`). |
24
24
  | [docs/navigation_and_state.md](./docs/navigation_and_state.md) | `AppRouter` (embedded/standalone URL model, the screens and `drawers` it reports to the host), `useUrlState` + `urlParam` codecs, `useRecents`, `useFolderPick`. |
25
25
  | [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. |
26
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, why a per-input bound is a tenancy floor rather than an authorization check. |
27
- | [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` — queries, workflows and agents, a mocked agent's run played line by line), `openExternal`/`openApp`/`peekApp`/`downloadFile`, geofencing, the peer dependencies. |
27
+ | [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()` and `installRpcTransport` (a page that is never an app's answers every op itself), the mock harness (`fixture` + `?__mock=1` — queries, workflows and agents, a mocked agent's run played line by line), `openExternal`/`openApp`/`peekApp`/`downloadFile`, geofencing, the peer dependencies. |
28
28
 
29
29
  ## Non-negotiables (each detailed in its doc)
30
30
 
@@ -249,6 +249,18 @@ function isFieldKey(value) {
249
249
  return value.startsWith(FIELD_KEY_PREFIX);
250
250
  }
251
251
 
252
+ // ../shared/src/compare_bounds.ts
253
+ var COMPARE_KEYS = ["gt", "gte", "lt", "lte"];
254
+ function isRecordBound(bound) {
255
+ return typeof bound === "object" && "record" in bound;
256
+ }
257
+ function boundsOf(compared) {
258
+ return COMPARE_KEYS.flatMap((key) => {
259
+ const bound = compared[key];
260
+ return bound === void 0 ? [] : [{ key, bound }];
261
+ });
262
+ }
263
+
252
264
  // ../shared/src/schemas/app_spec_rules.ts
253
265
  var bandKey = (band) => `${band.min ?? ""}..${band.max ?? ""}`;
254
266
  function bandOf(tiers, figure) {
@@ -256,6 +268,8 @@ function bandOf(tiers, figure) {
256
268
  const at = above < 0 ? tiers.length : above;
257
269
  return { min: tiers[at - 1] ?? null, max: tiers[at] ?? null };
258
270
  }
271
+ var AGENT_SCAN_READS = ["text", "iso6346"];
272
+ var SCAN_READS = [...AGENT_SCAN_READS, "code"];
259
273
 
260
274
  // ../../node_modules/big.js/big.mjs
261
275
  var DP = 20;
@@ -1315,7 +1329,15 @@ function getHostOrigin() {
1315
1329
  function isEmbedded() {
1316
1330
  return Boolean(getHostOrigin());
1317
1331
  }
1332
+ var installedTransport = null;
1333
+ function installRpcTransport(transport) {
1334
+ installedTransport = transport;
1335
+ }
1336
+ function hostSpec() {
1337
+ return rpc("spec", {});
1338
+ }
1318
1339
  function rpc(op, payload) {
1340
+ if (installedTransport !== null) return installedTransport(op, payload);
1319
1341
  const hostOrigin = getHostOrigin();
1320
1342
  return hostOrigin ? rpcBridged(op, payload, hostOrigin) : rpcStandalone(op, payload);
1321
1343
  }
@@ -1750,6 +1772,8 @@ function rpcStandalone(op, payload) {
1750
1772
  return standaloneMembers(payload);
1751
1773
  case "context":
1752
1774
  return standaloneContext();
1775
+ case "spec":
1776
+ return Promise.reject(new Error("A standalone app carries its spec in its document; only the Lotics host hands one over the bridge."));
1753
1777
  case "write_model":
1754
1778
  return standaloneWriteModel();
1755
1779
  case "prediction_miss":
@@ -1780,14 +1804,15 @@ function rpcStandalone(op, payload) {
1780
1804
  case "comments.delete":
1781
1805
  case "comments.counts":
1782
1806
  return rejectCommentsStandalone();
1783
- case "activity.list":
1784
- case "activity.undo":
1785
- return Promise.reject(new Error("A record's activity is available only in embedded apps \u2014 a signed-in member is required."));
1786
1807
  case "recording.start":
1787
1808
  case "recording.stop":
1788
1809
  return Promise.reject(
1789
1810
  new Error("Recording needs the Lotics host and a signed-in member. Gate the control on useRecording's `available`.")
1790
1811
  );
1812
+ case "outsideLink.list":
1813
+ case "outsideLink.create":
1814
+ case "outsideLink.revoke":
1815
+ return Promise.reject(new Error("A link to a record is made and withdrawn by a signed-in member in the Lotics host. Gate the control on useOutsideLinks' `available`."));
1791
1816
  }
1792
1817
  }
1793
1818
  function folderTable(payload) {
@@ -2000,6 +2025,9 @@ export {
2000
2025
  searchWords,
2001
2026
  customAlphabet,
2002
2027
  isFieldKey,
2028
+ COMPARE_KEYS,
2029
+ isRecordBound,
2030
+ boundsOf,
2003
2031
  bandKey,
2004
2032
  bandOf,
2005
2033
  addDecimal,
@@ -2030,6 +2058,8 @@ export {
2030
2058
  applyPatch,
2031
2059
  paramsEqual,
2032
2060
  isEmbedded,
2061
+ installRpcTransport,
2062
+ hostSpec,
2033
2063
  rpc,
2034
2064
  getUrlParams,
2035
2065
  setUrlParams,
@@ -51,7 +51,7 @@ export interface CommentsState {
51
51
  export interface UseCommentsArgs {
52
52
  record_id: string;
53
53
  }
54
- /** What every read a comment changes is read under — the counts, a record's activity — so a comment written or deleted asks each again. */
54
+ /** What every read a comment changes is read under — the counts — so a comment written or deleted asks each again. */
55
55
  export declare const COMMENT_WRITES = "comment-counts";
56
56
  /**
57
57
  * `record_id` must be a real id — an empty string still fetches. Gate the
package/dist/index.d.ts CHANGED
@@ -11,18 +11,17 @@ export type { ExportedFile } from "./shared_types.js";
11
11
  export type { AttachedFile, AttachmentPiles, AttachmentPilesOptions, AttachmentsOptions, AttachmentsState } from "./attachments.js";
12
12
  export { useComments, useCommentCounts } from "./comments.js";
13
13
  export type { AppComment, AppCommentAuthor, AppCommentFile, CommentsState, UseCommentsArgs, CommentCountsState, UseCommentCountsArgs, } from "./comments.js";
14
- export { undoRecordChange, useRecordActivity } from "./activity.js";
15
- export type { RecordActivityOptions, RecordActivityState } from "./activity.js";
16
- export type { ActivityActor, ActivityActorKind, ActivityChange, ActivityComment, ActivityEntry, ActivityUndoResult, ActivityValue, RecordActivityPage, UndoKeptReason, } from "./shared_types.js";
17
14
  export { useAppContext, useViewer, useWorkspaceCurrency, useWorkspaceTimezone } from "./viewer.js";
18
15
  export type { AppAbsence } from "./shared_types.js";
16
+ export { useOutsideLinks } from "./outside_link.js";
17
+ export type { OutsideLinksState } from "./outside_link.js";
19
18
  export { useRecording, useRecordings } from "./recording.js";
20
19
  export type { UseRecording, UseRecordings } from "./recording.js";
21
20
  export type { RecordingState, RecordingInputs } from "./recording_state.js";
22
21
  export { requestGeofencedLocation, isWithinZone } from "./geolocation.js";
23
22
  export type { GeofenceZone, GeoCoords, GeofenceOutcome, GeofenceOptions } from "./geolocation.js";
24
- export { rpc, isEmbedded } from "./rpc.js";
25
- export type { RpcOp, AiContextValue, AiContextRecordRef } from "./rpc.js";
23
+ export { rpc, hostSpec, isEmbedded, installRpcTransport } from "./rpc.js";
24
+ export type { RpcOp, RpcTransport, HostSpec, AiContextValue, AiContextRecordRef } from "./rpc.js";
26
25
  export { openExternal } from "./open_external.js";
27
26
  export { openApp, peekApp } from "./open_app.js";
28
27
  export { askAi, type AskAiArgs } from "./ask_ai.js";
@@ -35,7 +34,7 @@ export type { ResolvedOption } from "./select.js";
35
34
  export type { AppFixture, MockExport, MockQuery, MockQueryCall, MockWorkflow } from "./mock.js";
36
35
  export type { MockAgent, MockAgentRun } from "./mock_agent_run.js";
37
36
  export type { AppWorkflows, AppWorkflowResults, AppQueries, AppQueryColumns, AppAgents, AppAgentResults } from "./types.js";
38
- export { row, readLinks, readFiles, readLocked, readCreatedAt, readUpdatedAt, PENDING } from "./row.js";
37
+ export { row, readLinks, readFiles, readLocked, readLockedBy, readCreatedAt, readUpdatedAt, PENDING } from "./row.js";
39
38
  export type { ResolvedLink, AppFile, PhotoPlace } from "./row.js";
40
39
  export { useNewRecord, newRecordId } from "./new_record.js";
41
40
  export type { NewRecordApi } from "./new_record.js";