@colixsystems/widget-sdk 0.9.0 → 0.11.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.
package/README.md CHANGED
@@ -6,7 +6,16 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
6
6
 
7
7
  ## Status
8
8
 
9
- `v0.9.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
9
+ `v0.11.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
10
+
11
+ ### What's new in 0.11.0
12
+
13
+ - **`useNavigation()` is wired.** Returns the host-provided navigation surface `{ goTo, goBack, push, replace, back, currentRoute }` for internal page-to-page navigation. Missing methods degrade to no-ops on the Studio canvas preview. Additive.
14
+ - **`Linking` primitive re-exported.** `Linking.openURL(url)` opens an external URL with the OS handler — web (`react-native-web`) maps to `window.open` / `location.href`; native hands off to the system. Use this for external URLs; use `useNavigation().goTo(pageId)` for internal pages.
15
+
16
+ ### What's new in 0.10.0
17
+
18
+ - **`useUser()` is wired.** Returns the active end-user identity `{ id, email, displayName, roles, groupIds }` from the host-provided `WidgetContext`. `id` is `null` for anonymous visitors and on the Studio canvas preview. All fields are guaranteed present (the host fills safe defaults), so widgets read them without optional chaining. Additive — no migration needed for existing widgets.
10
19
 
11
20
  ### What's new in 0.9.0
12
21
 
@@ -71,7 +80,7 @@ import { defineWidget, validateManifest, useDatastoreQuery, Text, View } from "@
71
80
 
72
81
  - `defineWidget({ manifest, component })` — validates the manifest and produces a widget module the host can register.
73
82
  - `validateManifest(m)` / `validatePropertySchema(s)` / `validateProps(schema, props)` — shape validation; no third-party deps.
74
- - `useDatastoreQuery`, `useDatastoreMutation`, `useDirectory`, `useWidgetEvent`, `usePayments`, `useTheme`, `useI18n` — hooks that read from the host-provided `WidgetContext`. `useDirectory(query?)` returns `{ users, loading, error, refetch }` (each user `{ id, name, role }`) and requires the `directory.read:users` scope. `usePayments()` returns `{ requestPayment, getPayment }` and requires the `payments.charge:appUser` scope; `requestPayment(...)` rejects with a `PaymentError`.
83
+ - `useDatastoreQuery`, `useDatastoreMutation`, `useDirectory`, `useWidgetEvent`, `usePayments`, `useTheme`, `useI18n`, `useUser`, `useNavigation` — hooks that read from the host-provided `WidgetContext`. `useDirectory(query?)` returns `{ users, loading, error, refetch }` (each user `{ id, name, role }`) and requires the `directory.read:users` scope. `usePayments()` returns `{ requestPayment, getPayment }` and requires the `payments.charge:appUser` scope; `requestPayment(...)` rejects with a `PaymentError`. `useUser()` returns the active end-user identity `{ id, email, displayName, roles, groupIds }` (`id` is `null` for anonymous / preview). `useNavigation()` returns `{ goTo, goBack, push, replace, back, currentRoute }` for internal page navigation — for external URLs use the `Linking` primitive (`Linking.openURL(url)`).
75
84
  - `Text`, `View`, `Pressable`, `Image`, `ScrollView`, `TextInput`, `FlatList`, `SectionList`, `ActivityIndicator`, `Switch`, `StyleSheet` — re-exported from `react-native`. The web build aliases `react-native` to `react-native-web` so widgets render in the browser without any per-platform code; the exported Expo app's Metro bundler resolves the real `react-native` library. See https://reactnative.dev/docs/ for per-component props.
76
85
  - `WidgetContextProvider` — React context provider that the host (Studio, Player, exported app) wraps widgets with.
77
86
 
package/dist/contract.cjs CHANGED
@@ -55,6 +55,33 @@ const HOOKS = [
55
55
  requiredContextSlice: ["i18n.t", "i18n.locale"],
56
56
  scopes: null,
57
57
  },
