@lotics/app-sdk 0.1.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.
@@ -1,8 +1,18 @@
1
- import type { QueryAst, TableRow, WorkspaceTables } from "./types.js";
1
+ import type { AppWorkflows, QueryAst, TableRow, WorkspaceTables } from "./types.js";
2
2
  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.
@@ -30,6 +40,29 @@ export declare function useMutate(table_id: string): {
30
40
  type RowFor<K extends keyof WorkspaceTables & string> = WorkspaceTables[K];
31
41
  /** Trigger a workflow by action_id. Returns a callable that runs it. */
32
42
  export declare function useAction(action_id: string): (inputs?: Record<string, unknown>) => Promise<unknown>;
43
+ /**
44
+ * Trigger a workflow by alias from the app's manifest.
45
+ *
46
+ * The alias must be declared in `package.json` "lotics.workflows" and synced
47
+ * to `apps.workflows` on the last deploy.
48
+ *
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)
57
+ *
58
+ * ```tsx
59
+ * const issue = useWorkflow("issueInvoiceStorageDrop");
60
+ * await issue({ record_id: row.__source_record_id });
61
+ * ```
62
+ */
63
+ export declare function useWorkflow<K extends keyof AppWorkflows & string>(alias: K): UseWorkflowFn<K>;
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>;
33
66
  /**
34
67
  * Escape hatch — pass a raw query AST. Same shape the server validates via
35
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 {
@@ -56,6 +61,9 @@ export function useMutate(table_id) {
56
61
  export function useAction(action_id) {
57
62
  return useCallback((inputs) => rpc("action", { action_id, inputs: inputs ?? {} }), [action_id]);
58
63
  }
64
+ export function useWorkflow(alias) {
65
+ return useCallback((inputs) => rpc("workflow", { alias, inputs: inputs ?? {} }), [alias]);
66
+ }
59
67
  /**
60
68
  * Escape hatch — pass a raw query AST. Same shape the server validates via
61
69
  * `parseQueryNode`. Use for joins, group-by, projections, and other shapes
@@ -63,6 +71,10 @@ export function useAction(action_id) {
63
71
  */
64
72
  export function useQuery(ast) {
65
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);
66
78
  const [state, setState] = useState({
67
79
  rows: [],
68
80
  loading: true,
@@ -86,8 +98,12 @@ export function useQuery(ast) {
86
98
  cancelled = true;
87
99
  };
88
100
  // Dep is the stringified AST so structurally-equal-but-referentially-new
89
- // 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.
90
103
  // eslint-disable-next-line react-hooks/exhaustive-deps
91
- }, [astKey]);
92
- return state;
104
+ }, [astKey, refetchToken]);
105
+ const refetch = useCallback(() => {
106
+ setRefetchToken((n) => n + 1);
107
+ }, []);
108
+ return { ...state, refetch };
93
109
  }
@@ -10,7 +10,7 @@
10
10
  * depending on packages/ui's React Native Web setup.
11
11
  */
12
12
  export { mount } from "./mount.js";
13
- export { useTable, useMutate, useAction, useQuery } from "./hooks.js";
13
+ export { useTable, useMutate, useAction, useWorkflow, useQuery } from "./hooks.js";
14
14
  export { rpc } from "./rpc.js";
15
15
  export type { RpcOp } from "./rpc.js";
16
- export type { WorkspaceTables, RowOf, TableRow, SourceAddressing, QueryAst } from "./types.js";
16
+ export type { WorkspaceTables, AppWorkflows, RowOf, TableRow, SourceAddressing, QueryAst, } from "./types.js";
package/dist/src/index.js CHANGED
@@ -10,5 +10,5 @@
10
10
  * depending on packages/ui's React Native Web setup.
11
11
  */
12
12
  export { mount } from "./mount.js";
13
- export { useTable, useMutate, useAction, useQuery } from "./hooks.js";
13
+ export { useTable, useMutate, useAction, useWorkflow, useQuery } from "./hooks.js";
14
14
  export { rpc } from "./rpc.js";
package/dist/src/rpc.d.ts CHANGED
@@ -14,5 +14,5 @@
14
14
  * old bundles must keep working forever, since we can't force users to
15
15
  * redeploy. Add new ops alongside existing ones; never repurpose them.
16
16
  */
17
- export type RpcOp = "query" | "mutate" | "action" | "filter";
17
+ export type RpcOp = "query" | "mutate" | "action" | "workflow" | "filter";
18
18
  export declare function rpc<T = unknown>(op: RpcOp, payload: unknown): Promise<T>;
@@ -22,6 +22,32 @@
22
22
  */
23
23
  export interface WorkspaceTables {
24
24
  }
25
+ /**
26
+ * App-specific workflow augmentation point. Same pattern as WorkspaceTables.
27
+ *
28
+ * The base SDK ships `AppWorkflows` empty — `useWorkflow(alias)` accepts any
29
+ * string at runtime. Per-app codegen (folded into `lotics app pull`) emits a
30
+ * file that augments this interface with the aliases declared in the app's
31
+ * `package.json` lotics.workflows, giving compile-time autocomplete +
32
+ * "undeclared alias" errors:
33
+ *
34
+ * ```ts
35
+ * // .lotics/types.ts (generated)
36
+ * import "@lotics/app-sdk";
37
+ * declare module "@lotics/app-sdk" {
38
+ * interface AppWorkflows {
39
+ * "issueInvoiceStorageDrop": never;
40
+ * "issueInvoiceReuseLift": never;
41
+ * }
42
+ * }
43
+ * ```
44
+ *
45
+ * The `never` value is a placeholder for v2 input/output typing — when the
46
+ * codegen learns to extract workflow trigger schemas, the value becomes the
47
+ * input type. For now the hook's runtime signature is unaffected.
48
+ */
49
+ export interface AppWorkflows {
50
+ }
25
51
  /**
26
52
  * Helper: row type for a known table id, or fallback for unknown ones.
27
53
  * Currently unused by exported hooks (useRecord deferred to v2) but kept
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/app-sdk",
3
- "version": "0.1.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": {