Skip to content

Commit f886d33

Browse files
fix: allow commands from within endpoints (#14343)
* fix: allow commands from within endpoints fixes #14325 * limit commands to post/put/patch/delete * fix * tweak --------- Co-authored-by: Rich Harris <[email protected]>
1 parent cfaba75 commit f886d33

File tree

8 files changed

+69
-1
lines changed

8 files changed

+69
-1
lines changed

.changeset/sour-vans-fix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: allow commands from within endpoints

packages/kit/src/runtime/app/server/remote/command.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ export function command(validate_or_fn, maybe_fn) {
6464
const wrapper = (arg) => {
6565
const { event, state } = get_request_store();
6666

67-
if (!event.isRemoteRequest) {
67+
if (state.is_endpoint_request) {
68+
if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(event.request.method)) {
69+
throw new Error(
70+
`Cannot call a command (\`${__.name}(${maybe_fn ? '...' : ''})\`) from a ${event.request.method} handler`
71+
);
72+
}
73+
} else if (!event.isRemoteRequest) {
6874
throw new Error(
6975
`Cannot call a command (\`${__.name}(${maybe_fn ? '...' : ''})\`) during server-side rendering`
7076
);

packages/kit/src/runtime/server/endpoint.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export async function render_endpoint(event, event_state, mod, state) {
4141
}
4242
}
4343

44+
event_state.is_endpoint_request = true;
45+
4446
try {
4547
const response = await with_request_store({ event, state: event_state }, () =>
4648
handler(/** @type {import('@sveltejs/kit').RequestEvent<Record<string, any>>} */ (event))

packages/kit/src/types/internal.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ export interface RequestState {
598598
form_instances?: Map<any, any>;
599599
remote_data?: Record<string, MaybePromise<any>>;
600600
refreshes?: Record<string, Promise<any>>;
601+
is_endpoint_request?: boolean;
601602
}
602603

603604
export interface RequestStore {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script>
2+
let result = $state('');
3+
</script>
4+
5+
<p>{result}</p>
6+
7+
<button
8+
onclick={() =>
9+
fetch('/remote/server-endpoint/api')
10+
.then((r) => r.json())
11+
.then((r) => (result = r.result))}
12+
>
13+
get
14+
</button>
15+
16+
<button
17+
onclick={() =>
18+
fetch('/remote/server-endpoint/api', { method: 'POST' })
19+
.then((r) => r.json())
20+
.then((r) => (result = r.result))}
21+
>
22+
post
23+
</button>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { json } from '@sveltejs/kit';
2+
import { add, get } from '../internal.remote';
3+
4+
export async function GET() {
5+
const result = await get();
6+
return json({ result });
7+
}
8+
9+
export async function POST() {
10+
const result = await add(1);
11+
return json({ result });
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { command, query } from '$app/server';
2+
3+
export const get = query(() => {
4+
return 'get';
5+
});
6+
7+
export const add = command('unchecked', () => {
8+
return 'post';
9+
});

packages/kit/test/apps/basics/test/client.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,16 @@ test.describe('remote functions', () => {
17541754
expect(request_count).toBe(1); // no query refreshes, since that happens as part of the command response
17551755
});
17561756

1757+
test('query/command inside endpoint works', async ({ page }) => {
1758+
await page.goto('/remote/server-endpoint');
1759+
1760+
await page.getByRole('button', { name: 'get' }).click();
1761+
await expect(page.locator('p')).toHaveText('get');
1762+
1763+
await page.getByRole('button', { name: 'post' }).click();
1764+
await expect(page.locator('p')).toHaveText('post');
1765+
});
1766+
17571767
test('form.enhance works', async ({ page }) => {
17581768
await page.goto('/remote/form');
17591769
await page.fill('#input-task-enhance', 'abort');

0 commit comments

Comments
 (0)