@hook-sdk/template 0.10.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/dist/index.cjs CHANGED
@@ -153,7 +153,12 @@ var AppConfigSchema = import_zod.z.object({
153
153
  persistedKeys: import_zod.z.array(PersistedKeySchema),
154
154
  onboarding: OnboardingSchema.optional(),
155
155
  deepLinks: DeepLinksSchema.optional(),
156
- features_enabled: import_zod.z.array(import_zod.z.string()).optional()
156
+ features_enabled: import_zod.z.array(import_zod.z.string()).optional(),
157
+ // Build-time injected theme metadata (e.g. icon_url for InstallSplash).
158
+ // Apps don't author this directly; deploy workflows fill it from
159
+ // env-resolved bundle host. Permissive shape so apps/workflows can
160
+ // extend without re-bumping the template schema.
161
+ theme: import_zod.z.object({}).passthrough().optional()
157
162
  }).strict();
158
163
  function parseAppConfig(input) {
159
164
  const r = AppConfigSchema.safeParse(input);
@@ -1829,8 +1834,15 @@ var ErrorBoundary = class extends import_react9.Component {
1829
1834
  static getDerivedStateFromError(error) {
1830
1835
  return { error };
1831
1836
  }
1832
- componentDidCatch(error) {
1833
- console.error("[ErrorBoundary] caught", error);
1837
+ componentDidCatch(error, info) {
1838
+ console.error(
1839
+ "[ErrorBoundary] caught:",
1840
+ error?.message || "(no message)",
1841
+ "\nstack:",
1842
+ error?.stack || "(no stack)",
1843
+ "\ncomponentStack:",
1844
+ info?.componentStack || "(no componentStack)"
1845
+ );
1834
1846
  }
1835
1847
  render() {
1836
1848
  if (this.state.error) {
@@ -2604,62 +2616,82 @@ function useOnboardingStep() {
2604
2616
  // src/OnboardingFlow.tsx
2605
2617
  var import_jsx_runtime24 = require("react/jsx-runtime");
2606
2618
  var isFilled = (v) => v != null && v !== "";
2619
+ var CURRENT_STEP_FIELD = "currentStep";
2620
+ function readPersistedStepIdx(draft) {
2621
+ const raw = draft[CURRENT_STEP_FIELD];
2622
+ return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? raw : 0;
2623
+ }
2607
2624
  function OnboardingFlow({
2608
2625
  steps,
2609
2626
  screens,
2610
2627
  onComplete,
2611
2628
  persistKey
2612
2629
  }) {
2613
- const [draft, setDraft] = (0, import_sdk16.usePersistedState)(persistKey, {});
2614
- const [idx, setIdx] = (0, import_react21.useState)(0);
2630
+ const [draft, setDraft, status] = (0, import_sdk16.usePersistedState)(persistKey, {});
2615
2631
  const draftRef = (0, import_react21.useRef)(draft);
2616
2632
  draftRef.current = draft;
2617
- const step = steps[idx];
2618
- if (!step) {
2619
- throw new Error(
2620
- `[hook-template] OnboardingFlow: step index ${idx} out of range (steps.length=${steps.length})`
2621
- );
2622
- }
2623
- const Screen = screens[step.screen];
2624
- if (!Screen) {
2625
- throw new Error(
2626
- `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
2627
- );
2628
- }
2629
- const valid = (0, import_react21.useMemo)(
2630
- () => (step.validates ?? []).every((field) => isFilled(draft[field])),
2631
- [draft, step]
2633
+ const idx = readPersistedStepIdx(draft);
2634
+ const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2635
+ const setIdx = (0, import_react21.useCallback)(
2636
+ (n) => {
2637
+ setDraft((prev) => {
2638
+ const prevIdx = readPersistedStepIdx(prev);
2639
+ const nextIdx = typeof n === "function" ? n(prevIdx) : n;
2640
+ return { ...prev, [CURRENT_STEP_FIELD]: nextIdx };
2641
+ });
2642
+ },
2643
+ [setDraft]
2632
2644
  );
2633
2645
  const setValue = (0, import_react21.useCallback)(
2634
2646
  (patch) => {
2635
2647
  draftRef.current = { ...draftRef.current, ...patch };
2636
- setDraft((prev2) => ({ ...prev2, ...patch }));
2648
+ setDraft((prev) => ({ ...prev, ...patch }));
2637
2649
  },
2638
2650
  [setDraft]
2639
2651
  );
2652
+ const step = steps[clampedIdx];
2653
+ const valid = (0, import_react21.useMemo)(
2654
+ () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
2655
+ [draft, step]
2656
+ );
2640
2657
  const next = (0, import_react21.useCallback)(() => {
2658
+ if (!step) return;
2641
2659
  const current = draftRef.current;
2642
2660
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
2643
2661
  if (!validNow) return;
2644
- if (idx + 1 >= steps.length) {
2662
+ if (clampedIdx + 1 >= steps.length) {
2645
2663
  onComplete(current);
2646
2664
  } else {
2647
- setIdx(idx + 1);
2665
+ setIdx(clampedIdx + 1);
2648
2666
  }
2649
- }, [idx, onComplete, step, steps.length]);
2650
- const prev = (0, import_react21.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), []);
2667
+ }, [clampedIdx, onComplete, step, steps.length, setIdx]);
2668
+ const prevStep = (0, import_react21.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2651
2669
  const ctx = (0, import_react21.useMemo)(
2652
2670
  () => ({
2653
- stepIndex: idx,
2671
+ stepIndex: clampedIdx,
2654
2672
  totalSteps: steps.length,
2655
2673
  value: draft,
2656
2674
  setValue,
2657
2675
  valid,
2658
2676
  next,
2659
- prev
2677
+ prev: prevStep
2660
2678
  }),
2661
- [idx, steps.length, draft, setValue, valid, next, prev]
2679
+ [clampedIdx, steps.length, draft, setValue, valid, next, prevStep]
2662
2680
  );
2681
+ if (status.loading) {
2682
+ return null;
2683
+ }
2684
+ if (!step) {
2685
+ throw new Error(
2686
+ `[hook-template] OnboardingFlow: step index ${clampedIdx} out of range (steps.length=${steps.length})`
2687
+ );
2688
+ }
2689
+ const Screen = screens[step.screen];
2690
+ if (!Screen) {
2691
+ throw new Error(
2692
+ `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
2693
+ );
2694
+ }
2663
2695
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Screen, {}) });
2664
2696
  }
2665
2697