58
+ {
59
+ name: "useUser",
60
+ signature: "useUser()",
61
+ returnShape: {
62
+ id: "string | null",
63
+ email: "string | null",
64
+ displayName: "string | null",
65
+ roles: "string[]",
66
+ groupIds: "string[]",
67
+ },
68
+ requiredContextSlice: ["user"],
69
+ scopes: null,
70
+ },
71
+ {
72
+ name: "useNavigation",
73
+ signature: "useNavigation()",
74
+ returnShape: {
75
+ goTo: "(pageId: string, params?: object) => void",
76
+ goBack: "() => void",
77
+ push: "(pageId: string, params?: object) => void",
78
+ replace: "(pageId: string, params?: object) => void",
79
+ back: "() => void",
80
+ currentRoute: "{ pageId: string, params: object }",
81
+ },
82
+ requiredContextSlice: ["navigation"],
83
+ scopes: null,
84
+ },
58
85
  {
59
86
  name: "useDatastoreQuery",
60
87
  signature: "useDatastoreQuery(tableId, options?)",
@@ -196,6 +223,13 @@ const PRIMITIVES = [
196
223
  rnComponent: "StyleSheet",
197
224
  docsUrl: "https://reactnative.dev/docs/stylesheet",
198
225
  },
226
+ {
227
+ name: "Linking",
228
+ description:
229
+ "Static API for external links. `Linking.openURL(url)` opens a URL with the OS handler (web: window.open / location.href via react-native-web). `canOpenURL` reports whether the scheme is registered. See https://reactnative.dev/docs/linking.",
230
+ rnComponent: "Linking",
231
+ docsUrl: "https://reactnative.dev/docs/linking",
232
+ },
199
233
  ];
200
234
 
