wizards 0.4.0 → 0.4.2

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.
Files changed (124) hide show
  1. package/apps/runtime/dist/agents/studio-assistant.js +67 -20
  2. package/apps/runtime/dist/docs/dev/plugins/reference.md +7 -4
  3. package/apps/runtime/dist/docs/dev/plugins/reloading.md +3 -3
  4. package/apps/runtime/dist/docs/dev/plugins/runners.md +9 -12
  5. package/apps/runtime/dist/docs/dev/plugins/server.md +3 -1
  6. package/apps/runtime/dist/docs/dev/plugins/space.md +19 -1
  7. package/apps/runtime/dist/docs/dev/plugins/studio.md +43 -6
  8. package/apps/runtime/dist/docs/dev/plugins/styling.md +8 -1
  9. package/apps/runtime/dist/docs/user/space.md +4 -4
  10. package/apps/runtime/dist/docs/user/test-and-share.md +22 -58
  11. package/apps/runtime/dist/engine/steps.js +3 -2
  12. package/apps/runtime/dist/engine/template.js +14 -10
  13. package/apps/runtime/dist/film/project.js +15 -3
  14. package/apps/runtime/dist/plugins/loader.js +38 -2
  15. package/apps/runtime/dist/routes/studio.js +28 -1
  16. package/apps/runtime/dist/services/brand.js +61 -1
  17. package/apps/runtime/dist/services/projects.js +19 -10
  18. package/apps/runtime/dist/tools/plugin.js +11 -3
  19. package/apps/web/dist/assets/AboutDialog-CH1rQdia.js +1 -0
  20. package/apps/web/dist/assets/{ChangelogDialog-DynvQuuR.js → ChangelogDialog-78MQLHfA.js} +1 -1
  21. package/apps/web/dist/assets/ChatView-DLJfy69U.js +10 -0
  22. package/apps/web/dist/assets/EditorPage-BYrZokVk.js +3 -0
  23. package/apps/web/dist/assets/{FlowPreview-BZLnG7GV.js → FlowPreview-xIWPdOCV.js} +1 -1
  24. package/apps/web/dist/assets/{Harness-CNh3nbB_.js → Harness-CsDhNLSW.js} +2 -2
  25. package/apps/web/dist/assets/NewWizardChannels-JB3V6DCL.js +1 -0
  26. package/apps/web/dist/assets/NewWizardPage-Bkh-hjSe.js +7 -0
  27. package/apps/web/dist/assets/OnboardingPage-Diw1ILjC.js +1 -0
  28. package/apps/web/dist/assets/ProjectPage-FgoZDzPI.js +1 -0
  29. package/apps/web/dist/assets/PublicRunner-ClT6B7t5.js +1 -0
  30. package/apps/web/dist/assets/{ReadOnly-DTjv2Jzm.js → ReadOnly-DQPHmvS0.js} +1 -1
  31. package/apps/web/dist/assets/RunDrawer-DAwTEyjM.js +4 -0
  32. package/apps/web/dist/assets/{RunnerView-BPPmlv9z.js → RunnerView-B_tJroFM.js} +1 -1
  33. package/apps/web/dist/assets/SettingsPage-BsMN-XQs.js +1 -0
  34. package/apps/web/dist/assets/SetupPage-C7FuIpSt.js +1 -0
  35. package/apps/web/dist/assets/SharePage-CbFe83L9.js +1 -0
  36. package/apps/web/dist/assets/changelog-mYclku73.js +1 -0
  37. package/apps/web/dist/assets/{circle-alert-CVOH4wAv.js → circle-alert-DCBV7n5k.js} +1 -1
  38. package/apps/web/dist/assets/{esm-BfXdeWaI.js → esm-BhIeKBJY.js} +1 -1
  39. package/apps/web/dist/assets/index-CmxVazOf.css +1 -0
  40. package/apps/web/dist/assets/index-fflYi8P1.js +14 -0
  41. package/apps/web/dist/assets/{lock-DHBh62LA.js → lock-DlzTfwxP.js} +1 -1
  42. package/apps/web/dist/assets/{phone-Bt1cyWpY.js → phone-BFD815nc.js} +1 -1
  43. package/apps/web/dist/assets/{settings-menu-ace1vI3i.js → settings-menu-C5Y8SOhG.js} +1 -1
  44. package/apps/web/dist/assets/ui-DTuixH4y.js +134 -0
  45. package/apps/web/dist/assets/{upload-CCEq88l4.js → upload-BEf5-d6X.js} +1 -1
  46. package/apps/web/dist/index.html +4 -5
  47. package/apps/web/dist/mcp/flow.html +2 -2
  48. package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +36 -2
  49. package/node_modules/@engenty-wizards/plugin-sdk/dist/studio.d.ts +44 -1
  50. package/node_modules/@engenty-wizards/shared/dist/feature-flags.d.ts +18 -0
  51. package/node_modules/@engenty-wizards/shared/dist/feature-flags.js +18 -0
  52. package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +22 -6
  53. package/node_modules/@engenty-wizards/shared/dist/projects.js +20 -0
  54. package/package.json +1 -1
  55. package/apps/web/dist/assets/AboutDialog-CPQiN7H9.js +0 -1
  56. package/apps/web/dist/assets/ChatView-CKo_9IZD.js +0 -10
  57. package/apps/web/dist/assets/EditorPage-CDIJXC4T.js +0 -3
  58. package/apps/web/dist/assets/NewWizardChannels-C1Ss9UMY.js +0 -1
  59. package/apps/web/dist/assets/NewWizardPage-2qLAbvDL.js +0 -7
  60. package/apps/web/dist/assets/OnboardingPage-C1FJwEsT.js +0 -1
  61. package/apps/web/dist/assets/ProjectPage-CGuLUuOs.js +0 -1
  62. package/apps/web/dist/assets/PublicRunner-BKw1lOW4.js +0 -1
  63. package/apps/web/dist/assets/RunDrawer-D1I5xqVf.js +0 -4
  64. package/apps/web/dist/assets/SettingsPage-zbomQfGy.js +0 -1
  65. package/apps/web/dist/assets/SetupPage-D3F7M6Pz.js +0 -1
  66. package/apps/web/dist/assets/SharePage-BY49IJgT.js +0 -1
  67. package/apps/web/dist/assets/changelog-DYZC2E6q.js +0 -1
  68. package/apps/web/dist/assets/index-B9xVkr2X.css +0 -1
  69. package/apps/web/dist/assets/index-BH0PYgov.js +0 -15
  70. package/apps/web/dist/assets/logo-C4V2_3Ar.js +0 -1
  71. package/apps/web/dist/assets/ui-D2SqIZeQ.js +0 -133
  72. package/modules/calls/dist/client.css +0 -3
  73. package/modules/calls/dist/client.js +0 -1
  74. package/modules/calls/engenty.plugin.json +0 -8
  75. package/modules/calls/migrations/0001_init.sql +0 -26
  76. package/modules/calls/package.json +0 -25
  77. package/modules/calls/src/openai.ts +0 -155
  78. package/modules/calls/src/plugin.ts +0 -407
  79. package/modules/calls/src/rules.ts +0 -226
  80. package/modules/calls/src/schema.ts +0 -39
  81. package/modules/calls/src/session.ts +0 -353
  82. package/modules/calls/src/store.ts +0 -124
  83. package/modules/calls/src/twilio.ts +0 -90
  84. package/modules/calls/tsconfig.json +0 -10
  85. package/modules/calls/ui/Settings.tsx +0 -137
  86. package/modules/calls/ui/app.ts +0 -50
  87. package/modules/calls/ui/messages.ts +0 -81
  88. package/modules/calls/ui/parts.tsx +0 -36
  89. package/modules/calls/ui/plugin.tsx +0 -15
  90. package/modules/sms/dist/client.css +0 -3
  91. package/modules/sms/dist/client.js +0 -1
  92. package/modules/sms/engenty.plugin.json +0 -8
  93. package/modules/sms/migrations/0001_init.sql +0 -26
  94. package/modules/sms/package.json +0 -24
  95. package/modules/sms/src/plugin.ts +0 -329
  96. package/modules/sms/src/schema.ts +0 -26
  97. package/modules/sms/src/store.ts +0 -140
  98. package/modules/sms/src/surface.ts +0 -70
  99. package/modules/sms/src/twilio.ts +0 -130
  100. package/modules/sms/tsconfig.json +0 -10
  101. package/modules/sms/ui/Settings.tsx +0 -113
  102. package/modules/sms/ui/Share.tsx +0 -60
  103. package/modules/sms/ui/app.ts +0 -51
  104. package/modules/sms/ui/messages.ts +0 -70
  105. package/modules/sms/ui/parts.tsx +0 -36
  106. package/modules/sms/ui/plugin.tsx +0 -20
  107. package/modules/whatsapp/dist/client.css +0 -3
  108. package/modules/whatsapp/dist/client.js +0 -1
  109. package/modules/whatsapp/engenty.plugin.json +0 -8
  110. package/modules/whatsapp/migrations/0001_init.sql +0 -30
  111. package/modules/whatsapp/package.json +0 -24
  112. package/modules/whatsapp/src/graph.ts +0 -271
  113. package/modules/whatsapp/src/inbound.ts +0 -143
  114. package/modules/whatsapp/src/plugin.ts +0 -374
  115. package/modules/whatsapp/src/schema.ts +0 -32
  116. package/modules/whatsapp/src/store.ts +0 -156
  117. package/modules/whatsapp/src/surface.ts +0 -127
  118. package/modules/whatsapp/tsconfig.json +0 -10
  119. package/modules/whatsapp/ui/Settings.tsx +0 -141
  120. package/modules/whatsapp/ui/Share.tsx +0 -60
  121. package/modules/whatsapp/ui/app.ts +0 -54
  122. package/modules/whatsapp/ui/messages.ts +0 -80
  123. package/modules/whatsapp/ui/parts.tsx +0 -36
  124. package/modules/whatsapp/ui/plugin.tsx +0 -20
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "jsx": "react-jsx",
5
- "lib": ["ES2023", "DOM", "DOM.Iterable"],
6
- "types": ["node"],
7
- "noEmit": true
8
- },
9
- "include": ["src", "ui"]
10
- }
@@ -1,113 +0,0 @@
1
- import { Button, Card, Input, Label, Spinner } from "@engenty-wizards/web/ui";
2
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
- import { useEffect, useState } from "react";
4
- import { type AccountView, api, errorText, KEY, t } from "./app";
5
- import { Shown } from "./parts";
6
-
7
- /** Settings → SMS: the Twilio account, the number, and the address to enter in Twilio. */
8
- export function SettingsSection() {
9
- const cache = useQueryClient();
10
- const account = useQuery({
11
- queryKey: [KEY, "account"],
12
- queryFn: () => api().get<AccountView>("/account"),
13
- });
14
- const [form, setForm] = useState({ accountSid: "", number: "", authToken: "" });
15
- const [to, setTo] = useState("");
16
- useEffect(() => {
17
- if (account.data) {
18
- setForm((f) => ({ ...f, accountSid: account.data.accountSid, number: account.data.number }));
19
- }
20
- }, [account.data]);
21
- const refresh = () => cache.invalidateQueries({ queryKey: [KEY] });
22
- const save = useMutation({
23
- mutationFn: () =>
24
- api().put<AccountView>("/account", {
25
- accountSid: form.accountSid,
26
- number: form.number,
27
- authToken: form.authToken || undefined,
28
- }),
29
- onSuccess: async () => {
30
- setForm((f) => ({ ...f, authToken: "" }));
31
- await refresh();
32
- },
33
- });
34
- const remove = useMutation({
35
- mutationFn: () => api().del<AccountView>("/account"),
36
- onSuccess: refresh,
37
- });
38
- const test = useMutation({
39
- mutationFn: () => api().post<{ ok: boolean }>("/account/test", { to }),
40
- });
41
- const set = (key: keyof typeof form) => (e: React.ChangeEvent<HTMLInputElement>) =>
42
- setForm((f) => ({ ...f, [key]: e.target.value }));
43
- const data = account.data;
44
- return (
45
- <section className="flex flex-col gap-2.5">
46
- <h2 className="px-1 font-display font-semibold text-lg leading-tight">{t("title")}</h2>
47
- <Card className="flex flex-col gap-4 p-5 text-[0.875rem]">
48
- <p className="text-[0.8125rem] text-ink-3">{t("intro")}</p>
49
- {account.isLoading ? <Spinner className="mx-auto" /> : null}
50
- <div>
51
- <Label hint={t("accountSidHint")}>{t("accountSid")}</Label>
52
- <Input value={form.accountSid} onChange={set("accountSid")} autoComplete="off" />
53
- </div>
54
- <div>
55
- <Label hint={data?.hasToken ? t("tokenKept") : t("tokenHint")}>{t("token")}</Label>
56
- <Input
57
- type="password"
58
- value={form.authToken}
59
- onChange={set("authToken")}
60
- placeholder={data?.hasToken ? "••••••••" : ""}
61
- autoComplete="new-password"
62
- />
63
- </div>
64
- <div>
65
- <Label hint={t("numberHint")}>{t("number")}</Label>
66
- <Input value={form.number} onChange={set("number")} inputMode="tel" />
67
- </div>
68
- <div className="flex items-center gap-3">
69
- <Button onClick={() => save.mutate()} busy={save.isPending}>
70
- {t("save")}
71
- </Button>
72
- {data?.connected ? (
73
- <Button variant="ghost" onClick={() => remove.mutate()} busy={remove.isPending}>
74
- {t("disconnect")}
75
- </Button>
76
- ) : null}
77
- {save.isSuccess ? (
78
- <span className="text-[0.8125rem] text-ink-3">{t("saved")}</span>
79
- ) : null}
80
- </div>
81
- {save.error ? <p className="text-[0.8125rem] text-rose">{errorText(save.error)}</p> : null}
82
- </Card>
83
- {data?.connected ? (
84
- <Card className="flex flex-col gap-4 p-5 text-[0.875rem]">
85
- <div className="font-medium">{t("twilio")}</div>
86
- <p className="text-[0.8125rem] text-ink-3">{t("twilioHint")}</p>
87
- <Shown label={t("webhook")} value={data.webhook} />
88
- <div>
89
- <Label>{t("testTo")}</Label>
90
- <div className="flex items-center gap-2">
91
- <Input
92
- value={to}
93
- onChange={(e) => setTo(e.target.value)}
94
- placeholder="+43 660 …"
95
- inputMode="tel"
96
- className="max-w-xs"
97
- />
98
- <Button variant="secondary" onClick={() => test.mutate()} busy={test.isPending}>
99
- {t("sendTest")}
100
- </Button>
101
- </div>
102
- {test.isSuccess ? (
103
- <p className="mt-2 text-[0.8125rem] text-ink-3">{t("testSent")}</p>
104
- ) : null}
105
- {test.error ? (
106
- <p className="mt-2 text-[0.8125rem] text-rose">{errorText(test.error)}</p>
107
- ) : null}
108
- </div>
109
- </Card>
110
- ) : null}
111
- </section>
112
- );
113
- }
@@ -1,60 +0,0 @@
1
- import type { StudioShareSectionProps } from "@engenty-wizards/plugin-sdk/studio";
2
- import { Input } from "@engenty-wizards/web/ui";
3
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
- import { useState } from "react";
5
- import { api, type Binding, errorText, KEY, t } from "./app";
6
-
7
- /**
8
- * In the share dialog's settings, while SMS is on: the keyword that picks the wizard. Its
9
- * number, its link and the QR code the dialog shows itself, from the runner's address.
10
- */
11
- export function ShareSection({ wizard }: StudioShareSectionProps) {
12
- const cache = useQueryClient();
13
- const binding = useQuery({
14
- queryKey: [KEY, "binding", wizard.id],
15
- queryFn: () => api().get<Binding>(`/binding/${wizard.id}`),
16
- });
17
- const [draft, setDraft] = useState<string | null>(null);
18
- const save = useMutation({
19
- mutationFn: (keyword: string) => api().put<Binding>(`/binding/${wizard.id}`, { keyword }),
20
- onSuccess: async () => {
21
- setDraft(null);
22
- // The dialog's row shows the keyword and the link that writes it.
23
- await Promise.all([
24
- cache.invalidateQueries({ queryKey: [KEY, "binding", wizard.id] }),
25
- cache.invalidateQueries({ queryKey: ["wizard-runners", wizard.id] }),
26
- ]);
27
- },
28
- });
29
- if (!binding.data) {
30
- return null;
31
- }
32
- const keyword = draft ?? binding.data.keyword;
33
- const commit = () => {
34
- if (draft?.trim() && draft.trim() !== binding.data?.keyword) {
35
- save.mutate(draft);
36
- } else {
37
- setDraft(null);
38
- }
39
- };
40
- return (
41
- <div className="flex flex-col gap-1.5">
42
- <label className="flex flex-col gap-1.5">
43
- <span className="font-medium text-[0.875rem]">{t("keyword")}</span>
44
- <Input
45
- value={keyword}
46
- onChange={(e) => setDraft(e.target.value)}
47
- onBlur={commit}
48
- onKeyDown={(e) => {
49
- if (e.key === "Enter") {
50
- e.currentTarget.blur();
51
- }
52
- }}
53
- className="max-w-xs"
54
- />
55
- </label>
56
- <p className="text-[0.8125rem] text-ink-3">{t("keywordHint")}</p>
57
- {save.error ? <p className="text-[0.8125rem] text-rose">{errorText(save.error)}</p> : null}
58
- </div>
59
- );
60
- }
@@ -1,51 +0,0 @@
1
- import type { StudioPluginContext } from "@engenty-wizards/plugin-sdk/studio";
2
- import { messages } from "./messages";
3
-
4
- /** The studio this half was handed, and its words. */
5
-
6
- let current: StudioPluginContext | null = null;
7
- let translate: ((key: string, vars?: Record<string, string | number>) => string) | null = null;
8
-
9
- export function setStudio(studio: StudioPluginContext) {
10
- current = studio;
11
- translate = studio.i18n.register(messages) as typeof translate;
12
- }
13
-
14
- export function studio(): StudioPluginContext {
15
- if (!current) {
16
- throw new Error("The SMS plugin is not loaded.");
17
- }
18
- return current;
19
- }
20
-
21
- export type Key = keyof (typeof messages)["de"];
22
- export const t = (key: Key, vars?: Record<string, string | number>) =>
23
- translate?.(key, vars) ?? key;
24
- export const api = () => studio().api;
25
-
26
- export const KEY = "sms";
27
-
28
- /** What a failed request says, in the person's language. */
29
- export function errorText(error: unknown): string {
30
- const body = (error as { body?: { code?: string; error?: string } } | null)?.body;
31
- const code = body?.code;
32
- const message = body?.error ?? (error instanceof Error ? error.message : String(error));
33
- if (code && `error_${code}` in messages.de) {
34
- return t(`error_${code}` as Key, { message });
35
- }
36
- return t("error_other", { message });
37
- }
38
-
39
- export interface AccountView {
40
- connected: boolean;
41
- accountSid: string;
42
- number: string;
43
- hasToken: boolean;
44
- webhook: string;
45
- }
46
-
47
- export interface Binding {
48
- keyword: string;
49
- link: string | null;
50
- number: string | null;
51
- }
@@ -1,70 +0,0 @@
1
- /** The studio half's words. `de` is the source. */
2
- export const messages = {
3
- de: {
4
- title: "SMS",
5
- intro:
6
- "Wizards laufen per SMS auf der eigenen Nummer: eine Frage pro Nachricht, Auswahl als Nummern, Bilder und Dateien als Link. Dafür braucht es ein Twilio-Konto mit einer SMS-fähigen Nummer.",
7
- accountSid: "Account SID",
8
- accountSidHint: "Aus der Twilio-Konsole, beginnt mit AC.",
9
- token: "Auth Token",
10
- tokenHint:
11
- "Der Auth Token des Kontos. Damit wird auch jede Nachricht von Twilio auf ihre Signatur geprüft.",
12
- tokenKept: "Ist hinterlegt. Leer lassen, um ihn zu behalten.",
13
- number: "Nummer",
14
- numberHint: "Die Twilio-Nummer, von der die Texte kommen, mit Ländervorwahl: +43660…",
15
- save: "Speichern",
16
- saved: "Gespeichert.",
17
- disconnect: "Trennen",
18
- twilio: "In Twilio eintragen",
19
- twilioHint:
20
- "Bei der Nummer unter Messaging → „A message comes in“: diese Adresse, als Webhook mit HTTP POST.",
21
- webhook: "Webhook-Adresse",
22
- copy: "Kopieren",
23
- copied: "Kopiert",
24
- testTo: "Test-SMS an",
25
- sendTest: "Senden",
26
- testSent: "Angekommen? Dann passt alles.",
27
- keyword: "Stichwort",
28
- keywordHint:
29
- "Wer dieses Wort an die Nummer schreibt, startet den Wizard. Der Link und der QR-Code tippen es vor.",
30
- error_bad_keyword:
31
- "Ein Stichwort besteht aus Buchstaben, Ziffern, Leerzeichen und Bindestrichen, bis zu 40.",
32
- error_keyword_taken: "Ein anderer Wizard hat dieses Stichwort schon.",
33
- error_no_token: "Es braucht einen Auth Token.",
34
- error_provider: "Twilio hat die Nachricht nicht angenommen: {message}",
35
- error_other: "{message}",
36
- },
37
- en: {
38
- title: "SMS",
39
- intro:
40
- "Wizards run by text message on your own number: one question per text, choices as numbers, pictures and files as links. It takes a Twilio account with a number that can text.",
41
- accountSid: "Account SID",
42
- accountSidHint: "From the Twilio console, starts with AC.",
43
- token: "Auth token",
44
- tokenHint:
45
- "The account's auth token. It also checks every message from Twilio for its signature.",
46
- tokenKept: "Is set. Leave empty to keep it.",
47
- number: "Number",
48
- numberHint: "The Twilio number the texts come from, with the country code: +43660…",
49
- save: "Save",
50
- saved: "Saved.",
51
- disconnect: "Disconnect",
52
- twilio: "Enter in Twilio",
53
- twilioHint:
54
- "On the number under Messaging → “A message comes in”: this address, as a webhook with HTTP POST.",
55
- webhook: "Webhook address",
56
- copy: "Copy",
57
- copied: "Copied",
58
- testTo: "Test text to",
59
- sendTest: "Send",
60
- testSent: "Arrived? Then everything is set.",
61
- keyword: "Keyword",
62
- keywordHint:
63
- "Whoever texts this word to the number starts the wizard. The link and the QR code type it for them.",
64
- error_bad_keyword: "A keyword is letters, digits, spaces and dashes, up to 40.",
65
- error_keyword_taken: "Another wizard has this keyword already.",
66
- error_no_token: "An auth token is needed.",
67
- error_provider: "Twilio did not take the message: {message}",
68
- error_other: "{message}",
69
- },
70
- } as const;
@@ -1,36 +0,0 @@
1
- import { IconButton } from "@engenty-wizards/web/ui";
2
- import { Check, Copy } from "lucide-react";
3
- import { useState } from "react";
4
- import { t } from "./app";
5
-
6
- /** A value to take along: the webhook address, the verify token, the link. */
7
- export function CopyButton({ text }: { text: string }) {
8
- const [done, setDone] = useState(false);
9
- return (
10
- <IconButton
11
- label={t(done ? "copied" : "copy")}
12
- className="size-8"
13
- onClick={() => {
14
- void navigator.clipboard.writeText(text).then(() => {
15
- setDone(true);
16
- setTimeout(() => setDone(false), 1500);
17
- });
18
- }}
19
- >
20
- {done ? <Check className="size-4" /> : <Copy className="size-4" />}
21
- </IconButton>
22
- );
23
- }
24
-
25
- /** A value shown as it is, with the button that copies it. */
26
- export function Shown({ label, value }: { label: string; value: string }) {
27
- return (
28
- <div className="flex items-center gap-2">
29
- <div className="min-w-0 flex-1">
30
- <div className="text-[0.8125rem] text-ink-3">{label}</div>
31
- <div className="select-all truncate font-mono text-[0.8125rem]">{value}</div>
32
- </div>
33
- <CopyButton text={value} />
34
- </div>
35
- );
36
- }
@@ -1,20 +0,0 @@
1
- import { defineStudioPlugin } from "@engenty-wizards/plugin-sdk/studio";
2
- import { MessageSquareText } from "lucide-react";
3
- import { setStudio, t } from "./app";
4
- import { SettingsSection } from "./Settings";
5
- import { ShareSection } from "./Share";
6
-
7
- /**
8
- * The studio half: the Twilio account and the number in the settings, and the keyword with
9
- * its link under the SMS row of the share dialog. Everything talks to src/plugin.ts.
10
- */
11
- export default defineStudioPlugin((studio) => {
12
- setStudio(studio);
13
- studio.registerSettingsSection({
14
- id: "sms",
15
- label: () => t("title"),
16
- icon: MessageSquareText,
17
- component: SettingsSection,
18
- });
19
- studio.registerShareSection({ runner: "sms", component: ShareSection });
20
- });
@@ -1,3 +0,0 @@
1
- /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-content:"";--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer wizards-plugin{[data-plugin=whatsapp] .pointer-events-none{pointer-events:none}[data-plugin=whatsapp] .absolute{position:absolute}[data-plugin=whatsapp] .fixed{position:fixed}[data-plugin=whatsapp] .relative{position:relative}[data-plugin=whatsapp] .-top-1\.5{top:-.375rem}[data-plugin=whatsapp] .top-0\.5{top:.125rem}[data-plugin=whatsapp] .top-1\/2{top:50%}[data-plugin=whatsapp] .-right-1\.5{right:-.375rem}[data-plugin=whatsapp] .right-2{right:.5rem}[data-plugin=whatsapp] .right-3{right:.75rem}[data-plugin=whatsapp] .bottom-0\.5{bottom:.125rem}[data-plugin=whatsapp] .bottom-1{bottom:.25rem}[data-plugin=whatsapp] .left-0{left:0}[data-plugin=whatsapp] .left-1\/2{left:50%}[data-plugin=whatsapp] .z-50{z-index:50}[data-plugin=whatsapp] .m-auto{margin:auto}[data-plugin=whatsapp] .-mx-1{margin-inline:-.25rem}[data-plugin=whatsapp] .mx-auto{margin-inline:auto}[data-plugin=whatsapp] .my-1\.5{margin-block:.375rem}[data-plugin=whatsapp] .-mt-1\.5{margin-top:-.375rem}[data-plugin=whatsapp] .mt-0\.5{margin-top:.125rem}[data-plugin=whatsapp] .mt-2{margin-top:.5rem}[data-plugin=whatsapp] .-mr-2{margin-right:-.5rem}[data-plugin=whatsapp] .mr-0\.5{margin-right:.125rem}[data-plugin=whatsapp] .mb-2{margin-bottom:.5rem}[data-plugin=whatsapp] .mb-5{margin-bottom:1.25rem}[data-plugin=whatsapp] .-ml-1\.5{margin-left:-.375rem}[data-plugin=whatsapp] .ml-1{margin-left:.25rem}[data-plugin=whatsapp] .flex{display:flex}[data-plugin=whatsapp] .grid{display:grid}[data-plugin=whatsapp] .hidden{display:none}[data-plugin=whatsapp] .inline-block{display:inline-block}[data-plugin=whatsapp] .inline-flex{display:inline-flex}[data-plugin=whatsapp] .size-1{width:.25rem;height:.25rem}[data-plugin=whatsapp] .size-1\.5{width:.375rem;height:.375rem}[data-plugin=whatsapp] .size-3{width:.75rem;height:.75rem}[data-plugin=whatsapp] .size-3\.5{width:.875rem;height:.875rem}[data-plugin=whatsapp] .size-4{width:1rem;height:1rem}[data-plugin=whatsapp] .size-5{width:1.25rem;height:1.25rem}[data-plugin=whatsapp] .size-6{width:1.5rem;height:1.5rem}[data-plugin=whatsapp] .size-7{width:1.75rem;height:1.75rem}[data-plugin=whatsapp] .size-8{width:2rem;height:2rem}[data-plugin=whatsapp] .size-9{width:2.25rem;height:2.25rem}[data-plugin=whatsapp] .size-11{width:2.75rem;height:2.75rem}[data-plugin=whatsapp] .size-16{width:4rem;height:4rem}[data-plugin=whatsapp] .h-6{height:1.5rem}[data-plugin=whatsapp] .h-8{height:2rem}[data-plugin=whatsapp] .h-9{height:2.25rem}[data-plugin=whatsapp] .h-10{height:2.5rem}[data-plugin=whatsapp] .h-11{height:2.75rem}[data-plugin=whatsapp] .h-12{height:3rem}[data-plugin=whatsapp] .h-px{height:1px}[data-plugin=whatsapp] .max-h-56{max-height:14rem}[data-plugin=whatsapp] .max-h-\[200px\]{max-height:200px}[data-plugin=whatsapp] .max-h-\[calc\(100dvh-32px\)\]{max-height:calc(100dvh - 32px)}[data-plugin=whatsapp] .min-h-9{min-height:2.25rem}[data-plugin=whatsapp] .w-5{width:1.25rem}[data-plugin=whatsapp] .w-11{width:2.75rem}[data-plugin=whatsapp] .w-14{width:3.5rem}[data-plugin=whatsapp] .w-72{width:18rem}[data-plugin=whatsapp] .w-\[19rem\]{width:19rem}[data-plugin=whatsapp] .w-\[calc\(100\%-32px\)\]{width:calc(100% - 32px)}[data-plugin=whatsapp] .w-\[calc\(100\%-48px\)\]{width:calc(100% - 48px)}[data-plugin=whatsapp] .w-full{width:100%}[data-plugin=whatsapp] .w-px{width:1px}[data-plugin=whatsapp] .max-w-\[calc\(100vw-2rem\)\]{max-width:calc(100vw - 2rem)}[data-plugin=whatsapp] .max-w-\[calc\(100vw-16px\)\]{max-width:calc(100vw - 16px)}[data-plugin=whatsapp] .max-w-full{max-width:100%}[data-plugin=whatsapp] .max-w-xs{max-width:20rem}[data-plugin=whatsapp] .min-w-0{min-width:0}[data-plugin=whatsapp] .flex-1{flex:1}[data-plugin=whatsapp] .shrink-0{flex-shrink:0}[data-plugin=whatsapp] .-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}[data-plugin=whatsapp] .translate-x-\[2px\]{--tw-translate-x:2px;translate:var(--tw-translate-x) var(--tw-translate-y)}[data-plugin=whatsapp] .translate-x-\[22px\]{--tw-translate-x:22px;translate:var(--tw-translate-x) var(--tw-translate-y)}[data-plugin=whatsapp] .-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}[data-plugin=whatsapp] .rotate-180{rotate:180deg}[data-plugin=whatsapp] .transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}[data-plugin=whatsapp] .animate-spin{animation:1s linear infinite spin}[data-plugin=whatsapp] .cursor-pointer{cursor:pointer}[data-plugin=whatsapp] .touch-none{touch-action:none}[data-plugin=whatsapp] .resize{resize:both}[data-plugin=whatsapp] .resize-none{resize:none}[data-plugin=whatsapp] .\[scrollbar-width\:none\]{scrollbar-width:none}[data-plugin=whatsapp] .appearance-none{appearance:none}[data-plugin=whatsapp] .grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}[data-plugin=whatsapp] .flex-col{flex-direction:column}[data-plugin=whatsapp] .flex-wrap{flex-wrap:wrap}[data-plugin=whatsapp] .place-items-center{place-items:center}[data-plugin=whatsapp] .items-center{align-items:center}[data-plugin=whatsapp] .items-end{align-items:flex-end}[data-plugin=whatsapp] .items-start{align-items:flex-start}[data-plugin=whatsapp] .justify-between{justify-content:space-between}[data-plugin=whatsapp] .justify-center{justify-content:center}[data-plugin=whatsapp] .gap-0\.5{gap:.125rem}[data-plugin=whatsapp] .gap-1{gap:.25rem}[data-plugin=whatsapp] .gap-1\.5{gap:.375rem}[data-plugin=whatsapp] .gap-2{gap:.5rem}[data-plugin=whatsapp] .gap-2\.5{gap:.625rem}[data-plugin=whatsapp] .gap-3{gap:.75rem}[data-plugin=whatsapp] .gap-4{gap:1rem}[data-plugin=whatsapp] .gap-y-0\.5{row-gap:.125rem}[data-plugin=whatsapp] .self-stretch{align-self:stretch}[data-plugin=whatsapp] .truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}[data-plugin=whatsapp] .overflow-visible{overflow:visible}[data-plugin=whatsapp] .overflow-x-auto{overflow-x:auto}[data-plugin=whatsapp] .overflow-y-auto{overflow-y:auto}[data-plugin=whatsapp] .overscroll-contain{overscroll-behavior:contain}[data-plugin=whatsapp] .rounded-2xl{border-radius:calc(var(--radius) * 2)}[data-plugin=whatsapp] .rounded-\[1\.375rem\]{border-radius:1.375rem}[data-plugin=whatsapp] .rounded-full{border-radius:2147483647px}[data-plugin=whatsapp] .rounded-lg{border-radius:var(--radius)}[data-plugin=whatsapp] .rounded-md{border-radius:calc(var(--radius) * .75)}[data-plugin=whatsapp] .rounded-xl{border-radius:calc(var(--radius) * 1.5)}[data-plugin=whatsapp] .border{border-style:var(--tw-border-style);border-width:1px}[data-plugin=whatsapp] .border-t{border-top-style:var(--tw-border-style);border-top-width:1px}[data-plugin=whatsapp] .border-border{border-color:var(--border)}[data-plugin=whatsapp] .border-border-soft{border-color:var(--border-soft)}[data-plugin=whatsapp] .border-ember{border-color:var(--ember-mark)}[data-plugin=whatsapp] .border-focus{border-color:var(--focus-line)}[data-plugin=whatsapp] .border-input{border-color:var(--input)}[data-plugin=whatsapp] .bg-amber-tint{background-color:var(--amber-tint)}[data-plugin=whatsapp] .bg-border-soft{background-color:var(--border-soft)}[data-plugin=whatsapp] .bg-card{background-color:var(--card)}[data-plugin=whatsapp] .bg-ember{background-color:var(--ember-mark)}[data-plugin=whatsapp] .bg-ember-tint{background-color:var(--ember-tint)}[data-plugin=whatsapp] .bg-ink{background-color:var(--ink)}[data-plugin=whatsapp] .bg-moss{background-color:var(--moss)}[data-plugin=whatsapp] .bg-moss-tint{background-color:var(--moss-tint)}[data-plugin=whatsapp] .bg-paper-2{background-color:var(--paper-2)}[data-plugin=whatsapp] .bg-paper-3{background-color:var(--paper-3)}[data-plugin=whatsapp] .bg-primary{background-color:var(--primary)}[data-plugin=whatsapp] .bg-rose-tint{background-color:var(--rose-tint)}[data-plugin=whatsapp] .bg-transparent{background-color:#0000}[data-plugin=whatsapp] .bg-white{background-color:#fff}[data-plugin=whatsapp] .bg-linear-to-l{--tw-gradient-position:to left}@supports (background-image:linear-gradient(in lab, red, red)){[data-plugin=whatsapp] .bg-linear-to-l{--tw-gradient-position:to left in oklab}}[data-plugin=whatsapp] .bg-linear-to-l{background-image:linear-gradient(var(--tw-gradient-stops))}[data-plugin=whatsapp] .bg-linear-to-r{--tw-gradient-position:to right}@supports (background-image:linear-gradient(in lab, red, red)){[data-plugin=whatsapp] .bg-linear-to-r{--tw-gradient-position:to right in oklab}}[data-plugin=whatsapp] .bg-linear-to-r{background-image:linear-gradient(var(--tw-gradient-stops))}[data-plugin=whatsapp] .from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}[data-plugin=whatsapp] .from-50\%{--tw-gradient-from-position:50%}[data-plugin=whatsapp] .to-ember-tint{--tw-gradient-to:var(--ember-tint);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}[data-plugin=whatsapp] .to-50\%{--tw-gradient-to-position:50%}[data-plugin=whatsapp] .fill-current{fill:currentColor}[data-plugin=whatsapp] .object-cover{object-fit:cover}[data-plugin=whatsapp] .p-0{padding:0}[data-plugin=whatsapp] .p-0\.5{padding:.125rem}[data-plugin=whatsapp] .p-1{padding:.25rem}[data-plugin=whatsapp] .p-1\.5{padding:.375rem}[data-plugin=whatsapp] .p-3{padding:.75rem}[data-plugin=whatsapp] .p-5{padding:1.25rem}[data-plugin=whatsapp] .px-1{padding-inline:.25rem}[data-plugin=whatsapp] .px-2{padding-inline:.5rem}[data-plugin=whatsapp] .px-2\.5{padding-inline:.625rem}[data-plugin=whatsapp] .px-3{padding-inline:.75rem}[data-plugin=whatsapp] .px-3\.5{padding-inline:.875rem}[data-plugin=whatsapp] .px-4{padding-inline:1rem}[data-plugin=whatsapp] .px-6{padding-inline:1.5rem}[data-plugin=whatsapp] .py-1{padding-block:.25rem}[data-plugin=whatsapp] .py-1\.5{padding-block:.375rem}[data-plugin=whatsapp] .py-2{padding-block:.5rem}[data-plugin=whatsapp] .py-2\.5{padding-block:.625rem}[data-plugin=whatsapp] .py-16{padding-block:4rem}[data-plugin=whatsapp] .pt-1\.5{padding-top:.375rem}[data-plugin=whatsapp] .pt-2{padding-top:.5rem}[data-plugin=whatsapp] .pr-1{padding-right:.25rem}[data-plugin=whatsapp] .pr-9{padding-right:2.25rem}[data-plugin=whatsapp] .pb-1{padding-bottom:.25rem}[data-plugin=whatsapp] .pl-2{padding-left:.5rem}[data-plugin=whatsapp] .pl-2\.5{padding-left:.625rem}[data-plugin=whatsapp] .text-center{text-align:center}[data-plugin=whatsapp] .text-left{text-align:left}[data-plugin=whatsapp] .font-display{font-family:var(--f-display)}[data-plugin=whatsapp] .font-mono{font-family:var(--f-mono)}[data-plugin=whatsapp] .text-lg{font-size:1.125rem;line-height:var(--tw-leading,calc(1.75 / 1.125))}[data-plugin=whatsapp] .text-sm{font-size:.875rem;line-height:var(--tw-leading,calc(1.25 / .875))}[data-plugin=whatsapp] .text-xl{font-size:1.25rem;line-height:var(--tw-leading,calc(1.75 / 1.25))}[data-plugin=whatsapp] .text-\[0\.75rem\]{font-size:.75rem}[data-plugin=whatsapp] .text-\[0\.875rem\]{font-size:.875rem}[data-plugin=whatsapp] .text-\[0\.6875rem\]{font-size:.6875rem}[data-plugin=whatsapp] .text-\[0\.8125rem\]{font-size:.8125rem}[data-plugin=whatsapp] .text-\[0\.9375rem\]{font-size:.9375rem}[data-plugin=whatsapp] .text-\[14px\]{font-size:14px}[data-plugin=whatsapp] .leading-5{--tw-leading:calc(.25rem * 5);line-height:1.25rem}[data-plugin=whatsapp] .leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}[data-plugin=whatsapp] .leading-tight{--tw-leading:1.25;line-height:1.25}[data-plugin=whatsapp] .font-medium{--tw-font-weight:500;font-weight:500}[data-plugin=whatsapp] .font-semibold{--tw-font-weight:600;font-weight:600}[data-plugin=whatsapp] .tracking-wide{--tw-tracking:.025em;letter-spacing:.025em}[data-plugin=whatsapp] .whitespace-nowrap{white-space:nowrap}[data-plugin=whatsapp] .text-ember{color:var(--ember-mark)}[data-plugin=whatsapp] .text-ember-strong{color:var(--ember-strong-mark)}[data-plugin=whatsapp] .text-ink{color:var(--ink)}[data-plugin=whatsapp] .text-ink-2{color:var(--ink-2)}[data-plugin=whatsapp] .text-ink-3{color:var(--ink-3)}[data-plugin=whatsapp] .text-ink-4{color:var(--ink-4)}[data-plugin=whatsapp] .text-moss{color:var(--moss)}[data-plugin=whatsapp] .text-paper{color:var(--paper)}[data-plugin=whatsapp] .text-primary-foreground{color:var(--primary-foreground)}[data-plugin=whatsapp] .text-rose{color:var(--rose)}[data-plugin=whatsapp] .capitalize{text-transform:capitalize}[data-plugin=whatsapp] .uppercase{text-transform:uppercase}[data-plugin=whatsapp] .tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}[data-plugin=whatsapp] .line-through{text-decoration-line:line-through}[data-plugin=whatsapp] .underline{text-decoration-line:underline}[data-plugin=whatsapp] .underline-offset-2{text-underline-offset:2px}[data-plugin=whatsapp] .opacity-0{opacity:0}[data-plugin=whatsapp] .opacity-35{opacity:.35}[data-plugin=whatsapp] .shadow-\[0_1px_0_oklch\(0\%_0_0\/0\.08\)\]{--tw-shadow:0 1px 0 var(--tw-shadow-color,oklch(0% 0 0/.08));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .shadow-\[inset_0_1px_0_oklch\(0\%_0_0\/0\.02\)\]{--tw-shadow:inset 0 1px 0 var(--tw-shadow-color,oklch(0% 0 0/.02));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .shadow-overlay{--tw-shadow:var(--shadow-ember-overlay);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .shadow-soft{--tw-shadow:var(--shadow-ember-soft);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .ring-4{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .ring-border{--tw-ring-color:var(--border)}[data-plugin=whatsapp] .ring-border-soft{--tw-ring-color:var(--border-soft)}[data-plugin=whatsapp] .ring-focus-glow{--tw-ring-color:var(--focus-glow)}[data-plugin=whatsapp] .transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,cubic-bezier(.4, 0, .2, 1));transition-duration:var(--tw-duration,.15s)}[data-plugin=whatsapp] .transition-\[background\,filter\,color\,transform\]{transition-property:background,filter,color,transform;transition-timing-function:var(--tw-ease,cubic-bezier(.4, 0, .2, 1));transition-duration:var(--tw-duration,.15s)}[data-plugin=whatsapp] .transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,cubic-bezier(.4, 0, .2, 1));transition-duration:var(--tw-duration,.15s)}[data-plugin=whatsapp] .transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,cubic-bezier(.4, 0, .2, 1));transition-duration:var(--tw-duration,.15s)}[data-plugin=whatsapp] .duration-150{--tw-duration:.15s;transition-duration:.15s}[data-plugin=whatsapp] .duration-200{--tw-duration:.2s;transition-duration:.2s}[data-plugin=whatsapp] .ease-out{--tw-ease:cubic-bezier(0, 0, .2, 1);transition-timing-function:cubic-bezier(0,0,.2,1)}[data-plugin=whatsapp] .outline-none{--tw-outline-style:none;outline-style:none}[data-plugin=whatsapp] .select-all{-webkit-user-select:all;user-select:all}[data-plugin=whatsapp] .select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){[data-plugin=whatsapp] .group-hover\:scale-110:is(:where(.group):hover *){--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}[data-plugin=whatsapp] .group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}[data-plugin=whatsapp] .placeholder\:truncate::placeholder{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}[data-plugin=whatsapp] .placeholder\:text-ink-4::placeholder{color:var(--ink-4)}[data-plugin=whatsapp] .backdrop\:bg-\[oklch\(20\%_0\.01_60\/0\.28\)\]::backdrop{background-color:oklch(20% .01 60/.28)}[data-plugin=whatsapp] .backdrop\:backdrop-blur-\[2px\]::backdrop{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}[data-plugin=whatsapp] .before\:absolute:before{content:var(--tw-content);position:absolute}[data-plugin=whatsapp] .before\:-inset-x-1:before{content:var(--tw-content);inset-inline:-.25rem}[data-plugin=whatsapp] .before\:-inset-y-2\.5:before{content:var(--tw-content);inset-block:-.625rem}[data-plugin=whatsapp] .before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}[data-plugin=whatsapp] .focus-within\:ring-focus:focus-within{--tw-ring-color:var(--focus-line)}@media (hover:hover){[data-plugin=whatsapp] .hover\:border-ink-4:hover{border-color:var(--ink-4)}[data-plugin=whatsapp] .hover\:bg-accent:hover{background-color:var(--accent)}[data-plugin=whatsapp] .hover\:bg-card:hover{background-color:var(--card)}[data-plugin=whatsapp] .hover\:bg-paper-2:hover{background-color:var(--paper-2)}[data-plugin=whatsapp] .hover\:bg-paper-3:hover{background-color:var(--paper-3)}[data-plugin=whatsapp] .hover\:bg-rose-tint:hover{background-color:var(--rose-tint)}[data-plugin=whatsapp] .hover\:text-ink:hover{color:var(--ink)}[data-plugin=whatsapp] .hover\:text-ink-2:hover{color:var(--ink-2)}[data-plugin=whatsapp] .hover\:text-rose:hover{color:var(--rose)}[data-plugin=whatsapp] .hover\:brightness-\[1\.06\]:hover{--tw-brightness:brightness(1.06);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}}[data-plugin=whatsapp] .focus\:border-focus:focus{border-color:var(--focus-line)}[data-plugin=whatsapp] .focus\:ring-4:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .focus\:ring-focus-glow:focus{--tw-ring-color:var(--focus-glow)}[data-plugin=whatsapp] .focus-visible\:border-focus:focus-visible{border-color:var(--focus-line)}[data-plugin=whatsapp] .focus-visible\:opacity-100:focus-visible{opacity:1}[data-plugin=whatsapp] .focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .focus-visible\:ring-4:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-plugin=whatsapp] .focus-visible\:ring-focus:focus-visible{--tw-ring-color:var(--focus-line)}[data-plugin=whatsapp] .focus-visible\:ring-focus-glow:focus-visible{--tw-ring-color:var(--focus-glow)}[data-plugin=whatsapp] .active\:scale-\[0\.98\]:active{scale:.98}[data-plugin=whatsapp] .active\:brightness-95:active{--tw-brightness:brightness(95%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}[data-plugin=whatsapp] .disabled\:pointer-events-none:disabled{pointer-events:none}[data-plugin=whatsapp] .disabled\:line-through:disabled{text-decoration-line:line-through}[data-plugin=whatsapp] .disabled\:opacity-40:disabled{opacity:.4}[data-plugin=whatsapp] .disabled\:opacity-50:disabled{opacity:.5}[data-plugin=whatsapp] .disabled\:opacity-60:disabled{opacity:.6}@media (prefers-reduced-motion:reduce){[data-plugin=whatsapp] .motion-reduce\:transition-none{transition-property:none}}@media not all and (width>=48rem){[data-plugin=whatsapp] .max-md\:hidden{display:none}}@media not all and (width>=40rem){[data-plugin=whatsapp] .max-sm\:m-0{margin:0}[data-plugin=whatsapp] .max-sm\:h-dvh{height:100dvh}[data-plugin=whatsapp] .max-sm\:max-h-none{max-height:none}[data-plugin=whatsapp] .max-sm\:w-full{width:100%}[data-plugin=whatsapp] .max-sm\:max-w-none{max-width:none}[data-plugin=whatsapp] .max-sm\:rounded-none{border-radius:0}[data-plugin=whatsapp] .max-sm\:pt-\[env\(safe-area-inset-top\)\]{padding-top:env(safe-area-inset-top)}[data-plugin=whatsapp] .max-sm\:pb-\[env\(safe-area-inset-bottom\)\]{padding-bottom:env(safe-area-inset-bottom)}}@media (width>=40rem){[data-plugin=whatsapp] .sm\:h-\[min\(calc\(100dvh-32px\)\,56rem\)\]{height:min(100dvh - 32px,56rem)}[data-plugin=whatsapp] .sm\:max-w-2xl{max-width:42rem}[data-plugin=whatsapp] .sm\:max-w-4xl{max-width:56rem}[data-plugin=whatsapp] .sm\:max-w-md{max-width:28rem}[data-plugin=whatsapp] .sm\:p-7{padding:1.75rem}}@media (width>=48rem){[data-plugin=whatsapp] .md\:hidden{display:none}}@media (pointer:coarse){[data-plugin=whatsapp] .coarse\:size-10{width:2.5rem;height:2.5rem}[data-plugin=whatsapp] .coarse\:size-11{width:2.75rem;height:2.75rem}[data-plugin=whatsapp] .coarse\:h-9{height:2.25rem}[data-plugin=whatsapp] .coarse\:h-11{height:2.75rem}[data-plugin=whatsapp] .coarse\:min-h-11{min-height:2.75rem}[data-plugin=whatsapp] .coarse\:px-4{padding-inline:1rem}[data-plugin=whatsapp] .coarse\:py-3{padding-block:.75rem}}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
3
- /*$vite$:1*/
@@ -1 +0,0 @@
1
- var __wizardsPlugin_whatsapp=(function(e,t,n,r,i){var a=e=>e?.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase();function o(e,t,n=[]){if(t==null)throw Error(`[lucide]: iconNode is required when icon name is used`);return{name:a(e),size:24,node:t,...n.length>0?{aliases:n}:{}}}var s=e=>{let t=``,n=!1;for(let r of e){if(r===`-`||r===`_`||r<=` `){n=t.length>0;continue}t.length===0?t+=r.toLowerCase():t+=n?r.toUpperCase():r,n=!1}return t},c=e=>{let t=s(e);return t.charAt(0).toUpperCase()+t.slice(1)},l=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),u={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":2,"stroke-linecap":`round`,"stroke-linejoin":`round`};function d(e){return e!=null}function f(e,t={}){let n=t.attributeNames??{},r=e=>n[e]??e,i=e.size??e.width??u.width,a=e.size??e.height??u.height,o=e.aliases?.filter(e=>typeof e==`string`&&e.trim()!==``).map(e=>`lucide-${e}`)??[],s=[...e.name?[`lucide-${e.name}`]:[],...o],c=t.className?.split(` `).filter(Boolean)??[],f=t.includeDefaultClasses===!1?l(...c):l(`lucide`,...s,...c),p=t.absoluteStrokeWidth?Number(t.strokeWidth??u[`stroke-width`])*Number(e.size??e.width??u.width)/Number(t.size??t.width??u.width):t.strokeWidth??u[`stroke-width`];return[`svg`,{...Object.entries(u).reduce((e,[t,n])=>(e[r(t)]=n,e),{}),...`color`in t&&t.color&&{[r(`stroke`)]:t.color},...`size`in t&&d(t.size)&&{[r(`width`)]:t.size,[r(`height`)]:t.size},...`width`in t&&d(t.width)&&{[r(`width`)]:t.width},...`height`in t&&d(t.height)&&{[r(`height`)]:t.height},[r(`stroke-width`)]:p,...f&&{[r(`class`)]:f},[r(`viewBox`)]:`0 0 ${i} ${a}`,...t.hasA11yProp===!1?{[r(`aria-hidden`)]:`true`}:{},...`attributes`in t&&t.attributes},e.node.map(e=>{let[n,i,a]=e,o=t.nonScalingStroke?{[r(`vector-effect`)]:`non-scaling-stroke`,...i}:i;return a?[n,o,a]:[n,o]})]}function p(e,t={}){return f(e,{...t,attributeNames:{...t.attributeNames,class:`className`,"stroke-width":`strokeWidth`,"stroke-linecap":`strokeLinecap`,"stroke-linejoin":`strokeLinejoin`,"vector-effect":`vectorEffect`}})}var m=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},h=(0,t.createContext)({}),g=()=>(0,t.useContext)(h),_=(0,t.forwardRef)(({color:e,size:n,width:r,height:i,strokeWidth:a,absoluteStrokeWidth:o,nonScalingStroke:s,className:c=``,children:u,iconNode:d=[],icon:f={node:d,aliases:[],size:24},...h},_)=>{let{size:v=24,strokeWidth:y=2,absoluteStrokeWidth:b=!1,nonScalingStroke:x=!1,color:S=`currentColor`,className:C=``}=g()??{},w=!!u||m(h),[T,E,D=[]]=p(f,{color:e??S,width:r??n??v,height:i??n??v,strokeWidth:a??y,absoluteStrokeWidth:o??b,nonScalingStroke:s??x,className:l(C,c),hasA11yProp:w,attributes:h});return(0,t.createElement)(T,{ref:_,...E},[...D.map(([e,n])=>(0,t.createElement)(e,n)),...Array.isArray(u)?u:[u]])});function v(e,n=[],r=[]){let i=typeof e==`string`?o(e,n,r):e,a=(0,t.forwardRef)(({className:e,...n},r)=>(0,t.createElement)(_,{ref:r,icon:i,className:e,...n}));return i.name&&(a.displayName=c(i.name)),a}var y={name:`check`,size:24,node:[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]};y.node;var b=v(y),x={name:`copy`,size:24,node:[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]};x.node;var S=v(x),C={name:`message-circle`,size:24,node:[[`path`,{d:`M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719`,key:`1sd12s`}]]};C.node;var w=v(C),T={de:{title:`WhatsApp`,intro:`Wizards laufen in einem WhatsApp-Thread auf der eigenen Business-Nummer. Dafür braucht es eine Meta-App mit dem Produkt WhatsApp: die ID der Telefonnummer und einen dauerhaften Access Token aus dem Meta-Dashboard.`,phoneNumberId:`Phone number ID`,phoneNumberIdHint:`Im Meta-Dashboard unter WhatsApp → API-Setup.`,number:`Nummer`,numberHint:`Mit Ländervorwahl, nur Ziffern: 43660…`,token:`Access Token`,tokenHint:`Ein dauerhafter Token eines System-Users mit whatsapp_business_messaging.`,tokenKept:`Ist hinterlegt. Leer lassen, um ihn zu behalten.`,secret:`App Secret`,secretHint:`Freiwillig. Damit wird jede Nachricht von Meta auf ihre Signatur geprüft.`,template:`Template`,templateHint:`Freiwillig. Der Name eines genehmigten Utility-Templates mit einem Platzhalter im Text: damit meldet sich der Wizard nach einem Tag Stille mit dem Link.`,save:`Speichern`,saved:`Gespeichert.`,disconnect:`Trennen`,meta:`In der Meta-App eintragen`,metaHint:`Unter WhatsApp → Konfiguration: die Webhook-Adresse und den Verify Token eintragen, dann das Feld „messages“ abonnieren.`,webhook:`Webhook-Adresse`,verifyToken:`Verify Token`,copy:`Kopieren`,copied:`Kopiert`,testTo:`Testnachricht an`,sendTest:`Senden`,testSent:`Angekommen? Dann passt alles.`,keyword:`Stichwort`,keywordHint:`Wer dieses Wort an die Nummer schreibt, startet den Wizard. Der Link und der QR-Code schreiben es vor.`,error_bad_keyword:`Ein Stichwort besteht aus Buchstaben, Ziffern, Leerzeichen und Bindestrichen, bis zu 40.`,error_keyword_taken:`Ein anderer Wizard hat dieses Stichwort schon.`,error_no_token:`Es braucht einen Access Token.`,error_provider:`WhatsApp hat die Nachricht nicht angenommen: {message}`,error_other:`{message}`},en:{title:`WhatsApp`,intro:`Wizards run in a WhatsApp thread on your own business number. It takes a Meta app with the WhatsApp product: the phone number's ID and a permanent access token from the Meta dashboard.`,phoneNumberId:`Phone number ID`,phoneNumberIdHint:`In the Meta dashboard under WhatsApp → API setup.`,number:`Number`,numberHint:`With the country code, digits only: 43660…`,token:`Access token`,tokenHint:`A permanent token of a system user with whatsapp_business_messaging.`,tokenKept:`Is set. Leave empty to keep it.`,secret:`App secret`,secretHint:`Optional. With it, every message from Meta is checked for its signature.`,template:`Template`,templateHint:`Optional. The name of an approved utility template with one placeholder in its text: the wizard reaches back with the link after a day of silence.`,save:`Save`,saved:`Saved.`,disconnect:`Disconnect`,meta:`Enter in the Meta app`,metaHint:`Under WhatsApp → Configuration: enter the webhook address and the verify token, then subscribe to the “messages” field.`,webhook:`Webhook address`,verifyToken:`Verify token`,copy:`Copy`,copied:`Copied`,testTo:`Test message to`,sendTest:`Send`,testSent:`Arrived? Then everything is set.`,keyword:`Keyword`,keywordHint:`Whoever writes this word to the number starts the wizard. The link and the QR code write it for them.`,error_bad_keyword:`A keyword is letters, digits, spaces and dashes, up to 40.`,error_keyword_taken:`Another wizard has this keyword already.`,error_no_token:`An access token is needed.`,error_provider:`WhatsApp did not take the message: {message}`,error_other:`{message}`}},E=null,D=null;function O(e){E=e,D=e.i18n.register(T)}function k(){if(!E)throw Error(`The WhatsApp plugin is not loaded.`);return E}var A=(e,t)=>D?.(e,t)??e,j=()=>k().api,M=`whatsapp`;function N(e){let t=e?.body,n=t?.code,r=t?.error??(e instanceof Error?e.message:String(e));return n&&`error_${n}`in T.de?A(`error_${n}`,{message:r}):A(`error_other`,{message:r})}function P({text:e}){let[r,a]=(0,t.useState)(!1);return(0,i.jsx)(n.IconButton,{label:A(r?`copied`:`copy`),className:`size-8`,onClick:()=>{navigator.clipboard.writeText(e).then(()=>{a(!0),setTimeout(()=>a(!1),1500)})},children:r?(0,i.jsx)(b,{className:`size-4`}):(0,i.jsx)(S,{className:`size-4`})})}function F({label:e,value:t}){return(0,i.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,i.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,i.jsx)(`div`,{className:`text-[0.8125rem] text-ink-3`,children:e}),(0,i.jsx)(`div`,{className:`select-all truncate font-mono text-[0.8125rem]`,children:t})]}),(0,i.jsx)(P,{text:t})]})}function I(){let e=(0,r.useQueryClient)(),a=(0,r.useQuery)({queryKey:[M,`account`],queryFn:()=>j().get(`/account`)}),[o,s]=(0,t.useState)({phoneNumberId:``,number:``,accessToken:``,appSecret:``,template:``}),[c,l]=(0,t.useState)(``);(0,t.useEffect)(()=>{a.data&&s(e=>({...e,phoneNumberId:a.data.phoneNumberId,number:a.data.number,template:a.data.template}))},[a.data]);let u=()=>e.invalidateQueries({queryKey:[M]}),d=(0,r.useMutation)({mutationFn:()=>j().put(`/account`,{phoneNumberId:o.phoneNumberId,number:o.number,accessToken:o.accessToken||void 0,appSecret:o.appSecret||void 0,template:o.template||null}),onSuccess:async()=>{s(e=>({...e,accessToken:``,appSecret:``})),await u()}}),f=(0,r.useMutation)({mutationFn:()=>j().del(`/account`),onSuccess:u}),p=(0,r.useMutation)({mutationFn:()=>j().post(`/account/test`,{to:c})}),m=e=>t=>s(n=>({...n,[e]:t.target.value})),h=a.data;return(0,i.jsxs)(`section`,{className:`flex flex-col gap-2.5`,children:[(0,i.jsx)(`h2`,{className:`px-1 font-display font-semibold text-lg leading-tight`,children:A(`title`)}),(0,i.jsxs)(n.Card,{className:`flex flex-col gap-4 p-5 text-[0.875rem]`,children:[(0,i.jsx)(`p`,{className:`text-[0.8125rem] text-ink-3`,children:A(`intro`)}),a.isLoading?(0,i.jsx)(n.Spinner,{className:`mx-auto`}):null,(0,i.jsxs)(`div`,{children:[(0,i.jsx)(n.Label,{hint:A(`phoneNumberIdHint`),children:A(`phoneNumberId`)}),(0,i.jsx)(n.Input,{value:o.phoneNumberId,onChange:m(`phoneNumberId`),autoComplete:`off`})]}),(0,i.jsxs)(`div`,{children:[(0,i.jsx)(n.Label,{hint:A(`numberHint`),children:A(`number`)}),(0,i.jsx)(n.Input,{value:o.number,onChange:m(`number`),inputMode:`numeric`})]}),(0,i.jsxs)(`div`,{children:[(0,i.jsx)(n.Label,{hint:h?.hasToken?A(`tokenKept`):A(`tokenHint`),children:A(`token`)}),(0,i.jsx)(n.Input,{type:`password`,value:o.accessToken,onChange:m(`accessToken`),placeholder:h?.hasToken?`••••••••`:``,autoComplete:`new-password`})]}),(0,i.jsxs)(`div`,{children:[(0,i.jsx)(n.Label,{hint:A(`secretHint`),children:A(`secret`)}),(0,i.jsx)(n.Input,{type:`password`,value:o.appSecret,onChange:m(`appSecret`),placeholder:h?.hasSecret?`••••••••`:``,autoComplete:`new-password`})]}),(0,i.jsxs)(`div`,{children:[(0,i.jsx)(n.Label,{hint:A(`templateHint`),children:A(`template`)}),(0,i.jsx)(n.Input,{value:o.template,onChange:m(`template`),autoComplete:`off`})]}),(0,i.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,i.jsx)(n.Button,{onClick:()=>d.mutate(),busy:d.isPending,children:A(`save`)}),h?.connected?(0,i.jsx)(n.Button,{variant:`ghost`,onClick:()=>f.mutate(),busy:f.isPending,children:A(`disconnect`)}):null,d.isSuccess?(0,i.jsx)(`span`,{className:`text-[0.8125rem] text-ink-3`,children:A(`saved`)}):null]}),d.error?(0,i.jsx)(`p`,{className:`text-[0.8125rem] text-rose`,children:N(d.error)}):null]}),h?.connected?(0,i.jsxs)(n.Card,{className:`flex flex-col gap-4 p-5 text-[0.875rem]`,children:[(0,i.jsx)(`div`,{className:`font-medium`,children:A(`meta`)}),(0,i.jsx)(`p`,{className:`text-[0.8125rem] text-ink-3`,children:A(`metaHint`)}),(0,i.jsx)(F,{label:A(`webhook`),value:h.webhook}),h.verifyToken?(0,i.jsx)(F,{label:A(`verifyToken`),value:h.verifyToken}):null,(0,i.jsxs)(`div`,{children:[(0,i.jsx)(n.Label,{children:A(`testTo`)}),(0,i.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,i.jsx)(n.Input,{value:c,onChange:e=>l(e.target.value),placeholder:`+43 660 …`,inputMode:`tel`,className:`max-w-xs`}),(0,i.jsx)(n.Button,{variant:`secondary`,onClick:()=>p.mutate(),busy:p.isPending,children:A(`sendTest`)})]}),p.isSuccess?(0,i.jsx)(`p`,{className:`mt-2 text-[0.8125rem] text-ink-3`,children:A(`testSent`)}):null,p.error?(0,i.jsx)(`p`,{className:`mt-2 text-[0.8125rem] text-rose`,children:N(p.error)}):null]})]}):null]})}function L({wizard:e}){let a=(0,r.useQueryClient)(),o=(0,r.useQuery)({queryKey:[M,`binding`,e.id],queryFn:()=>j().get(`/binding/${e.id}`)}),[s,c]=(0,t.useState)(null),l=(0,r.useMutation)({mutationFn:t=>j().put(`/binding/${e.id}`,{keyword:t}),onSuccess:async()=>{c(null),await Promise.all([a.invalidateQueries({queryKey:[M,`binding`,e.id]}),a.invalidateQueries({queryKey:[`wizard-runners`,e.id]})])}});if(!o.data)return null;let u=s??o.data.keyword;return(0,i.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[(0,i.jsxs)(`label`,{className:`flex flex-col gap-1.5`,children:[(0,i.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:A(`keyword`)}),(0,i.jsx)(n.Input,{value:u,onChange:e=>c(e.target.value),onBlur:()=>{s?.trim()&&s.trim()!==o.data?.keyword?l.mutate(s):c(null)},onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur()},className:`max-w-xs`})]}),(0,i.jsx)(`p`,{className:`text-[0.8125rem] text-ink-3`,children:A(`keywordHint`)}),l.error?(0,i.jsx)(`p`,{className:`text-[0.8125rem] text-rose`,children:N(l.error)}):null]})}return(0,e.defineStudioPlugin)(e=>{O(e),e.registerSettingsSection({id:`whatsapp`,label:()=>A(`title`),icon:w,component:I}),e.registerShareSection({runner:`whatsapp`,component:L})})})(__WIZARDS_STUDIO__.sdk,__WIZARDS_STUDIO__.react,__WIZARDS_STUDIO__.ui,__WIZARDS_STUDIO__.query,__WIZARDS_STUDIO__.jsx);
@@ -1,8 +0,0 @@
1
- {
2
- "id": "whatsapp",
3
- "name": "WhatsApp",
4
- "version": "0.1.0",
5
- "description": "Runs wizards in a WhatsApp thread: a keyword on the tenant's business number starts one, the fields come one message at a time with buttons and lists, photos and files are sent in the chat, and what the wizard makes arrives as pictures, documents and links. Talks to Meta's WhatsApp Cloud API with the tenant's own number and token; keeps the threads in the tenant's database.",
6
- "kind": "module",
7
- "provides": ["runner.whatsapp"]
8
- }
@@ -1,30 +0,0 @@
1
- -- The tenant's WhatsApp Business number, as Meta's Cloud API names it. One row. Dates are milliseconds.
2
- CREATE TABLE whatsapp_account (
3
- id INTEGER PRIMARY KEY CHECK (id = 1),
4
- phone_number_id TEXT NOT NULL,
5
- number TEXT NOT NULL,
6
- access_token TEXT NOT NULL,
7
- app_secret TEXT,
8
- verify_token TEXT NOT NULL,
9
- template TEXT,
10
- updated_at INTEGER NOT NULL
11
- );
12
-
13
- -- The keyword that starts a wizard on the number: wa.me/<number>?text=<keyword>.
14
- CREATE TABLE whatsapp_binding (
15
- wizard_id TEXT PRIMARY KEY,
16
- keyword TEXT NOT NULL COLLATE NOCASE
17
- );
18
- CREATE UNIQUE INDEX whatsapp_binding_keyword ON whatsapp_binding (keyword);
19
-
20
- -- One thread per number that wrote: the run it is in, and where in it (state is JSON).
21
- CREATE TABLE whatsapp_thread (
22
- wa_id TEXT PRIMARY KEY,
23
- name TEXT,
24
- run_id TEXT,
25
- state TEXT NOT NULL,
26
- last_inbound_at INTEGER NOT NULL,
27
- last_message_id TEXT,
28
- updated_at INTEGER NOT NULL
29
- );
30
- CREATE INDEX whatsapp_thread_run ON whatsapp_thread (run_id);
@@ -1,24 +0,0 @@
1
- {
2
- "name": "@engenty-wizards/module-whatsapp",
3
- "version": "0.1.0",
4
- "license": "FSL-1.1-MIT",
5
- "private": true,
6
- "type": "module",
7
- "scripts": {
8
- "build": "node ../../scripts/build-plugin.mjs .",
9
- "dev": "node ../../scripts/build-plugin.mjs . --watch",
10
- "typecheck": "tsc -p tsconfig.json --noEmit"
11
- },
12
- "devDependencies": {
13
- "@engenty-wizards/plugin-sdk": "workspace:*",
14
- "@engenty-wizards/web": "workspace:*",
15
- "@tanstack/react-query": "^5.104.0",
16
- "@types/node": "^26.6.4",
17
- "@types/react": "^19.3.0",
18
- "drizzle-orm": "^0.45.3",
19
- "lucide-react": "^1.49.0",
20
- "react": "19.3.0",
21
- "typescript": "~6.0.3",
22
- "zod": "4.6.5"
23
- }
24
- }