@xnetjs/react 2.1.0 → 2.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,7 +1,7 @@
1
1
  import {
2
2
  useMutate,
3
3
  useQuery
4
- } from "./chunk-ZGP56IIJ.js";
4
+ } from "./chunk-RW3DSDKO.js";
5
5
  import {
6
6
  XNetContext,
7
7
  downloadBackup,
@@ -9,7 +9,7 @@ import {
9
9
  useNodeStore,
10
10
  useSecurityContext,
11
11
  useXNet
12
- } from "./chunk-H44ZSIH4.js";
12
+ } from "./chunk-5ILJMPKO.js";
13
13
 
14
14
  // src/hooks/useTaskProjectionSync.ts
15
15
  import { ExternalReferenceSchema, TaskSchema, isCompletedTaskStatus } from "@xnetjs/data";
@@ -3398,9 +3398,18 @@ var TRANSITIONS = {
3398
3398
  AUTHENTICATE: "authenticating",
3399
3399
  CREATE_NEW: "authenticating",
3400
3400
  CREATE_RECOVERABLE: "creating-recoverable",
3401
+ CONTINUE_WITH_ATPROTO: "atproto-ceremony",
3401
3402
  IMPORT_EXISTING: "import-identity",
3402
3403
  BROWSER_UNSUPPORTED: "unsupported-browser"
3403
3404
  },
3405
+ "atproto-ceremony": {
3406
+ // The ceremony handler stores the linked handle (ATPROTO_LINKED, self-loop)
3407
+ // then runs the existing passkey-create flow → PASSKEY_SUCCESS.
3408
+ ATPROTO_LINKED: "atproto-ceremony",
3409
+ PASSKEY_SUCCESS: "connecting-hub",
3410
+ ATPROTO_CEREMONY_FAILED: "auth-error",
3411
+ BACK_TO_WELCOME: "welcome"
3412
+ },
3404
3413
  "creating-recoverable": {
3405
3414
  RECOVERABLE_CREATED: "show-recovery-phrase",
3406
3415
  PASSKEY_FAILED: "auth-error",
@@ -3478,6 +3487,16 @@ function onboardingReducer(current, event) {
3478
3487
  case "IMPORT_FAILED":
3479
3488
  nextContext.error = event.error;
3480
3489
  break;
3490
+ case "ATPROTO_LINKED":
3491
+ nextContext.atprotoDid = event.atprotoDid;
3492
+ nextContext.atprotoHandle = event.atprotoHandle;
3493
+ nextContext.atprotoDisplayName = event.displayName ?? null;
3494
+ nextContext.error = null;
3495
+ break;
3496
+ case "ATPROTO_CEREMONY_FAILED":
3497
+ nextContext.error = event.error;
3498
+ break;
3499
+ case "CONTINUE_WITH_ATPROTO":
3481
3500
  case "CREATE_RECOVERABLE":
3482
3501
  nextContext.error = null;
3483
3502
  break;
@@ -3504,7 +3523,10 @@ function createInitialState(hubUrl) {
3504
3523
  hubUrl: hubUrl ?? null,
3505
3524
  error: null,
3506
3525
  isDemo: false,
3507
- recoveryPhrase: null
3526
+ recoveryPhrase: null,
3527
+ atprotoDid: null,
3528
+ atprotoHandle: null,
3529
+ atprotoDisplayName: null
3508
3530
  }
3509
3531
  };
3510
3532
  }