201
235
  const CATEGORIES = [
package/dist/contract.js CHANGED
@@ -55,6 +55,33 @@ const HOOKS = [
55
55
  requiredContextSlice: ["i18n.t", "i18n.locale"],
56
56
  scopes: null,
57
57
  },
58
+ {
59
+ name: "useUser",
60
+ signature: "useUser()",
61
+ returnShape: {
62
+ id: "string | null",
63
+ email: "string | null",
64
+ displayName: "string | null",
65
+ roles: "string[]",
66
+ groupIds: "string[]",
67
+ },
68
+ requiredContextSlice: ["user"],
69
+ scopes: null,
70
+ },
71
+ {
72
+ name: "useNavigation",
73
+ signature: "useNavigation()",
74
+ returnShape: {
75
+ goTo: "(pageId: string, params?: object) => void",
76
+ goBack: "() => void",
77
+ push: "(pageId: string, params?: object) => void",
78
+ replace: "(pageId: string, params?: object) => void",
79
+ back: "() => void",
80
+ currentRoute: "{ pageId: string, params: object }",
81
+ },
82
+ requiredContextSlice: ["navigation"],
83
+ scopes: null,
84
+ },
58
85
  {
59
86
  name: "useDatastoreQuery",
60
87
  signature: "useDatastoreQuery(tableId, options?)",
@@ -191,6 +218,13 @@ const PRIMITIVES = [
191
218
  rnComponent: "StyleSheet",
192
219
  docsUrl: "https://reactnative.dev/docs/stylesheet",
193
220
  },
221
+ {
222
+ name: "Linking",
223
+ description:
224
+ "Static API for external links. `Linking.openURL(url)` opens a URL with the OS handler (web: window.open / location.href via react-native-web). `canOpenURL` reports whether the scheme is registered. See https://reactnative.dev/docs/linking.",
225
+ rnComponent: "Linking",
226
+ docsUrl: "https://reactnative.dev/docs/linking",
227
+ },
194
228
  ];
195
229
 
196
230
  const CATEGORIES = [
package/dist/hooks.js CHANGED
@@ -352,6 +352,42 @@ export function useTheme() {
352
352
  return ctx.workspace.theme;
353
353
  }
354
354
 
355
+ /**
356
+ * Returns the active end-user identity:
357
+ * `{ id, email, displayName, roles, groupIds }`.
358
+ *
359
+ * `id` is `null` for anonymous visitors (and on the Studio canvas preview,
360
+ * which renders widgets as if signed-out so the public branch shows). All
361
+ * fields are guaranteed present by the host (`buildHostWidgetContext`
362
+ * + the native `WidgetHost`); widgets read them without optional chaining.
363
+ *
364
+ * Use this to render the signed-in user's name in a header, branch on
365
+ * roles, or stamp a created-by field. Email is opaque to widgets that
366
+ * only need a display name — prefer `displayName` for UI strings.
367
+ */
368
+ export function useUser() {
369
+ const ctx = useWidgetContextOrThrow("useUser");
370
+ return ctx.user;
371
+ }
372
+
373
+ /**
374
+ * Returns the host-provided navigation surface:
375
+ * `{ goTo, goBack, push, replace, back, currentRoute }`.
376
+ *
377
+ * `goTo(pageId, params?)` navigates to an internal app page. `goBack()`
378
+ * pops the stack. `push` / `replace` / `back` are aliases that map to
379
+ * the platform's native navigator (react-router on web, react-navigation
380
+ * on native). Missing methods degrade to no-ops on the Studio canvas
381
+ * preview, where there is no live router.
382
+ *
383
+ * For EXTERNAL URLs use the `Linking` primitive — `Linking.openURL(url)`
384
+ * works on both platforms.
385
+ */
386
+ export function useNavigation() {
387
+ const ctx = useWidgetContextOrThrow("useNavigation");
388
+ return ctx.navigation;
389
+ }
390
+
355
391
  /**
356
392
  * Structured error thrown by `usePayments` callbacks. Carries a stable
357
393
  * `code` so widgets can branch without parsing message strings.
package/dist/index.d.ts CHANGED
@@ -368,6 +368,45 @@ export function useI18n(): {
368
368
  t(key: string, fallback?: string): string;
369
369
  };
370
370
 
371
+ /**
372
+ * The active end-user identity. `id` is null for anonymous visitors and on
373
+ * the Studio canvas preview; every field is guaranteed present (the host
374
+ * fills safe defaults), so widgets read them without optional chaining.
375
+ */
376
+ export function useUser(): {
377
+ id: string | null;
378
+ email: string | null;
379
+ displayName: string | null;
380
+ roles: string[];
381
+ groupIds: string[];
382
+ };
383
+
384
+ /**
385
+ * The host-provided navigation surface. `goTo(pageId, params?)` navigates
386
+ * to an internal app page; `goBack()` pops the stack. Missing methods
387
+ * degrade to no-ops on the Studio canvas preview where no live router is
388
+ * mounted. For external URLs use the `Linking` primitive.
389
+ */
390
+ export function useNavigation(): {
391
+ goTo(pageId: string, params?: Record<string, unknown>): void;
392
+ goBack(): void;
393
+ push(pageId: string, params?: Record<string, unknown>): void;
394
+ replace(pageId: string, params?: Record<string, unknown>): void;
395
+ back(): void;
396
+ currentRoute: { pageId: string; params: Record<string, unknown> };
397
+ };
398
+
399
+ /**
400
+ * Static API for external URLs. `openURL(url)` opens a URL with the OS
401
+ * handler (web: react-native-web maps to `window.open` / `location.href`;
402
+ * native: hands off to the system). `canOpenURL` reports whether the
403
+ * scheme is registered.
404
+ */
405
+ export const Linking: {
406
+ openURL(url: string): Promise<unknown>;
407
+ canOpenURL(url: string): Promise<boolean>;
408
+ };
409
+
371
410
  /**
372
411
  * Error class thrown by useDatastoreMutation callbacks (and surfaced by
373
412
  * useDatastoreQuery in its `error` slot). The `code` is a stable
package/dist/index.js CHANGED
@@ -16,6 +16,8 @@ export {
16
16
  usePayments,
17
17
  useTheme,
18
18
  useI18n,
19
+ useUser,
20
+ useNavigation,
19
21
  } from "./hooks.js";
20
22
  export {
21
23
  Text,
@@ -29,6 +31,7 @@ export {
29
31
  ActivityIndicator,
30
32
  Switch,
31
33
  StyleSheet,
34
+ Linking,
32
35
  } from "./primitives.js";
33
36
  export { lintSource, bannedIdentifiers } from "./linter.js";
34
37
  export { CONTRACT, isHookAllowed, requiredContextKeys } from "./contract.js";
@@ -16,6 +16,8 @@ export {
16
16
  usePayments,
17
17
  useTheme,
18
18
  useI18n,
19
+ useUser,
20
+ useNavigation,
19
21
  } from "./hooks.js";
20
22
  export {
21
23
  Text,
@@ -29,6 +31,7 @@ export {
29
31
  ActivityIndicator,
30
32
  Switch,
31
33
  StyleSheet,
34
+ Linking,
32
35
  } from "./primitives.native.js";
33
36
  export { lintSource, bannedIdentifiers } from "./linter.js";
34
37
  export { CONTRACT, isHookAllowed, requiredContextKeys } from "./contract.js";
@@ -55,3 +55,8 @@ export const SectionList = ReactNative.SectionList;
55
55
  export const ActivityIndicator = ReactNative.ActivityIndicator;
56
56
  export const Switch = ReactNative.Switch;
57
57
  export const StyleSheet = ReactNative.StyleSheet;
58
+ // Static API (not a component): `Linking.openURL(url)` opens an external
59
+ // URL — on web react-native-web uses window.open / location.href, on native
60
+ // the OS hands it off to the system handler. `canOpenURL` reports whether
61
+ // the URL scheme is registered.
62
+ export const Linking = ReactNative.Linking;
@@ -18,4 +18,5 @@ export {
18
18
  ActivityIndicator,
19
19
  Switch,
20
20
  StyleSheet,
21
+ Linking,
21
22
  } from "react-native";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colixsystems/widget-sdk",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",