From 1ecc8411e46e5c81eb64067592c4e72d665b5583 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Thu, 4 Jun 2026 15:03:09 +0200 Subject: [PATCH] refactor: drop await on draft-delete in reset flows, refetch deployed directly --- .../sessions/ScriptEditorView.svelte | 26 ++++++++-------- .../azure/AzureTriggerEditorInner.svelte | 10 +++++-- .../email/EmailTriggerEditorInner.svelte | 10 +++++-- .../triggers/gcp/GcpTriggerEditorInner.svelte | 10 +++++-- .../triggers/http/RouteEditorInner.svelte | 10 +++++-- .../kafka/KafkaTriggerEditorInner.svelte | 10 +++++-- .../mqtt/MqttTriggerEditorInner.svelte | 10 +++++-- .../nats/NatsTriggerEditorInner.svelte | 10 +++++-- .../PostgresTriggerEditorInner.svelte | 10 +++++-- .../schedules/ScheduleEditorInner.svelte | 20 +++++++++---- .../triggers/sqs/SqsTriggerEditorInner.svelte | 10 +++++-- .../WebsocketTriggerEditorInner.svelte | 10 +++++-- frontend/src/lib/userDraftToast.ts | 30 +++++++++---------- .../(logged)/apps/edit/[...path]/+page.svelte | 7 +++-- .../apps_raw/edit/[...path]/+page.svelte | 7 +++-- .../flows/edit/[...path]/+page.svelte | 7 +++-- .../scripts/edit/[...path]/+page.svelte | 14 ++++----- 17 files changed, 131 insertions(+), 80 deletions(-) diff --git a/frontend/src/lib/components/sessions/ScriptEditorView.svelte b/frontend/src/lib/components/sessions/ScriptEditorView.svelte index 0c6b6d67ac..f526590a4e 100644 --- a/frontend/src/lib/components/sessions/ScriptEditorView.svelte +++ b/frontend/src/lib/components/sessions/ScriptEditorView.svelte @@ -58,19 +58,21 @@ // separate `.draft` field), so `saved.is_draft` is the signal that // there's actually a draft worth deleting; the syncer's // `value: null` POST is the canonical per-user delete. + // + // Fire-and-forget: every read here (`saved`, the snapshot we build + // below, the UserDraft.discard write) is purely in-memory, so we + // don't need the DELETE to have landed to finish the restore. We + // flip `is_draft` optimistically so the UI matches the new intent + // immediately. A failed DELETE only matters across a hard reload + // before it lands — log and move on. if (saved.is_draft) { - try { - await UserDraftDbSyncer.save({ - workspace: workspaceId, - itemKind: 'script', - path: saved.path, - value: null - }) - saved.is_draft = false - } catch (e: any) { - sendUserToast(`Could not delete draft: ${e?.body ?? e}`, true) - return - } + saved.is_draft = false + UserDraftDbSyncer.save({ + workspace: workspaceId, + itemKind: 'script', + path: saved.path, + value: null + }).catch((e) => console.error('restoreDeployed: draft delete failed', e)) } const deployed = structuredClone($state.snapshot(saved)) as NewScript & { draft?: unknown } delete deployed.draft diff --git a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte index a7623fc76a..65ca9e1c60 100644 --- a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte @@ -185,7 +185,11 @@ } } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -194,7 +198,7 @@ const s = await AzureTriggerService.getAzureTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -203,7 +207,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte index 9fedd124ee..707b5637bf 100644 --- a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte @@ -207,7 +207,11 @@ preservePermissionedAs = !!cfg?.permissioned_as } - async function loadTrigger(defaultConfig?: Partial): Promise { + async function loadTrigger( + defaultConfig?: Partial, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -215,7 +219,7 @@ const s = await EmailTriggerService.getEmailTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -224,7 +228,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte index cd9348b693..13a419ab0b 100644 --- a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte @@ -189,7 +189,11 @@ } } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -198,7 +202,7 @@ const s = await GcpTriggerService.getGcpTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -207,7 +211,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte index f35ccfc705..2402ba342b 100644 --- a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte +++ b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte @@ -340,7 +340,11 @@ preservePermissionedAs = !!cfg?.permissioned_as } - async function loadTrigger(defaultConfig?: Partial): Promise { + async function loadTrigger( + defaultConfig?: Partial, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -348,7 +352,7 @@ const s = await HttpTriggerService.getHttpTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -357,7 +361,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte index 98fe398887..6990dbbeee 100644 --- a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte @@ -246,7 +246,11 @@ preservePermissionedAs = !!cfg?.permissioned_as } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -254,7 +258,7 @@ const s = await KafkaTriggerService.getKafkaTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -263,7 +267,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte index 8b365b8d13..85e6a4d022 100644 --- a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte @@ -245,7 +245,11 @@ } } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true try { if (defaultConfig) { loadTriggerConfig(defaultConfig) @@ -254,7 +258,7 @@ const s = await MqttTriggerService.getMqttTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -263,7 +267,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte index aaec8d7e6d..a7112ca0ab 100644 --- a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte @@ -228,7 +228,11 @@ preservePermissionedAs = !!cfg?.permissioned_as } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -236,7 +240,7 @@ const s = await NatsTriggerService.getNatsTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -245,7 +249,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte index f7b03348b5..d7c35ed187 100644 --- a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte @@ -368,7 +368,11 @@ preservePermissionedAs = !!cfg?.permissioned_as } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) if (defaultConfig?.publication) { @@ -380,7 +384,7 @@ const s = await PostgresTriggerService.getPostgresTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -389,7 +393,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte index 1808fa4ba0..0fda44ced9 100644 --- a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte +++ b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte @@ -278,8 +278,10 @@ nis_flow: boolean, initial_script_path?: string, defaultValues?: Schedule, - schedule_path?: string + schedule_path?: string, + opts: { getDraft?: boolean } = {} ) { + const getDraft = opts.getDraft ?? true let loadingTimeout = setTimeout(() => { showLoading = true }, 100) // Do not show loading spinner for the first 100ms @@ -290,7 +292,7 @@ const resp = await ScheduleService.getSchedule({ workspace: $workspaceStore!, path: schedule_path, - getDraft: true + getDraft }) if (resp.is_draft) { notifyDraftLoaded({ @@ -299,7 +301,9 @@ path: schedule_path, draftOnly: resp.no_deployed, onResetToDeployed: async () => { - await openNew(nis_flow, initial_script_path, defaultValues, schedule_path) + await openNew(nis_flow, initial_script_path, defaultValues, schedule_path, { + getDraft: false + }) } }) } @@ -466,13 +470,17 @@ } } - async function loadSchedule(defaultCfg?: Record): Promise { + async function loadSchedule( + defaultCfg?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (!defaultCfg) { try { const s = await ScheduleService.getSchedule({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s.is_draft) { notifyDraftLoaded({ @@ -481,7 +489,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadSchedule() + await loadSchedule(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte index 5ad99c92cb..684e3c0fc7 100644 --- a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte @@ -222,7 +222,11 @@ } } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true try { if (defaultConfig) { loadTriggerConfig(defaultConfig) @@ -231,7 +235,7 @@ const s = await SqsTriggerService.getSqsTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -240,7 +244,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte index d98f20052e..cb00aab099 100644 --- a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte @@ -303,7 +303,11 @@ } } - async function loadTrigger(defaultConfig?: Record): Promise { + async function loadTrigger( + defaultConfig?: Record, + opts: { getDraft?: boolean } = {} + ): Promise { + const getDraft = opts.getDraft ?? true if (defaultConfig) { loadTriggerConfig(defaultConfig) return @@ -311,7 +315,7 @@ const s = await WebsocketTriggerService.getWebsocketTrigger({ workspace: $workspaceStore!, path: initialPath, - getDraft: true + getDraft }) if (s?.is_draft) { notifyDraftLoaded({ @@ -320,7 +324,7 @@ path: initialPath, draftOnly: s.no_deployed, onResetToDeployed: async () => { - await loadTrigger() + await loadTrigger(undefined, { getDraft: false }) } }) } diff --git a/frontend/src/lib/userDraftToast.ts b/frontend/src/lib/userDraftToast.ts index 543b7bee55..072827e524 100644 --- a/frontend/src/lib/userDraftToast.ts +++ b/frontend/src/lib/userDraftToast.ts @@ -43,11 +43,14 @@ export function notifyRestoredFromLocal( * draft) but omit the action. * * The action: - * 1. POSTs `value: null` to delete the user's draft for this entity - * 2. invokes `onResetToDeployed` so the editor can re-fetch without - * the overlay and apply the pure deployed version - * Failures in either step surface a follow-up toast and leave the editor - * state untouched. + * 1. Fires `value: null` at the syncer (fire-and-forget — the user's + * delete races no reader; `onResetToDeployed` doesn't depend on it). + * 2. invokes `onResetToDeployed`, which MUST fetch deployed directly + * (e.g. `getDraft: false`) instead of trusting that the delete has + * already landed in the DB. + * + * A delete failure logs to console only — there's no UI state that + * depends on it. A reset-callback failure surfaces a toast. */ export function notifyDraftLoaded(opts: { workspace: string @@ -64,17 +67,12 @@ export function notifyDraftLoaded(opts: { { label: 'Reset to deployed', callback: async () => { - try { - await UserDraftDbSyncer.save({ - workspace: opts.workspace, - itemKind: opts.itemKind, - path: opts.path, - value: null - }) - } catch (e: any) { - sendUserToast(`Could not delete draft: ${e?.body ?? e}`, true) - return - } + UserDraftDbSyncer.save({ + workspace: opts.workspace, + itemKind: opts.itemKind, + path: opts.path, + value: null + }).catch((e) => console.error('Reset to deployed: draft delete failed', e)) try { await opts.onResetToDeployed() } catch (e: any) { diff --git a/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte index f7b7ab273d..1777125854 100644 --- a/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte @@ -76,7 +76,8 @@ * navigation races a draft-discard reload) bail at the next checkpoint * after their captured token no longer matches. */ let loadAppToken = 0 - async function loadApp(): Promise { + async function loadApp(opts: { getDraft?: boolean } = {}): Promise { + const getDraft = opts.getDraft ?? true const tok = ++loadAppToken // `?new_draft=true` (set by `/apps/add`'s redirect) means we landed // on a fresh `u/{user}/draft_{uuid}` path that's never been saved. @@ -115,7 +116,7 @@ const backendApp = await AppService.getAppByPath({ path: page.params.path ?? '', workspace: $workspaceStore!, - getDraft: true + getDraft }) if (tok !== loadAppToken) return if (backendApp.is_draft) { @@ -126,7 +127,7 @@ draftOnly: backendApp.no_deployed, onResetToDeployed: async () => { UserDraft.remove('app', path) - await loadApp() + await loadApp({ getDraft: false }) redraw++ } }) diff --git a/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte index c49c23ccff..537b28a219 100644 --- a/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte @@ -162,7 +162,8 @@ * navigation races a draft-discard reload) bail at the next checkpoint * after their captured token no longer matches. */ let loadAppToken = 0 - async function loadApp(): Promise { + async function loadApp(opts: { getDraft?: boolean } = {}): Promise { + const getDraft = opts.getDraft ?? true const tok = ++loadAppToken // `?new_draft=true` (set by `/apps_raw/add`'s redirect) means we // landed on a fresh `u/{user}/draft_{uuid}` path that's never @@ -194,7 +195,7 @@ const backendApp = (await AppService.getAppByPath({ path: page.params.path ?? '', workspace: $workspaceStore!, - getDraft: true, + getDraft, rawApp: true })) as any if (tok !== loadAppToken) return @@ -206,7 +207,7 @@ draftOnly: backendApp.no_deployed, onResetToDeployed: async () => { draftHandle.setDraftAndMeta(undefined, {}) - await loadApp() + await loadApp({ getDraft: false }) } }) } diff --git a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte index 520ea17b20..5f35964f70 100644 --- a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte @@ -147,7 +147,8 @@ * (e.g. picker navigation while a draft-discard reload is in flight), * the older promise no-ops at the next checkpoint. */ let loadFlowToken = 0 - async function loadFlow(): Promise { + async function loadFlow(opts: { getDraft?: boolean } = {}): Promise { + const getDraft = opts.getDraft ?? true const tok = ++loadFlowToken loading = true let flow: Flow @@ -214,7 +215,7 @@ const backendFlow = await FlowService.getFlowByPath({ workspace: $workspaceStore!, path: page.params.path ?? '', - getDraft: true + getDraft }) if (tok !== loadFlowToken) return if (backendFlow.is_draft) { @@ -225,7 +226,7 @@ draftOnly: backendFlow.no_deployed, onResetToDeployed: async () => { flowHandle.setDraftAndMeta(undefined, {}) - await loadFlow() + await loadFlow({ getDraft: false }) } }) } diff --git a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte index f7679f008e..91226a4373 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte @@ -135,7 +135,8 @@ * navigation races a draft-discard reload) bail at the next checkpoint * after their captured token no longer matches. */ let loadScriptToken = 0 - async function loadScript(): Promise { + async function loadScript(opts: { getDraft?: boolean } = {}): Promise { + const getDraft = opts.getDraft ?? true const tok = ++loadScriptToken fullyLoaded = false // `?new_draft=true` (set by `/scripts/add`'s redirect) means we @@ -179,7 +180,7 @@ const backendScript = await ScriptService.getScriptByPath({ workspace: $workspaceStore!, path: page.params.path ?? '', - getDraft: true + getDraft }) if (tok !== loadScriptToken) return if (backendScript.is_draft) { @@ -189,12 +190,11 @@ path: page.params.path ?? '', draftOnly: backendScript.no_deployed, onResetToDeployed: async () => { - // Drop the in-memory draft so loadScript's no-localDraft - // branch fires; the next fetch with `getDraft: true` will - // return pure deployed because we just deleted the draft - // row server-side. + // Drop the in-memory draft and refetch *without* the + // draft overlay — we don't trust the eventual delete + // to have landed, so we read deployed directly. scriptHandle.setDraftAndMeta(undefined, {}) - await loadScript() + await loadScript({ getDraft: false }) } }) }