@lotics/app-sdk 0.10.0 → 0.11.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/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +1 -0
- package/dist/src/members.d.ts +28 -0
- package/dist/src/members.js +42 -0
- package/dist/src/rpc.js +20 -3
- package/package.json +1 -1
package/dist/src/index.d.ts
CHANGED
|
@@ -16,5 +16,7 @@ export type { UploadedFile } from "./hooks.js";
|
|
|
16
16
|
export { downloadFileFromUrl } from "./download.js";
|
|
17
17
|
export { rpc } from "./rpc.js";
|
|
18
18
|
export type { RpcOp } from "./rpc.js";
|
|
19
|
+
export { readMembers } from "./members.js";
|
|
20
|
+
export type { ResolvedMember } from "./members.js";
|
|
19
21
|
export type { AppFixture } from "./mock.js";
|
|
20
22
|
export type { AppWorkflows, AppQueries } from "./types.js";
|
package/dist/src/index.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader for `select_member` cells in `useQuery` rows.
|
|
3
|
+
*
|
|
4
|
+
* The server (`backend/lib/select_member_resolver.ts`) rewrites every
|
|
5
|
+
* `select_member` column from its storage shape (`string[]` of bare member
|
|
6
|
+
* IDs) into `ResolvedMember[]` before the row reaches the app. Apps used to
|
|
7
|
+
* hardcode an id→name fallback map because the SDK didn't expose the
|
|
8
|
+
* resolved shape; this helper makes the right shape the obvious one.
|
|
9
|
+
*
|
|
10
|
+
* If the wire format changes, the resolver and this reader move together.
|
|
11
|
+
*/
|
|
12
|
+
export interface ResolvedMember {
|
|
13
|
+
id: string;
|
|
14
|
+
/** `null` when the id resolves outside the app's org (e.g. removed
|
|
15
|
+
* member) — surfaces the missing state explicitly instead of an
|
|
16
|
+
* empty string. */
|
|
17
|
+
name: string | null;
|
|
18
|
+
/** Present only on authenticated responses. Omitted on public-app
|
|
19
|
+
* responses (no PII exposure to anonymous visitors). */
|
|
20
|
+
email?: string | null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parse a `useQuery` cell value into `ResolvedMember[]`. Returns `[]` for
|
|
24
|
+
* null/undefined/empty cells and for any unexpected shape — callers iterate
|
|
25
|
+
* uniformly without null-checks. Entries that fail the shape check are
|
|
26
|
+
* dropped silently rather than corrupting the array with partial data.
|
|
27
|
+
*/
|
|
28
|
+
export declare function readMembers(value: unknown): ResolvedMember[];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader for `select_member` cells in `useQuery` rows.
|
|
3
|
+
*
|
|
4
|
+
* The server (`backend/lib/select_member_resolver.ts`) rewrites every
|
|
5
|
+
* `select_member` column from its storage shape (`string[]` of bare member
|
|
6
|
+
* IDs) into `ResolvedMember[]` before the row reaches the app. Apps used to
|
|
7
|
+
* hardcode an id→name fallback map because the SDK didn't expose the
|
|
8
|
+
* resolved shape; this helper makes the right shape the obvious one.
|
|
9
|
+
*
|
|
10
|
+
* If the wire format changes, the resolver and this reader move together.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Parse a `useQuery` cell value into `ResolvedMember[]`. Returns `[]` for
|
|
14
|
+
* null/undefined/empty cells and for any unexpected shape — callers iterate
|
|
15
|
+
* uniformly without null-checks. Entries that fail the shape check are
|
|
16
|
+
* dropped silently rather than corrupting the array with partial data.
|
|
17
|
+
*/
|
|
18
|
+
export function readMembers(value) {
|
|
19
|
+
if (!Array.isArray(value))
|
|
20
|
+
return [];
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const entry of value) {
|
|
23
|
+
if (!entry || typeof entry !== "object")
|
|
24
|
+
continue;
|
|
25
|
+
const obj = entry;
|
|
26
|
+
const id = obj.id;
|
|
27
|
+
if (typeof id !== "string" || id === "")
|
|
28
|
+
continue;
|
|
29
|
+
const name = typeof obj.name === "string" ? obj.name : obj.name === null ? null : null;
|
|
30
|
+
const m = { id, name };
|
|
31
|
+
if ("email" in obj) {
|
|
32
|
+
m.email =
|
|
33
|
+
typeof obj.email === "string"
|
|
34
|
+
? obj.email
|
|
35
|
+
: obj.email === null
|
|
36
|
+
? null
|
|
37
|
+
: null;
|
|
38
|
+
}
|
|
39
|
+
out.push(m);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
package/dist/src/rpc.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
import { promptForPassword } from "./password_gate.js";
|
|
2
2
|
import { runUploadPipeline } from "./upload/pipeline.js";
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The embedding Lotics host's origin — present iff the app is bridged.
|
|
5
|
+
*
|
|
6
|
+
* Lazy + memoized so the module's top level doesn't touch `window`. The SDK
|
|
7
|
+
* gets imported by `frontend/lib/download.ts`, which Jest pulls in at module
|
|
8
|
+
* evaluation time before its jsdom environment finishes setting up
|
|
9
|
+
* `window.location` — eager reads crash every test suite that transitively
|
|
10
|
+
* imports the SDK.
|
|
11
|
+
*
|
|
12
|
+
* `undefined` = not yet computed; `string | null` = computed result.
|
|
13
|
+
*/
|
|
14
|
+
let hostOriginCache;
|
|
15
|
+
function getHostOrigin() {
|
|
16
|
+
if (hostOriginCache === undefined) {
|
|
17
|
+
hostOriginCache = new URLSearchParams(window.location.search).get("lotics_host");
|
|
18
|
+
}
|
|
19
|
+
return hostOriginCache;
|
|
20
|
+
}
|
|
5
21
|
export function rpc(op, payload) {
|
|
22
|
+
const hostOrigin = getHostOrigin();
|
|
6
23
|
return hostOrigin
|
|
7
24
|
? rpcBridged(op, payload, hostOrigin)
|
|
8
25
|
: rpcStandalone(op, payload);
|
|
@@ -16,7 +33,7 @@ function ensureListener() {
|
|
|
16
33
|
listenerInstalled = true;
|
|
17
34
|
window.addEventListener("message", (event) => {
|
|
18
35
|
// Accept only messages from the parent window, at the host origin.
|
|
19
|
-
if (event.source !== window.parent || event.origin !==
|
|
36
|
+
if (event.source !== window.parent || event.origin !== getHostOrigin())
|
|
20
37
|
return;
|
|
21
38
|
const msg = event.data;
|
|
22
39
|
if (!msg || typeof msg.id !== "number")
|