@lotics/app-sdk 0.2.0 → 0.3.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.
@@ -3,6 +3,16 @@ interface QueryState<R> {
3
3
  rows: R[];
4
4
  loading: boolean;
5
5
  error: string | null;
6
+ /**
7
+ * Re-run the underlying query against the current AST / table_id. Use after
8
+ * known mutation points — `useMutate.update`, `useAction(...)`, or a
9
+ * successful `useWorkflow(alias)()` — to pull the latest state.
10
+ *
11
+ * The iframe SDK does not subscribe to realtime invalidation channels in
12
+ * v1; refetch is the explicit refresh path. Future SDK versions may add a
13
+ * `subscribe` RPC op for push-based invalidation.
14
+ */
15
+ refetch: () => void;
6
16
  }
7
17
  /**
8
18
  * Read all rows from a table. Re-fetches when the table id changes.
@@ -34,20 +44,25 @@ export declare function useAction(action_id: string): (inputs?: Record<string, u
34
44
  * Trigger a workflow by alias from the app's manifest.
35
45
  *
36
46
  * The alias must be declared in `package.json` "lotics.workflows" and synced
37
- * to `apps.workflows` on the last deploy. Returns a callable; pass whatever
38
- * inputs the workflow expects (the workflow's own trigger schema gates them
39
- * server-side).
47
+ * to `apps.workflows` on the last deploy.
40
48
  *
41
- * Per-app `lotics types` codegen augments `AppWorkflows` with the declared
42
- * alias keys passing an undeclared alias is a compile-time error.
49
+ * Per-app CLI codegen (`lotics app pull` / `app dev` / `app deploy`) writes
50
+ * `.lotics/app_workflows.d.ts` augmenting `AppWorkflows` with the declared
51
+ * alias → input-type map. Result:
52
+ * - Undeclared alias → compile-time error at the `useWorkflow("...")` site
53
+ * - Declared with full `{workflow_id, inputs}` form → callable typed as
54
+ * `(inputs: <DeclaredShape>) => Promise<unknown>`
55
+ * - Declared with shorthand (bare workflow_id) → callable typed as
56
+ * `(inputs?: Record<string, unknown>) => Promise<unknown>` (untyped)
43
57
  *
44
58
  * ```tsx
45
59
  * const issue = useWorkflow("issueInvoiceStorageDrop");
46
60
  * await issue({ record_id: row.__source_record_id });
47
61
  * ```
48
62
  */
49
- export declare function useWorkflow<K extends keyof AppWorkflows & string>(alias: K): (inputs?: Record<string, unknown>) => Promise<unknown>;
63
+ export declare function useWorkflow<K extends keyof AppWorkflows & string>(alias: K): UseWorkflowFn<K>;
50
64
  export declare function useWorkflow(alias: string): (inputs?: Record<string, unknown>) => Promise<unknown>;
65
+ type UseWorkflowFn<K extends keyof AppWorkflows & string> = AppWorkflows[K] extends Record<string, unknown> ? AppWorkflows[K] extends Record<string, never> ? (inputs?: Record<string, never>) => Promise<unknown> : (inputs: AppWorkflows[K]) => Promise<unknown> : (inputs?: Record<string, unknown>) => Promise<unknown>;
51
66
  /**
52
67
  * Escape hatch — pass a raw query AST. Same shape the server validates via
53
68
  * `parseQueryNode`. Use for joins, group-by, projections, and other shapes
package/dist/src/hooks.js CHANGED
@@ -14,6 +14,7 @@
14
14
  import { useCallback, useEffect, useState } from "react";
15
15
  import { rpc } from "./rpc.js";
16
16
  export function useTable(table_id) {
17
+ const [refetchToken, setRefetchToken] = useState(0);
17
18
  const [state, setState] = useState({
18
19
  rows: [],
19
20
  loading: true,
@@ -41,8 +42,12 @@ export function useTable(table_id) {
41
42
  return () => {
42
43
  cancelled = true;
43
44
  };
44
- }, [table_id]);
45
- return state;
45
+ // eslint-disable-next-line react-hooks/exhaustive-deps
46
+ }, [table_id, refetchToken]);
47
+ const refetch = useCallback(() => {
48
+ setRefetchToken((n) => n + 1);
49
+ }, []);
50
+ return { ...state, refetch };
46
51
  }
47
52
  export function useMutate(table_id) {
48
53
  return {
@@ -66,6 +71,10 @@ export function useWorkflow(alias) {
66
71
  */
67
72
  export function useQuery(ast) {
68
73
  const astKey = JSON.stringify(ast);
74
+ // Bumping this token re-fires the effect without changing the AST. The
75
+ // refetch callback mutates only this counter; state transitions still
76
+ // happen inside the effect so loading / error / rows flow consistently.
77
+ const [refetchToken, setRefetchToken] = useState(0);
69
78
  const [state, setState] = useState({
70
79
  rows: [],
71
80
  loading: true,
@@ -89,8 +98,12 @@ export function useQuery(ast) {
89
98
  cancelled = true;
90
99
  };
91
100
  // Dep is the stringified AST so structurally-equal-but-referentially-new
92
- // objects don't re-fetch on every render.
101
+ // objects don't re-fetch on every render. refetchToken lets the consumer
102
+ // explicitly retrigger without changing the AST identity.
93
103
  // eslint-disable-next-line react-hooks/exhaustive-deps
94
- }, [astKey]);
95
- return state;
104
+ }, [astKey, refetchToken]);
105
+ const refetch = useCallback(() => {
106
+ setRefetchToken((n) => n + 1);
107
+ }, []);
108
+ return { ...state, refetch };
96
109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/app-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Runtime SDK for Lotics custom-code apps — typed hooks, postMessage bridge, mount entry point",
5
5
  "type": "module",
6
6
  "exports": {