@lotics/app-sdk 0.122.8 → 0.122.9

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.
@@ -882,6 +882,24 @@ function aggregateRows(rows, aggregate) {
882
882
  });
883
883
  }
884
884
 
885
+ // src/load_timing.ts
886
+ function isNavigationTiming(entry) {
887
+ return entry !== void 0 && entry.entryType === "navigation";
888
+ }
889
+ function measureLoadTiming(sentAt) {
890
+ if (typeof performance.getEntriesByType !== "function") return {};
891
+ const navigation = performance.getEntriesByType("navigation")[0];
892
+ if (!isNavigationTiming(navigation)) return {};
893
+ return {
894
+ page_connect_ms: navigation.requestStart - navigation.fetchStart,
895
+ page_ttfb_ms: navigation.responseStart - navigation.requestStart,
896
+ page_download_ms: navigation.responseEnd - navigation.responseStart,
897
+ page_bytes: navigation.transferSize,
898
+ page_decoded_bytes: navigation.decodedBodySize,
899
+ boot_ms: sentAt - navigation.responseEnd
900
+ };
901
+ }
902
+
885
903
  // src/upload/optimize.ts
886
904
  var DEFAULT_IMAGE_FIDELITY = "high";
887
905
  var IMAGE_POLICIES = {
@@ -1332,12 +1350,15 @@ function ensureListener() {
1332
1350
  }
1333
1351
  });
1334
1352
  }
1353
+ var loadTimingSent = false;
1335
1354
  function rpcBridged(op, payload, host) {
1336
1355
  ensureListener();
1337
1356
  return new Promise((resolve, reject) => {
1338
1357
  const id = nextRpcId++;
1339
1358
  pending.set(id, { resolve, reject });
1340
- window.parent.postMessage({ id, op, payload }, host);
1359
+ const load = loadTimingSent ? {} : measureLoadTiming(performance.now());
1360
+ loadTimingSent = true;
1361
+ window.parent.postMessage(Object.keys(load).length === 0 ? { id, op, payload } : { id, op, payload, load }, host);
1341
1362
  });
1342
1363
  }
1343
1364
  function rpcAgentRun(payload, onText, onRunId) {
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  sumDecimal,
41
41
  tiersAscend,
42
42
  urlParam
43
- } from "./chunk-GXEBJ3RC.js";
43
+ } from "./chunk-WM76DHGT.js";
44
44
 
45
45
  // src/mount.tsx
46
46
  import { createRoot } from "react-dom/client";
@@ -0,0 +1,7 @@
1
+ import type { AppLoadTiming } from "./shared_types.js";
2
+ /**
3
+ * This document's own load, from the browser's navigation timing: the connection, the server's wait, the transfer and
4
+ * its size, and how long the runtime took from the document arriving to `sentAt` (a `performance.now()` reading). A
5
+ * browser with no navigation entry states nothing.
6
+ */
7
+ export declare function measureLoadTiming(sentAt: number): AppLoadTiming;
package/dist/router.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  isEmbedded,
3
3
  postHostNotification,
4
4
  setUrlParams
5
- } from "./chunk-GXEBJ3RC.js";
5
+ } from "./chunk-WM76DHGT.js";
6
6
 
7
7
  // src/router.tsx
8
8
  import { useEffect } from "react";
package/dist/rpc.d.ts CHANGED
@@ -6,7 +6,7 @@ import { type UrlParams, type UrlParamsPatch } from "./url_params.js";
6
6
  * postMessage and the host, holding the member's session, calls the API.
7
7
  * Standalone: the public `/v1/apps/{id}/*` endpoints are called directly, with
8
8
  * no credentials. The bridged wire must match `app_iframe_host.tsx`:
9
- * app → host: { id, op, payload }
9
+ * app → host: { id, op, payload }, the first also carrying `load` (`AppLoadTiming`) when the browser states any
10
10
  * host → app: { id, type: "result", data } | { id, type: "error", message }
11
11
  */
12
12
  export type RpcOp = "query" | "export" | "field_options" | "workflow" | "agentRuns" | "agentRun.get" | "agentRun.cancel" | "upload" | "file.rename" | "members" | "context" | "write_model" | "prediction_miss" | "openExternal" | "openApp" | "peekApp" | "askAi" | "urlState.get" | "urlState.set" | "folder.get" | "folder.set" | "comments.list" | "comments.create" | "comments.update" | "comments.delete" | "comments.counts" | "activity.list" | "activity.undo" | "recording.start" | "recording.stop";
@@ -6,6 +6,7 @@
6
6
  export type ActivityEntry = { undoable: boolean; changes: { field_id: string; label: string; before: string | number | boolean | { key: string; label: string; }[] | { id: string; display: string; }[] | { id: string; name: string | null; image?: string | undefined; }[] | { id: string; filename: string; mime_type: string; file_storage_key?: string | undefined; url?: string | undefined; thumbnail_url?: string | undefined; preview_url?: string | undefined; size?: number | null | undefined; created_at?: string | undefined; document_template_id?: string | undefined; }[] | null; after: string | number | boolean | { key: string; label: string; }[] | { id: string; display: string; }[] | { id: string; name: string | null; image?: string | undefined; }[] | { id: string; filename: string; mime_type: string; file_storage_key?: string | undefined; url?: string | undefined; thumbnail_url?: string | undefined; preview_url?: string | undefined; size?: number | null | undefined; created_at?: string | undefined; document_template_id?: string | undefined; }[] | null; removed?: true | undefined; }[]; id: string; actor: { kind: "member" | "agent" | "workflow" | "import"; id: string; name: string; image?: string | undefined; }; at: string; until: string; kind: "change"; created?: true | undefined; undo?: true | undefined; undone?: { by: { kind: "member" | "agent" | "workflow" | "import"; id: string; name: string; image?: string | undefined; }; at: string; } | undefined; } | { comment: { id: string; body: string; mentions: { id: string; name: string; }[]; files?: { id: string; filename: string; mime_type: string; file_storage_key?: string | undefined; url?: string | undefined; thumbnail_url?: string | undefined; preview_url?: string | undefined; size?: number | null | undefined; created_at?: string | undefined; document_template_id?: string | undefined; }[] | undefined; }; id: string; actor: { kind: "member" | "agent" | "workflow" | "import"; id: string; name: string; image?: string | undefined; }; at: string; until: string; kind: "comment"; };
7
7
  export type ActivityUndoResult = { reverted: { field_id: string; label: string; }[]; kept: { field_id: string; label: string; reason: "changed_since" | "refused"; }[]; };
8
8
  export type AppAbsence = { member: { id: string; name: string; }; stand_in: { id: string; name: string; }; starts_on: string; ends_on: string; group_ids: string[]; };
9
+ export type AppLoadTiming = { page_connect_ms?: number | undefined; page_ttfb_ms?: number | undefined; page_download_ms?: number | undefined; page_bytes?: number | undefined; page_decoded_bytes?: number | undefined; boot_ms?: number | undefined; };
9
10
  /** The file an app export made, as a link to download it: no workspace file, so no id, and kept a day. */
10
11
  export type ExportedFile = {
11
12
  filename: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/app-sdk",
3
- "version": "0.122.8",
3
+ "version": "0.122.9",
4
4
  "description": "The SDK a Lotics custom-code app reads and writes through — typed hooks over the host bridge, cell readers, mount() and AppRouter",
5
5
  "type": "module",
6
6
  "exports": {