diff --git a/.changeset/late-yaks-do.md b/.changeset/late-yaks-do.md new file mode 100644 index 0000000000..3db50606fc --- /dev/null +++ b/.changeset/late-yaks-do.md @@ -0,0 +1,5 @@ +--- +'houdini-svelte': patch +--- + +Add event argument to mutation for server-side operations diff --git a/e2e/sveltekit/package.json b/e2e/sveltekit/package.json index 2f088a6945..3150951426 100644 --- a/e2e/sveltekit/package.json +++ b/e2e/sveltekit/package.json @@ -8,6 +8,9 @@ "api": "cross-env TZ=utc e2e-api", "dev": "concurrently \"pnpm run web\" \"pnpm run api\" -n \"web,api\" -c \"green,magenta\"", "build": "vite build", + "build:": "cd ../../ && run build && cd -", + "build:dev": "pnpm build: && pnpm dev", + "build:test": "pnpm build: && pnpm test", "package": "svelte-kit package", "previewWeb": "vite preview --port 3007", "preview": "concurrently \"pnpm run previewWeb\" \"pnpm run api\" -n \"web,api\" -c \"green,magenta\"", diff --git a/e2e/sveltekit/src/routes/stores/action-mutation/+page.server.js b/e2e/sveltekit/src/routes/stores/action-mutation/+page.server.js index 89e8fb26d8..d552a1feb3 100644 --- a/e2e/sveltekit/src/routes/stores/action-mutation/+page.server.js +++ b/e2e/sveltekit/src/routes/stores/action-mutation/+page.server.js @@ -21,6 +21,6 @@ export const actions = { } `); - return await actionMutation.mutate({ name }); + return await actionMutation.mutate({ name }, { event }); } }; diff --git a/packages/houdini-svelte/src/runtime/stores/mutation.ts b/packages/houdini-svelte/src/runtime/stores/mutation.ts index 7a35fd7609..15e2393e78 100644 --- a/packages/houdini-svelte/src/runtime/stores/mutation.ts +++ b/packages/houdini-svelte/src/runtime/stores/mutation.ts @@ -1,9 +1,10 @@ import type { DocumentStore } from '$houdini/runtime/client' import type { MutationArtifact } from '$houdini/runtime/lib/types' import type { GraphQLObject } from '$houdini/runtime/lib/types' +import type { RequestEvent } from '@sveltejs/kit' import { getClient } from '../client' -import { getSession } from '../session' +import { fetchParams } from './query' export class MutationStore< _Data extends GraphQLObject, @@ -25,19 +26,27 @@ export class MutationStore< { metadata, fetch, + event, ...mutationConfig }: { // @ts-ignore metadata?: App.Metadata fetch?: typeof globalThis.fetch + event?: RequestEvent } & MutationConfig<_Data, _Input, _Optimistic> = {} ): Promise<_Data> { + const { context } = await fetchParams(this.artifact, this.artifact.name, { + fetch, + metadata, + event, + }) + return ( await this.store.send({ variables, - fetch, + fetch: context.fetch, metadata, - session: await getSession(), + session: context.session, stuff: { ...mutationConfig, }, diff --git a/packages/houdini-svelte/src/runtime/stores/query.ts b/packages/houdini-svelte/src/runtime/stores/query.ts index 3f44d78398..58fdf1312d 100644 --- a/packages/houdini-svelte/src/runtime/stores/query.ts +++ b/packages/houdini-svelte/src/runtime/stores/query.ts @@ -3,10 +3,12 @@ import type { FetchContext } from '$houdini/runtime/client/plugins/fetch' import * as log from '$houdini/runtime/lib/log' import type { QueryArtifact, + MutationArtifact, GraphQLObject, HoudiniFetchContext, QueryResult, } from '$houdini/runtime/lib/types' +import { ArtifactKind } from '$houdini/runtime/lib/types' // internals import { CachePolicy, CompiledQueryKind } from '$houdini/runtime/lib/types' import type { LoadEvent, RequestEvent } from '@sveltejs/kit' @@ -183,17 +185,17 @@ export type StoreConfig<_Data extends GraphQLObject, _Input, _Artifact> = { } export async function fetchParams<_Data extends GraphQLObject, _Input>( - artifact: QueryArtifact, + artifact: QueryArtifact | MutationArtifact, storeName: string, params?: QueryStoreFetchParams<_Data, _Input> ): Promise<{ context: FetchContext - policy: CachePolicy + policy: CachePolicy | undefined params: QueryStoreFetchParams<_Data, _Input> }> { // figure out the right policy let policy = params?.policy - if (!policy) { + if (!policy && artifact.kind === ArtifactKind.Query) { // use the artifact policy as the default, otherwise prefer the cache over the network policy = artifact.policy ?? CachePolicy.CacheOrNetwork } @@ -244,11 +246,15 @@ Please remember to pass event to fetch like so: import type { LoadEvent } from '@sveltejs/kit'; +// in a load function... export async function load(${log.yellow('event')}: LoadEvent) { return { ...load_${storeName}({ ${log.yellow('event')}, variables: { ... } }) }; } + +// in a server-side mutation: +await mutation.mutate({ ... }, ${log.yellow('{ event }')}) ` type FetchGlobalParams<_Data extends GraphQLObject, _Input> = { diff --git a/packages/houdini/src/runtime/client/plugins/fetchParams.ts b/packages/houdini/src/runtime/client/plugins/fetchParams.ts index 26bc7aae9d..039bb44bdd 100644 --- a/packages/houdini/src/runtime/client/plugins/fetchParams.ts +++ b/packages/houdini/src/runtime/client/plugins/fetchParams.ts @@ -10,7 +10,14 @@ export const fetchParamsPlugin: (fn?: FetchParamFn) => ClientPlugin = next({ ...ctx, fetchParams: fn({ - ...ctx, + // most of the stuff comes straight from the context + config: ctx.config, + policy: ctx.policy, + metadata: ctx.metadata, + session: ctx.session, + stuff: ctx.stuff, + // a few fields are renamed or modified + document: ctx.artifact, variables: marshalVariables(ctx), text: ctx.artifact.raw, hash: ctx.artifact.hash, @@ -25,5 +32,5 @@ export type FetchParamsInput = Pick< > & { text: string hash: string - artifact: DocumentArtifact + document: DocumentArtifact } diff --git a/site/src/routes/api/mutation/+page.svx b/site/src/routes/api/mutation/+page.svx index 3cfb0846bc..25daa068e4 100644 --- a/site/src/routes/api/mutation/+page.svx +++ b/site/src/routes/api/mutation/+page.svx @@ -73,7 +73,7 @@ export const actions: Actions = { } `) - return await actionMutation.mutate({ name }, event) + return await actionMutation.mutate({ name }, { event }) } } ``` diff --git a/site/src/routes/guides/release-notes/+page.svx b/site/src/routes/guides/release-notes/+page.svx index daadbcd38b..1c20eefe00 100644 --- a/site/src/routes/guides/release-notes/+page.svx +++ b/site/src/routes/guides/release-notes/+page.svx @@ -283,6 +283,28 @@ has become mostly used for "lazy" stores that don't fetch automatically. On top new imperative cache api relies heavily on `graphql` documents which would mean a lot of accidental loading. At least this way everything is very explicit. +### Server-side Mutations Need an Event + +In order to simplify the mental model for sessions and fetching, server-side mutations +need their event passed explicitly. + +```diff + import { Actions } from './$types' + + const actionMutation = graphql(...) + + export const actions: Actions = { + addUser: async (event) => { + const data = await event.request.formData(); + + const name = data.get('name')?.toString(); + +- return await actionMutation.mutate({ name }, { fetch: event.fetch }); ++ return await actionMutation.mutate({ name }, { event }); + } + } +``` + ## 0.20.0 This release was originally planned to be `1.0` but we have some exciting stuff planned