svelte-realtime 0.4.12 → 0.4.13
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.
- package/README.md +40 -7
- package/package.json +1 -1
- package/server.js +10 -1
- package/vite.js +5 -5
package/README.md
CHANGED
|
@@ -634,9 +634,9 @@ Call live functions from `+page.server.js` to load data server-side, then hydrat
|
|
|
634
634
|
|
|
635
635
|
```js
|
|
636
636
|
// src/routes/chat/+page.server.js
|
|
637
|
-
export async function load({ platform }) {
|
|
637
|
+
export async function load({ platform, locals }) {
|
|
638
638
|
const { messages } = await import('$live/chat');
|
|
639
|
-
const data = await messages.load(platform);
|
|
639
|
+
const data = await messages.load(platform, { user: locals.user });
|
|
640
640
|
return { messages: data };
|
|
641
641
|
}
|
|
642
642
|
```
|
|
@@ -884,14 +884,47 @@ Call `configure()` once at app startup. The hooks fire on state transitions only
|
|
|
884
884
|
When using svelte-realtime from a client that runs on a different origin (Svelte Native, React Native, or any standalone app), pass the `url` option to point at your SvelteKit backend:
|
|
885
885
|
|
|
886
886
|
```js
|
|
887
|
-
import { configure } from 'svelte-realtime/client';
|
|
887
|
+
import { configure, __rpc, __stream } from 'svelte-realtime/client';
|
|
888
888
|
|
|
889
|
-
configure({
|
|
890
|
-
|
|
891
|
-
|
|
889
|
+
configure({ url: 'wss://my-sveltekit-app.com/ws' });
|
|
890
|
+
|
|
891
|
+
// Call a live function (equivalent to $live/chat.sendMessage, but untyped)
|
|
892
|
+
const sendMessage = __rpc('chat/sendMessage');
|
|
893
|
+
await sendMessage('hello');
|
|
894
|
+
|
|
895
|
+
// Subscribe to a stream (returns a Svelte store)
|
|
896
|
+
const messages = __stream('chat/messages', { merge: 'crud', key: 'id' });
|
|
897
|
+
messages.subscribe((value) => console.log(value));
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
The typed `$live/*` imports and stream hydration are generated by the Vite plugin and only work inside a SvelteKit project. Outside SvelteKit, use `__rpc()` and `__stream()` directly. You get the same reconnection, offline queue, and batching -- just without codegen and types.
|
|
901
|
+
|
|
902
|
+
When `url` is set, the default same-origin WebSocket URL is bypassed entirely. Requires `svelte-adapter-uws` 0.4.8+.
|
|
903
|
+
|
|
904
|
+
Browser clients authenticate via cookies set during login. Native clients typically use a token instead. Your upgrade hook can support both:
|
|
905
|
+
|
|
906
|
+
```js
|
|
907
|
+
// src/hooks.ws.js
|
|
908
|
+
export { message } from 'svelte-realtime/server';
|
|
909
|
+
|
|
910
|
+
export function upgrade({ cookies, url }) {
|
|
911
|
+
// Browser -- cookie auth
|
|
912
|
+
const session = cookies.session_id;
|
|
913
|
+
if (session) return validateSession(session);
|
|
914
|
+
|
|
915
|
+
// Native app -- token auth via query string
|
|
916
|
+
const token = new URL(url, 'http://n').searchParams.get('token');
|
|
917
|
+
if (token) return validateToken(token);
|
|
918
|
+
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
892
921
|
```
|
|
893
922
|
|
|
894
|
-
|
|
923
|
+
The native client passes the token in the URL:
|
|
924
|
+
|
|
925
|
+
```js
|
|
926
|
+
configure({ url: 'wss://my-sveltekit-app.com/ws?token=...' });
|
|
927
|
+
```
|
|
895
928
|
|
|
896
929
|
---
|
|
897
930
|
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -13,6 +13,9 @@ const guards = new Map();
|
|
|
13
13
|
/** @type {Set<Function>} Streams with onUnsubscribe hooks (for iterating static matches in close) */
|
|
14
14
|
const _streamsWithUnsubscribe = new Set();
|
|
15
15
|
|
|
16
|
+
/** @type {Set<string>} Paths that already warned about null ctx.user in __directCall */
|
|
17
|
+
const _directCallWarned = new Set();
|
|
18
|
+
|
|
16
19
|
/**
|
|
17
20
|
* Tag a topic function with __topicUsesCtx by inspecting its first parameter name.
|
|
18
21
|
*
|
|
@@ -2472,7 +2475,13 @@ export async function __directCall(path, args, platform, options) {
|
|
|
2472
2475
|
// Run module guard
|
|
2473
2476
|
const modulePath = /** @type {any} */ (fn).__modulePath || path.substring(0, path.lastIndexOf('/'));
|
|
2474
2477
|
const guardFn = await _resolveGuard(modulePath);
|
|
2475
|
-
if (guardFn)
|
|
2478
|
+
if (guardFn) {
|
|
2479
|
+
if (ctx.user === null && typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production' && !_directCallWarned.has(path)) {
|
|
2480
|
+
_directCallWarned.add(path);
|
|
2481
|
+
console.warn(`[svelte-realtime] .load() is calling guard for '${path}' with ctx.user = null. Pass { user } in the options to provide user data:\n stream.load(platform, { user: locals.user })\n See: https://svti.me/ssr`);
|
|
2482
|
+
}
|
|
2483
|
+
await guardFn(ctx);
|
|
2484
|
+
}
|
|
2476
2485
|
|
|
2477
2486
|
if (/** @type {any} */ (fn).__isStream) {
|
|
2478
2487
|
if (/** @type {any} */ (fn).__isGated) {
|
package/vite.js
CHANGED
|
@@ -1604,7 +1604,7 @@ function _generateTypeDeclarations(liveDir, dir) {
|
|
|
1604
1604
|
if (isTS) {
|
|
1605
1605
|
const returnType = _extractStreamReturnType(source, name);
|
|
1606
1606
|
const storeType = `StreamStore<${returnType} | undefined | { error: RpcError }>`;
|
|
1607
|
-
const loadSig = `{ load(platform: any, options?: { args?: any[] }): Promise<${returnType}> }`;
|
|
1607
|
+
const loadSig = `{ load(platform: any, options?: { args?: any[]; user?: any }): Promise<${returnType}> }`;
|
|
1608
1608
|
if (isDynamic) {
|
|
1609
1609
|
const factoryParams = _extractDynamicFactoryParams(source, name, 'live\\.stream');
|
|
1610
1610
|
exports.push(` export const ${name}: (${factoryParams} => ${storeType}) & ${loadSig};`);
|
|
@@ -1612,7 +1612,7 @@ function _generateTypeDeclarations(liveDir, dir) {
|
|
|
1612
1612
|
exports.push(` export const ${name}: ${storeType} & ${loadSig};`);
|
|
1613
1613
|
}
|
|
1614
1614
|
} else {
|
|
1615
|
-
const loadSig = `{ load(platform: any, options?: { args?: any[] }): Promise<any> }`;
|
|
1615
|
+
const loadSig = `{ load(platform: any, options?: { args?: any[]; user?: any }): Promise<any> }`;
|
|
1616
1616
|
if (isDynamic) {
|
|
1617
1617
|
exports.push(` export const ${name}: ((...args: any[]) => StreamStore<any>) & ${loadSig};`);
|
|
1618
1618
|
} else {
|
|
@@ -1629,7 +1629,7 @@ function _generateTypeDeclarations(liveDir, dir) {
|
|
|
1629
1629
|
if (!exports.some(e => e.includes(`export const ${name}:`))) {
|
|
1630
1630
|
needsStreamStore = true;
|
|
1631
1631
|
const isDynamic = _isDynamicExport(source, name, 'live\\.channel');
|
|
1632
|
-
const loadSig = `{ load(platform: any, options?: { args?: any[] }): Promise<any> }`;
|
|
1632
|
+
const loadSig = `{ load(platform: any, options?: { args?: any[]; user?: any }): Promise<any> }`;
|
|
1633
1633
|
if (isDynamic) {
|
|
1634
1634
|
if (isTS) {
|
|
1635
1635
|
const factoryParams = _extractDynamicFactoryParams(source, name, 'live\\.channel');
|
|
@@ -1650,7 +1650,7 @@ function _generateTypeDeclarations(liveDir, dir) {
|
|
|
1650
1650
|
handledNames.add(name);
|
|
1651
1651
|
if (!exports.some(e => e.includes(`export const ${name}:`))) {
|
|
1652
1652
|
needsStreamStore = true;
|
|
1653
|
-
exports.push(` export const ${name}: StreamStore<any> & { load(platform: any, options?: { args?: any[] }): Promise<any> };`);
|
|
1653
|
+
exports.push(` export const ${name}: StreamStore<any> & { load(platform: any, options?: { args?: any[]; user?: any }): Promise<any> };`);
|
|
1654
1654
|
}
|
|
1655
1655
|
}
|
|
1656
1656
|
|
|
@@ -1661,7 +1661,7 @@ function _generateTypeDeclarations(liveDir, dir) {
|
|
|
1661
1661
|
handledNames.add(name);
|
|
1662
1662
|
if (!exports.some(e => e.includes(`export const ${name}:`))) {
|
|
1663
1663
|
needsStreamStore = true;
|
|
1664
|
-
exports.push(` export const ${name}: StreamStore<any> & { load(platform: any, options?: { args?: any[] }): Promise<any> };`);
|
|
1664
|
+
exports.push(` export const ${name}: StreamStore<any> & { load(platform: any, options?: { args?: any[]; user?: any }): Promise<any> };`);
|
|
1665
1665
|
}
|
|
1666
1666
|
}
|
|
1667
1667
|
|