@@ -3530,7 +3552,8 @@ var OnboardingCtx = createContext(null);
3530
3552
  function OnboardingProvider({
3531
3553
  children,
3532
3554
  defaultHubUrl = "wss://hub.xnet.fyi",
3533
- onComplete
3555
+ onComplete,
3556
+ runAtprotoCeremony
3534
3557
  }) {
3535
3558
  const [{ state, context }, dispatch] = useReducer(
3536
3559
  onboardingReducer,
@@ -3659,7 +3682,44 @@ function OnboardingProvider({
3659
3682
  },
3660
3683
  [state, manager]
3661
3684
  );
3662
- return /* @__PURE__ */ jsx6(OnboardingCtx.Provider, { value: { state, context, send }, children });
3685
+ const startAtprotoCeremony = useCallback18(
3686
+ (handleOrPds) => {
3687
+ if (!runAtprotoCeremony || authInFlight.current) return;
3688
+ authInFlight.current = true;
3689
+ runAtprotoCeremony({ handleOrPds }).then(async (result) => {
3690
+ dispatch({
3691
+ type: "ATPROTO_LINKED",
3692
+ atprotoDid: result.atprotoDid,
3693
+ atprotoHandle: result.atprotoHandle,
3694
+ displayName: result.displayName
3695
+ });
3696
+ const keyBundle = await manager.create();
3697
+ if (result.writeBinding) {
3698
+ await result.writeBinding(keyBundle.identity.did, keyBundle.signingKey);
3699
+ }
3700
+ dispatch({ type: "PASSKEY_SUCCESS", identity: keyBundle.identity, keyBundle });
3701
+ }).catch((err) => {
3702
+ dispatch({
3703
+ type: "ATPROTO_CEREMONY_FAILED",
3704
+ error: err instanceof Error ? err : new Error(String(err))
3705
+ });
3706
+ }).finally(() => {
3707
+ authInFlight.current = false;
3708
+ });
3709
+ },
3710
+ [runAtprotoCeremony, manager]
3711
+ );
3712
+ const value = useMemo14(
3713
+ () => ({
3714
+ state,
3715
+ context,
3716
+ send,
3717
+ atprotoEnabled: Boolean(runAtprotoCeremony),
3718
+ startAtprotoCeremony
3719
+ }),
3720
+ [state, context, send, runAtprotoCeremony, startAtprotoCeremony]
3721
+ );
3722
+ return /* @__PURE__ */ jsx6(OnboardingCtx.Provider, { value, children });
3663
3723
  }
3664
3724
  function useOnboarding() {
3665
3725
  const ctx = useContext7(OnboardingCtx);
@@ -3911,7 +3971,7 @@ function UnsupportedBrowserScreen() {
3911
3971
  // src/onboarding/screens/WelcomeScreen.tsx
3912
3972
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3913
3973
  function WelcomeScreen() {
3914
- const { send } = useOnboarding();
3974
+ const { send, atprotoEnabled } = useOnboarding();
3915
3975
  return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-background to-muted/30 text-foreground p-6", children: [
3916
3976
  /* @__PURE__ */ jsx13("div", { className: "w-16 h-16 mb-8 rounded-2xl bg-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsxs11(
3917
3977
  "svg",
@@ -3961,6 +4021,14 @@ function WelcomeScreen() {
3961
4021
  }
3962
4022
  ),
3963
4023
  /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground/70 text-center max-w-xs mt-2 mb-6", children: "Creates a secure passkey on your device. No passwords needed." }),
4024
+ atprotoEnabled && /* @__PURE__ */ jsx13(
4025
+ "button",
4026
+ {
4027
+ className: "text-sm text-muted-foreground hover:text-foreground transition-colors underline-offset-4 hover:underline mb-2",
4028
+ onClick: () => send({ type: "CONTINUE_WITH_ATPROTO" }),
4029
+ children: "Continue with Bluesky (or any PDS)"
4030
+ }
4031
+ ),
3964
4032
  /* @__PURE__ */ jsx13(
3965
4033
  "button",
3966
4034
  {
@@ -3980,13 +4048,81 @@ function WelcomeScreen() {
3980
4048
  ] });
3981
4049
  }
3982
4050
 
4051
+ // src/onboarding/screens/AtprotoCeremonyScreen.tsx
4052
+ import { useState as useState24 } from "react";
4053
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
4054
+ function AtprotoCeremonyScreen() {
4055
+ const { context, send, startAtprotoCeremony } = useOnboarding();
4056
+ const [handle, setHandle] = useState24("");
4057
+ const linked = Boolean(context.atprotoDid);
4058
+ const submit = () => {
4059
+ const value = handle.trim();
4060
+ if (value) startAtprotoCeremony(value);
4061
+ };
4062
+ return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-center justify-center min-h-screen bg-background text-foreground p-6", children: [
4063
+ /* @__PURE__ */ jsx14("h1", { className: "text-2xl font-semibold mb-2", children: "Continue with Bluesky" }),
4064
+ /* @__PURE__ */ jsx14("p", { className: "text-muted-foreground text-center mb-6 max-w-sm", children: "Sign in with your ATProto handle to claim a free global name. Works with Bluesky or any PDS." }),
4065
+ linked ? /* @__PURE__ */ jsxs12("p", { className: "text-sm text-muted-foreground mb-6", children: [
4066
+ "Linked ",
4067
+ /* @__PURE__ */ jsxs12("span", { className: "font-medium text-foreground", children: [
4068
+ "@",
4069
+ context.atprotoHandle
4070
+ ] }),
4071
+ " \u2014 finishing your passkey\u2026"
4072
+ ] }) : /* @__PURE__ */ jsxs12("div", { className: "w-full max-w-sm", children: [
4073
+ /* @__PURE__ */ jsx14("label", { htmlFor: "atproto-handle", className: "sr-only", children: "ATProto handle" }),
4074
+ /* @__PURE__ */ jsx14(
4075
+ "input",
4076
+ {
4077
+ id: "atproto-handle",
4078
+ type: "text",
4079
+ inputMode: "url",
4080
+ autoCapitalize: "none",
4081
+ autoCorrect: "off",
4082
+ spellCheck: false,
4083
+ placeholder: "alice.bsky.social",
4084
+ value: handle,
4085
+ onChange: (e) => setHandle(e.target.value),
4086
+ onKeyDown: (e) => {
4087
+ if (e.key === "Enter") submit();
4088
+ },
4089
+ className: "w-full px-4 py-3 rounded-lg border border-border bg-background mb-3"
4090
+ }
4091
+ ),
4092
+ /* @__PURE__ */ jsx14(
4093
+ "button",
4094
+ {
4095
+ onClick: submit,
4096
+ disabled: !handle.trim(),
4097
+ className: "w-full px-4 py-3 bg-primary text-primary-foreground rounded-lg font-medium disabled:opacity-50",
4098
+ children: "Continue"
4099
+ }
4100
+ )
4101
+ ] }),
4102
+ context.error && /* @__PURE__ */ jsx14("p", { className: "text-sm text-destructive mt-4 max-w-sm text-center", children: context.error.message }),
4103
+ /* @__PURE__ */ jsxs12("p", { className: "text-xs text-muted-foreground/80 text-center max-w-xs mt-6", children: [
4104
+ "Your Bluesky account gives you a global name. It does ",
4105
+ /* @__PURE__ */ jsx14("strong", { children: "not" }),
4106
+ " hold or recover your xNet keys unless you later enable it as a recovery anchor."
4107
+ ] }),
4108
+ /* @__PURE__ */ jsx14(
4109
+ "button",
4110
+ {
4111
+ className: "text-sm text-muted-foreground hover:text-foreground underline-offset-4 hover:underline mt-6",
4112
+ onClick: () => send({ type: "BACK_TO_WELCOME" }),
4113
+ children: "Back"
4114
+ }
4115
+ )
4116
+ ] });
4117
+ }
4118
+
3983
4119
  // src/onboarding/screens/GuardianRecoveryScreen.tsx
3984
4120
  import { parseShare as parseShare2 } from "@xnetjs/identity";
3985
- import { useMemo as useMemo15, useState as useState24 } from "react";
3986
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
4121
+ import { useMemo as useMemo15, useState as useState25 } from "react";
4122
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3987
4123
  function GuardianRecoveryScreen() {
3988
4124
  const { send, context } = useOnboarding();
3989
- const [text, setText] = useState24("");
4125
+ const [text, setText] = useState25("");
3990
4126
  const { validCodes, invalidCount, threshold } = useMemo15(() => {
3991
4127
  const lines = text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
3992
4128
  const valid = [];
@@ -4012,10 +4148,10 @@ function GuardianRecoveryScreen() {
4012
4148
  if (threshold !== null) return `${validCodes.length} of ${threshold} needed`;
4013
4149
  return `${validCodes.length} share${validCodes.length === 1 ? "" : "s"} pasted`;
4014
4150
  })();
4015
- return /* @__PURE__ */ jsxs12("div", { className: "flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground", children: [
4016
- /* @__PURE__ */ jsx14("h1", { className: "mb-2 text-2xl font-semibold", children: "Recover with your guardians" }),
4017
- /* @__PURE__ */ jsx14("p", { className: "mb-6 max-w-md text-center text-muted-foreground", children: "Paste the share codes your guardians gave you \u2014 one per line. You need enough of them to restore your identity; we\u2019ll tell you when you have enough." }),
4018
- /* @__PURE__ */ jsx14(
4151
+ return /* @__PURE__ */ jsxs13("div", { className: "flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground", children: [
4152
+ /* @__PURE__ */ jsx15("h1", { className: "mb-2 text-2xl font-semibold", children: "Recover with your guardians" }),
4153
+ /* @__PURE__ */ jsx15("p", { className: "mb-6 max-w-md text-center text-muted-foreground", children: "Paste the share codes your guardians gave you \u2014 one per line. You need enough of them to restore your identity; we\u2019ll tell you when you have enough." }),
4154
+ /* @__PURE__ */ jsx15(
4019
4155
  "textarea",
4020
4156
  {
4021
4157
  autoFocus: true,
@@ -4029,14 +4165,14 @@ function GuardianRecoveryScreen() {
4029
4165
  className: "mb-2 w-80 max-w-full resize-none rounded-lg border border-border bg-muted/30 p-3 font-mono text-xs outline-none focus:border-primary"
4030
4166
  }
4031
4167
  ),
4032
- /* @__PURE__ */ jsx14("div", { className: "mb-4 h-5 text-xs", children: /* @__PURE__ */ jsx14(
4168
+ /* @__PURE__ */ jsx15("div", { className: "mb-4 h-5 text-xs", children: /* @__PURE__ */ jsx15(
4033
4169
  "span",
4034
4170
  {
4035
4171
  className: context.error || invalidCount > 0 ? "text-destructive" : "text-muted-foreground",
4036
4172
  children: hint
4037
4173
  }
4038
4174
  ) }),
4039
- /* @__PURE__ */ jsx14(
4175
+ /* @__PURE__ */ jsx15(
4040
4176
  "button",
4041
4177
  {
4042
4178
  disabled: !canRecover,
@@ -4045,7 +4181,7 @@ function GuardianRecoveryScreen() {
4045
4181
  children: "Recover my identity"
4046
4182
  }
4047
4183
  ),
4048
- /* @__PURE__ */ jsx14(
4184
+ /* @__PURE__ */ jsx15(
4049
4185
  "button",
4050
4186
  {
4051
4187
  className: "text-sm text-muted-foreground transition-colors hover:text-foreground",
@@ -4058,11 +4194,11 @@ function GuardianRecoveryScreen() {
4058
4194
 
4059
4195
  // src/onboarding/screens/RecoveryPhraseScreen.tsx
4060
4196
  import { validateRecoveryPhrase } from "@xnetjs/identity";
4061
- import { useMemo as useMemo16, useState as useState25 } from "react";
4062
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
4197
+ import { useMemo as useMemo16, useState as useState26 } from "react";
4198
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4063
4199
  function RecoveryPhraseScreen() {
4064
4200
  const { send, context } = useOnboarding();
4065
- const [phrase, setPhrase] = useState25("");
4201
+ const [phrase, setPhrase] = useState26("");
4066
4202
  const validation = useMemo16(() => validateRecoveryPhrase(phrase), [phrase]);
4067
4203
  const empty = phrase.trim().length === 0;
4068
4204
  const hint = (() => {
@@ -4072,10 +4208,10 @@ function RecoveryPhraseScreen() {
4072
4208
  }
4073
4209
  return `Not in the wordlist: ${validation.unknownWords.join(", ")}`;
4074
4210
  })();
4075
- return /* @__PURE__ */ jsxs13("div", { className: "flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground", children: [
4076
- /* @__PURE__ */ jsx15("h1", { className: "mb-2 text-2xl font-semibold", children: "Enter your recovery phrase" }),
4077
- /* @__PURE__ */ jsx15("p", { className: "mb-6 max-w-md text-center text-muted-foreground", children: "Type the recovery phrase you saved. It restores the same identity and your encrypted data on this device." }),
4078
- /* @__PURE__ */ jsx15(
4211
+ return /* @__PURE__ */ jsxs14("div", { className: "flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground", children: [
4212
+ /* @__PURE__ */ jsx16("h1", { className: "mb-2 text-2xl font-semibold", children: "Enter your recovery phrase" }),
4213
+ /* @__PURE__ */ jsx16("p", { className: "mb-6 max-w-md text-center text-muted-foreground", children: "Type the recovery phrase you saved. It restores the same identity and your encrypted data on this device." }),
4214
+ /* @__PURE__ */ jsx16(
4079
4215
  "textarea",
4080
4216
  {
4081
4217
  autoFocus: true,
@@ -4089,11 +4225,11 @@ function RecoveryPhraseScreen() {
4089
4225
  className: "mb-2 w-80 max-w-full resize-none rounded-lg border border-border bg-muted/30 p-3 font-mono text-sm outline-none focus:border-primary"
4090
4226
  }
4091
4227
  ),
4092
- /* @__PURE__ */ jsxs13("div", { className: "mb-4 h-5 text-xs", children: [
4093
- hint && /* @__PURE__ */ jsx15("span", { className: "text-destructive", children: hint }),
4094
- context.error && !hint && /* @__PURE__ */ jsx15("span", { className: "text-destructive", children: context.error.message })
4228
+ /* @__PURE__ */ jsxs14("div", { className: "mb-4 h-5 text-xs", children: [
4229
+ hint && /* @__PURE__ */ jsx16("span", { className: "text-destructive", children: hint }),
4230
+ context.error && !hint && /* @__PURE__ */ jsx16("span", { className: "text-destructive", children: context.error.message })
4095
4231
  ] }),
4096
- /* @__PURE__ */ jsx15(
4232
+ /* @__PURE__ */ jsx16(
4097
4233
  "button",
4098
4234
  {
4099
4235
  disabled: !validation.ok,
@@ -4102,7 +4238,7 @@ function RecoveryPhraseScreen() {
4102
4238
  children: "Recover my identity"
4103
4239
  }
4104
4240
  ),
4105
- /* @__PURE__ */ jsx15(
4241
+ /* @__PURE__ */ jsx16(
4106
4242
  "button",
4107
4243
  {
4108
4244
  className: "text-sm text-muted-foreground transition-colors hover:text-foreground",
@@ -4114,12 +4250,12 @@ function RecoveryPhraseScreen() {
4114
4250
  }
4115
4251
 
4116
4252
  // src/onboarding/screens/ShowRecoveryPhraseScreen.tsx
4117
- import { useState as useState26 } from "react";
4118
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4253
+ import { useState as useState27 } from "react";
4254
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
4119
4255
  function ShowRecoveryPhraseScreen() {
4120
4256
  const { send, context } = useOnboarding();
4121
- const [saved, setSaved] = useState26(false);
4122
- const [copied, setCopied] = useState26(false);
4257
+ const [saved, setSaved] = useState27(false);
4258
+ const [copied, setCopied] = useState27(false);
4123
4259
  const phrase = context.recoveryPhrase ?? "";
4124
4260
  const words = phrase.split(" ").filter(Boolean);
4125
4261
  const copy = () => {
@@ -4128,14 +4264,14 @@ function ShowRecoveryPhraseScreen() {
4128
4264
  () => setCopied(false)
4129
4265
  );
4130
4266
  };
4131
- return /* @__PURE__ */ jsxs14("div", { className: "flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground", children: [
4132
- /* @__PURE__ */ jsx16("h1", { className: "mb-2 text-2xl font-semibold", children: "Save your recovery phrase" }),
4133
- /* @__PURE__ */ jsx16("p", { className: "mb-6 max-w-md text-center text-muted-foreground", children: "Write these words down and keep them somewhere safe. They are the only way to recover your workspace if you lose your passkey \u2014 we can\u2019t recover them for you." }),
4134
- /* @__PURE__ */ jsx16("ol", { className: "mb-3 grid w-80 max-w-full grid-cols-2 gap-x-6 gap-y-1 rounded-lg border border-border bg-muted/30 p-4 font-mono text-sm", children: words.map((word, i) => /* @__PURE__ */ jsxs14("li", { className: "flex gap-2", children: [
4135
- /* @__PURE__ */ jsx16("span", { className: "w-5 select-none text-right text-muted-foreground", children: i + 1 }),
4136
- /* @__PURE__ */ jsx16("span", { children: word })
4267
+ return /* @__PURE__ */ jsxs15("div", { className: "flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground", children: [
4268
+ /* @__PURE__ */ jsx17("h1", { className: "mb-2 text-2xl font-semibold", children: "Save your recovery phrase" }),
4269
+ /* @__PURE__ */ jsx17("p", { className: "mb-6 max-w-md text-center text-muted-foreground", children: "Write these words down and keep them somewhere safe. They are the only way to recover your workspace if you lose your passkey \u2014 we can\u2019t recover them for you." }),
4270
+ /* @__PURE__ */ jsx17("ol", { className: "mb-3 grid w-80 max-w-full grid-cols-2 gap-x-6 gap-y-1 rounded-lg border border-border bg-muted/30 p-4 font-mono text-sm", children: words.map((word, i) => /* @__PURE__ */ jsxs15("li", { className: "flex gap-2", children: [
4271
+ /* @__PURE__ */ jsx17("span", { className: "w-5 select-none text-right text-muted-foreground", children: i + 1 }),
4272
+ /* @__PURE__ */ jsx17("span", { children: word })
4137
4273
  ] }, `${i}-${word}`)) }),
4138
- /* @__PURE__ */ jsx16(
4274
+ /* @__PURE__ */ jsx17(
4139
4275
  "button",
4140
4276
  {
4141
4277
  className: "mb-5 text-xs text-muted-foreground transition-colors hover:text-foreground",
@@ -4143,8 +4279,8 @@ function ShowRecoveryPhraseScreen() {
4143
4279
  children: copied ? "Copied \u2713" : "Copy to clipboard"
4144
4280
  }
4145
4281
  ),
4146
- /* @__PURE__ */ jsxs14("label", { className: "mb-4 flex max-w-xs cursor-pointer items-start gap-2 text-sm text-muted-foreground", children: [
4147
- /* @__PURE__ */ jsx16(
4282
+ /* @__PURE__ */ jsxs15("label", { className: "mb-4 flex max-w-xs cursor-pointer items-start gap-2 text-sm text-muted-foreground", children: [
4283
+ /* @__PURE__ */ jsx17(
4148
4284
  "input",
4149
4285
  {
4150
4286
  type: "checkbox",
@@ -4155,7 +4291,7 @@ function ShowRecoveryPhraseScreen() {
4155
4291
  ),
4156
4292
  "I\u2019ve saved my recovery phrase somewhere safe."
4157
4293
  ] }),
4158
- /* @__PURE__ */ jsx16(
4294
+ /* @__PURE__ */ jsx17(
4159
4295
  "button",
4160
4296
  {
4161
4297
  disabled: !saved,
@@ -4168,52 +4304,54 @@ function ShowRecoveryPhraseScreen() {
4168
4304
  }
4169
4305
 
4170
4306
  // src/onboarding/OnboardingFlow.tsx
4171
- import { Fragment, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
4307
+ import { Fragment, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4172
4308
  function OnboardingFlow({ connectToHub, children }) {
4173
4309
  const { state } = useOnboarding();
4174
4310
  switch (state) {
4175
4311
  case "welcome":
4176
- return /* @__PURE__ */ jsx17(WelcomeScreen, {});
4312
+ return /* @__PURE__ */ jsx18(WelcomeScreen, {});
4177
4313
  case "authenticating":
4178
- return /* @__PURE__ */ jsx17(AuthenticatingScreen, {});
4314
+ return /* @__PURE__ */ jsx18(AuthenticatingScreen, {});
4179
4315
  case "auth-error":
4180
- return /* @__PURE__ */ jsx17(AuthErrorScreen, {});
4316
+ return /* @__PURE__ */ jsx18(AuthErrorScreen, {});
4181
4317
  case "unsupported-browser":
4182
- return /* @__PURE__ */ jsx17(UnsupportedBrowserScreen, {});
4318
+ return /* @__PURE__ */ jsx18(UnsupportedBrowserScreen, {});
4183
4319
  case "import-identity":
4184
- return /* @__PURE__ */ jsx17(ImportIdentityScreen, {});
4320
+ return /* @__PURE__ */ jsx18(ImportIdentityScreen, {});
4185
4321
  case "qr-scan":
4186
- return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-center justify-center min-h-screen bg-background text-foreground p-6", children: [
4187
- /* @__PURE__ */ jsx17("h1", { className: "text-2xl font-semibold mb-2", children: "QR Scan" }),
4188
- /* @__PURE__ */ jsx17("p", { className: "text-muted-foreground", children: "Coming soon \u2014 scan a QR code from another device." })
4322
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center justify-center min-h-screen bg-background text-foreground p-6", children: [
4323
+ /* @__PURE__ */ jsx18("h1", { className: "text-2xl font-semibold mb-2", children: "QR Scan" }),
4324
+ /* @__PURE__ */ jsx18("p", { className: "text-muted-foreground", children: "Coming soon \u2014 scan a QR code from another device." })
4189
4325
  ] });
4190
4326
  case "recovery-phrase":
4191
- return /* @__PURE__ */ jsx17(RecoveryPhraseScreen, {});
4327
+ return /* @__PURE__ */ jsx18(RecoveryPhraseScreen, {});
4192
4328
  case "guardian-recovery":
4193
- return /* @__PURE__ */ jsx17(GuardianRecoveryScreen, {});
4329
+ return /* @__PURE__ */ jsx18(GuardianRecoveryScreen, {});
4330
+ case "atproto-ceremony":
4331
+ return /* @__PURE__ */ jsx18(AtprotoCeremonyScreen, {});
4194
4332
  case "creating-recoverable":
4195
- return /* @__PURE__ */ jsx17(AuthenticatingScreen, {});
4333
+ return /* @__PURE__ */ jsx18(AuthenticatingScreen, {});
4196
4334
  case "show-recovery-phrase":
4197
- return /* @__PURE__ */ jsx17(ShowRecoveryPhraseScreen, {});
4335
+ return /* @__PURE__ */ jsx18(ShowRecoveryPhraseScreen, {});
4198
4336
  case "connecting-hub":
4199
- return /* @__PURE__ */ jsx17(HubConnectScreen, { connectToHub });
4337
+ return /* @__PURE__ */ jsx18(HubConnectScreen, { connectToHub });
4200
4338
  case "ready":
4201
- return /* @__PURE__ */ jsx17(ReadyScreen, {});
4339
+ return /* @__PURE__ */ jsx18(ReadyScreen, {});
4202
4340
  case "complete":
4203
- return /* @__PURE__ */ jsx17(Fragment, { children });
4341
+ return /* @__PURE__ */ jsx18(Fragment, { children });
4204
4342
  default:
4205
- return /* @__PURE__ */ jsx17(WelcomeScreen, {});
4343
+ return /* @__PURE__ */ jsx18(WelcomeScreen, {});
4206
4344
  }
4207
4345
  }
4208
4346
 
4209
4347
  // src/onboarding/screens/SmartWelcome.tsx
4210
4348
  import { discoverExistingPasskey } from "@xnetjs/identity";
4211
- import { useEffect as useEffect20, useState as useState27 } from "react";
4212
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4349
+ import { useEffect as useEffect20, useState as useState28 } from "react";
4350
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4213
4351
  function SmartWelcome() {
4214
4352
  const { send } = useOnboarding();
4215
- const [checking, setChecking] = useState27(true);
4216
- const [hasExisting, setHasExisting] = useState27(false);
4353
+ const [checking, setChecking] = useState28(true);
4354
+ const [hasExisting, setHasExisting] = useState28(false);
4217
4355
  useEffect20(() => {
4218
4356
  let cancelled = false;
4219
4357
  discoverExistingPasskey().then((passkey) => {
@@ -4231,31 +4369,31 @@ function SmartWelcome() {
4231
4369
  };
4232
4370
  }, []);
4233
4371
  if (checking) {
4234
- return /* @__PURE__ */ jsx18("div", { className: "onboarding-screen", children: /* @__PURE__ */ jsx18("p", { className: "spinner-text", children: "Checking for existing identity..." }) });
4372
+ return /* @__PURE__ */ jsx19("div", { className: "onboarding-screen", children: /* @__PURE__ */ jsx19("p", { className: "spinner-text", children: "Checking for existing identity..." }) });
4235
4373
  }
4236
4374
  if (hasExisting) {
4237
4375
  const authName = getPlatformAuthName();
4238
- return /* @__PURE__ */ jsxs16("div", { className: "onboarding-screen welcome-back", children: [
4239
- /* @__PURE__ */ jsx18("h1", { children: "Welcome back!" }),
4240
- /* @__PURE__ */ jsxs16("p", { className: "subtitle", children: [
4376
+ return /* @__PURE__ */ jsxs17("div", { className: "onboarding-screen welcome-back", children: [
4377
+ /* @__PURE__ */ jsx19("h1", { children: "Welcome back!" }),
4378
+ /* @__PURE__ */ jsxs17("p", { className: "subtitle", children: [
4241
4379
  "We found your xNet identity. Use ",
4242
4380
  authName,
4243
4381
  " to sign in."
4244
4382
  ] }),
4245
- /* @__PURE__ */ jsxs16("button", { className: "primary-button", onClick: () => send({ type: "AUTHENTICATE" }), children: [
4383
+ /* @__PURE__ */ jsxs17("button", { className: "primary-button", onClick: () => send({ type: "AUTHENTICATE" }), children: [
4246
4384
  "Sign in with ",
4247
4385
  authName
4248
4386
  ] }),
4249
- /* @__PURE__ */ jsx18("button", { className: "text-button", onClick: () => send({ type: "CREATE_NEW" }), children: "Create a new identity instead" })
4387
+ /* @__PURE__ */ jsx19("button", { className: "text-button", onClick: () => send({ type: "CREATE_NEW" }), children: "Create a new identity instead" })
4250
4388
  ] });
4251
4389
  }
4252
- return /* @__PURE__ */ jsx18(WelcomeScreen, {});
4390
+ return /* @__PURE__ */ jsx19(WelcomeScreen, {});
4253
4391
  }
4254
4392
 
4255
4393
  // src/onboarding/screens/SyncProgressOverlay.tsx
4256
4394
  import { formatBytes as formatBytes2 } from "@xnetjs/core";
4257
4395
  import { useEffect as useEffect21 } from "react";
4258
- import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4396
+ import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
4259
4397
  function SyncProgressOverlay({
4260
4398
  progress,
4261
4399
  onComplete
@@ -4266,14 +4404,14 @@ function SyncProgressOverlay({
4266
4404
  return () => clearTimeout(timer);
4267
4405
  }
4268
4406
  }, [progress.phase, onComplete]);
4269
- return /* @__PURE__ */ jsx19("div", { className: "sync-progress-overlay", children: /* @__PURE__ */ jsxs17("div", { className: "sync-card", children: [
4270
- progress.phase === "connecting" && /* @__PURE__ */ jsxs17(Fragment2, { children: [
4271
- /* @__PURE__ */ jsx19("h2", { children: "Connecting to server..." }),
4272
- /* @__PURE__ */ jsx19("p", { className: "spinner-text", children: "Please wait" })
4407
+ return /* @__PURE__ */ jsx20("div", { className: "sync-progress-overlay", children: /* @__PURE__ */ jsxs18("div", { className: "sync-card", children: [
4408
+ progress.phase === "connecting" && /* @__PURE__ */ jsxs18(Fragment2, { children: [
4409
+ /* @__PURE__ */ jsx20("h2", { children: "Connecting to server..." }),
4410
+ /* @__PURE__ */ jsx20("p", { className: "spinner-text", children: "Please wait" })
4273
4411
  ] }),
4274
- progress.phase === "syncing" && /* @__PURE__ */ jsxs17(Fragment2, { children: [
4275
- /* @__PURE__ */ jsx19("h2", { children: "Syncing your data" }),
4276
- /* @__PURE__ */ jsx19("div", { className: "progress-bar", children: /* @__PURE__ */ jsx19(
4412
+ progress.phase === "syncing" && /* @__PURE__ */ jsxs18(Fragment2, { children: [
4413
+ /* @__PURE__ */ jsx20("h2", { children: "Syncing your data" }),
4414
+ /* @__PURE__ */ jsx20("div", { className: "progress-bar", children: /* @__PURE__ */ jsx20(
4277
4415
  "div",
4278
4416
  {
4279
4417
  className: "progress-fill",
@@ -4282,29 +4420,29 @@ function SyncProgressOverlay({
4282
4420
  }
4283
4421
  }
4284
4422
  ) }),
4285
- /* @__PURE__ */ jsxs17("p", { className: "progress-text", children: [
4423
+ /* @__PURE__ */ jsxs18("p", { className: "progress-text", children: [
4286
4424
  progress.roomsSynced,
4287
4425
  " of ",
4288
4426
  progress.roomsTotal,
4289
4427
  " items"
4290
4428
  ] }),
4291
- /* @__PURE__ */ jsxs17("p", { className: "bytes-text", children: [
4429
+ /* @__PURE__ */ jsxs18("p", { className: "bytes-text", children: [
4292
4430
  formatBytes2(progress.bytesReceived),
4293
4431
  " received"
4294
4432
  ] })
4295
4433
  ] }),
4296
- progress.phase === "complete" && /* @__PURE__ */ jsxs17(Fragment2, { children: [
4297
- /* @__PURE__ */ jsx19("h2", { children: "All synced!" }),
4298
- /* @__PURE__ */ jsxs17("p", { children: [
4434
+ progress.phase === "complete" && /* @__PURE__ */ jsxs18(Fragment2, { children: [
4435
+ /* @__PURE__ */ jsx20("h2", { children: "All synced!" }),
4436
+ /* @__PURE__ */ jsxs18("p", { children: [
4299
4437
  progress.roomsTotal,
4300
4438
  " items synchronized"
4301
4439
  ] })
4302
4440
  ] }),
4303
- progress.phase === "error" && /* @__PURE__ */ jsxs17(Fragment2, { children: [
4304
- /* @__PURE__ */ jsx19("h2", { children: "Sync issue" }),
4305
- /* @__PURE__ */ jsx19("p", { children: "Some data may not be up to date." }),
4306
- progress.error && /* @__PURE__ */ jsx19("p", { className: "error-detail", children: progress.error.message }),
4307
- /* @__PURE__ */ jsx19("button", { className: "primary-button", onClick: onComplete, children: "Continue anyway" })
4441
+ progress.phase === "error" && /* @__PURE__ */ jsxs18(Fragment2, { children: [
4442
+ /* @__PURE__ */ jsx20("h2", { children: "Sync issue" }),
4443
+ /* @__PURE__ */ jsx20("p", { children: "Some data may not be up to date." }),
4444
+ progress.error && /* @__PURE__ */ jsx20("p", { className: "error-detail", children: progress.error.message }),
4445
+ /* @__PURE__ */ jsx20("button", { className: "primary-button", onClick: onComplete, children: "Continue anyway" })
4308
4446
  ] })
4309
4447
  ] }) });
4310
4448
  }
@@ -4369,60 +4507,60 @@ function isTaskOverdue(timestamp, completed) {
4369
4507
 
4370
4508
  // src/components/PageTasksPanel.tsx
4371
4509
  import { Calendar, CheckSquare2, ChevronDown, ChevronRight, Square, Users } from "lucide-react";
4372
- import { useMemo as useMemo17, useState as useState28 } from "react";
4373
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
4510
+ import { useMemo as useMemo17, useState as useState29 } from "react";
4511
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
4374
4512
  function PageTasksPanel({ pageId }) {
4375
- const [expanded, setExpanded] = useState28(true);
4513
+ const [expanded, setExpanded] = useState29(true);
4376
4514
  const { tree, loading } = useTasks({ pageId });
4377
4515
  const rows = useMemo17(() => flattenTaskTree(tree), [tree]);
4378
- return /* @__PURE__ */ jsxs18("div", { className: "mt-8 overflow-hidden rounded-lg border border-border", children: [
4379
- /* @__PURE__ */ jsx20(
4516
+ return /* @__PURE__ */ jsxs19("div", { className: "mt-8 overflow-hidden rounded-lg border border-border", children: [
4517
+ /* @__PURE__ */ jsx21(
4380
4518
  "button",
4381
4519
  {
4382
4520
  className: "w-full cursor-pointer border-none bg-secondary p-3 px-4 text-left",
4383
4521
  onClick: () => setExpanded((value) => !value),
4384
4522
  type: "button",
4385
- children: /* @__PURE__ */ jsxs18("h3", { className: "m-0 flex items-center justify-between text-sm font-semibold text-foreground", children: [
4386
- /* @__PURE__ */ jsxs18("span", { children: [
4523
+ children: /* @__PURE__ */ jsxs19("h3", { className: "m-0 flex items-center justify-between text-sm font-semibold text-foreground", children: [
4524
+ /* @__PURE__ */ jsxs19("span", { children: [
4387
4525
  "Tasks on this page (",
4388
4526
  rows.length,
4389
4527
  ")"
4390
4528
  ] }),
4391
- expanded ? /* @__PURE__ */ jsx20(ChevronDown, { size: 16, className: "text-muted-foreground" }) : /* @__PURE__ */ jsx20(ChevronRight, { size: 16, className: "text-muted-foreground" })
4529
+ expanded ? /* @__PURE__ */ jsx21(ChevronDown, { size: 16, className: "text-muted-foreground" }) : /* @__PURE__ */ jsx21(ChevronRight, { size: 16, className: "text-muted-foreground" })
4392
4530
  ] })
4393
4531
  }
4394
4532
  ),
4395
- expanded && /* @__PURE__ */ jsx20("div", { className: "p-3", children: loading ? /* @__PURE__ */ jsx20("p", { className: "m-0 text-sm text-muted-foreground", children: "Loading tasks..." }) : rows.length === 0 ? /* @__PURE__ */ jsx20("p", { className: "m-0 text-sm text-muted-foreground", children: "Checklist items on this page will appear here." }) : /* @__PURE__ */ jsx20("ul", { className: "m-0 list-none space-y-1 p-0", children: rows.map((task) => {
4533
+ expanded && /* @__PURE__ */ jsx21("div", { className: "p-3", children: loading ? /* @__PURE__ */ jsx21("p", { className: "m-0 text-sm text-muted-foreground", children: "Loading tasks..." }) : rows.length === 0 ? /* @__PURE__ */ jsx21("p", { className: "m-0 text-sm text-muted-foreground", children: "Checklist items on this page will appear here." }) : /* @__PURE__ */ jsx21("ul", { className: "m-0 list-none space-y-1 p-0", children: rows.map((task) => {
4396
4534
  const dueDateLabel = formatTaskDueDate(task.dueDate);
4397
4535
  const overdue = isTaskOverdue(task.dueDate, task.completed);
4398
- return /* @__PURE__ */ jsx20("li", { children: /* @__PURE__ */ jsxs18(
4536
+ return /* @__PURE__ */ jsx21("li", { children: /* @__PURE__ */ jsxs19(
4399
4537
  "div",
4400
4538
  {
4401
4539
  className: "flex items-start gap-2 rounded-md px-2 py-2 transition-colors hover:bg-accent/40",
4402
4540
  style: { paddingLeft: `${task.depth * 18 + 8}px` },
4403
4541
  children: [
4404
- task.completed ? /* @__PURE__ */ jsx20(CheckSquare2, { size: 15, className: "mt-0.5 flex-shrink-0 text-primary" }) : /* @__PURE__ */ jsx20(Square, { size: 15, className: "mt-0.5 flex-shrink-0 text-muted-foreground" }),
4405
- /* @__PURE__ */ jsxs18("div", { className: "min-w-0 flex-1", children: [
4406
- /* @__PURE__ */ jsx20(
4542
+ task.completed ? /* @__PURE__ */ jsx21(CheckSquare2, { size: 15, className: "mt-0.5 flex-shrink-0 text-primary" }) : /* @__PURE__ */ jsx21(Square, { size: 15, className: "mt-0.5 flex-shrink-0 text-muted-foreground" }),
4543
+ /* @__PURE__ */ jsxs19("div", { className: "min-w-0 flex-1", children: [
4544
+ /* @__PURE__ */ jsx21(
4407
4545
  "div",
4408
4546
  {
4409
4547
  className: `text-sm ${task.completed ? "line-through text-muted-foreground" : "text-foreground"}`,
4410
4548
  children: task.title
4411
4549
  }
4412
4550
  ),
4413
- /* @__PURE__ */ jsxs18("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground", children: [
4414
- dueDateLabel ? /* @__PURE__ */ jsxs18(
4551
+ /* @__PURE__ */ jsxs19("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground", children: [
4552
+ dueDateLabel ? /* @__PURE__ */ jsxs19(
4415
4553
  "span",
4416
4554
  {
4417
4555
  className: `inline-flex items-center gap-1 ${overdue ? "text-red-500" : "text-muted-foreground"}`,
4418
4556
  children: [
4419
- /* @__PURE__ */ jsx20(Calendar, { size: 11 }),
4557
+ /* @__PURE__ */ jsx21(Calendar, { size: 11 }),
4420
4558
  dueDateLabel
4421
4559
  ]
4422
4560
  }
4423
4561
  ) : null,
4424
- task.assigneeCount > 0 ? /* @__PURE__ */ jsxs18("span", { className: "inline-flex items-center gap-1", children: [
4425
- /* @__PURE__ */ jsx20(Users, { size: 11 }),
4562
+ task.assigneeCount > 0 ? /* @__PURE__ */ jsxs19("span", { className: "inline-flex items-center gap-1", children: [
4563
+ /* @__PURE__ */ jsx21(Users, { size: 11 }),
4426
4564
  task.assigneeCount
4427
4565
  ] }) : null
4428
4566
  ] })
@@ -4436,7 +4574,7 @@ function PageTasksPanel({ pageId }) {
4436
4574
 
4437
4575
  // src/components/TaskCollectionEmbed.tsx
4438
4576
  import { useMemo as useMemo18 } from "react";
4439
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
4577
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
4440
4578
  function TaskCollectionEmbed({
4441
4579
  currentPageId,
4442
4580
  currentDid,
@@ -4469,33 +4607,33 @@ function TaskCollectionEmbed({
4469
4607
  }));
4470
4608
  }, [data, showHierarchy, tree]);
4471
4609
  if (missingPageContext) {
4472
- return /* @__PURE__ */ jsx21("div", { className: "p-4 text-sm text-muted-foreground", children: "This view needs a page context." });
4610
+ return /* @__PURE__ */ jsx22("div", { className: "p-4 text-sm text-muted-foreground", children: "This view needs a page context." });
4473
4611
  }
4474
4612
  if (loading) {
4475
- return /* @__PURE__ */ jsx21("div", { className: "p-4 text-sm text-muted-foreground", children: "Loading tasks..." });
4613
+ return /* @__PURE__ */ jsx22("div", { className: "p-4 text-sm text-muted-foreground", children: "Loading tasks..." });
4476
4614
  }
4477
4615
  if (rows.length === 0) {
4478
- return /* @__PURE__ */ jsx21("div", { className: "p-4 text-sm text-muted-foreground", children: "No tasks match the saved filters for this view." });
4616
+ return /* @__PURE__ */ jsx22("div", { className: "p-4 text-sm text-muted-foreground", children: "No tasks match the saved filters for this view." });
4479
4617
  }
4480
- return /* @__PURE__ */ jsx21("div", { className: "p-3", children: /* @__PURE__ */ jsx21("ul", { className: "m-0 list-none space-y-1 p-0", children: rows.map((task) => {
4618
+ return /* @__PURE__ */ jsx22("div", { className: "p-3", children: /* @__PURE__ */ jsx22("ul", { className: "m-0 list-none space-y-1 p-0", children: rows.map((task) => {
4481
4619
  const dueDateLabel = formatTaskDueDate(task.dueDate);
4482
4620
  const overdue = isTaskOverdue(task.dueDate, task.completed);
4483
- return /* @__PURE__ */ jsx21("li", { children: /* @__PURE__ */ jsxs19(
4621
+ return /* @__PURE__ */ jsx22("li", { children: /* @__PURE__ */ jsxs20(
4484
4622
  "div",
4485
4623
  {
4486
4624
  className: "flex items-start gap-2 rounded-lg px-2 py-2 hover:bg-accent/40",
4487
4625
  style: { paddingLeft: `${task.depth * 18 + 8}px` },
4488
4626
  children: [
4489
- /* @__PURE__ */ jsx21("span", { className: task.completed ? "text-primary" : "text-muted-foreground", children: task.completed ? "\u2611" : "\u2610" }),
4490
- /* @__PURE__ */ jsxs19("div", { className: "min-w-0 flex-1", children: [
4491
- /* @__PURE__ */ jsx21(
4627
+ /* @__PURE__ */ jsx22("span", { className: task.completed ? "text-primary" : "text-muted-foreground", children: task.completed ? "\u2611" : "\u2610" }),
4628
+ /* @__PURE__ */ jsxs20("div", { className: "min-w-0 flex-1", children: [
4629
+ /* @__PURE__ */ jsx22(
4492
4630
  "div",
4493
4631
  {
4494
4632
  className: task.completed ? "truncate text-sm text-muted-foreground line-through" : "truncate text-sm text-foreground",
4495
4633
  children: task.title
4496
4634
  }
4497
4635
  ),
4498
- dueDateLabel ? /* @__PURE__ */ jsx21(
4636
+ dueDateLabel ? /* @__PURE__ */ jsx22(
4499
4637
  "div",
4500
4638
  {
4501
4639
  className: overdue ? "mt-1 text-[11px] text-red-500" : "mt-1 text-[11px] text-muted-foreground",