@instantdb/react-common 0.22.15-experimental.react-common.18536829600.1

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 (65) hide show
  1. package/.tshy/build.json +8 -0
  2. package/.tshy/commonjs.json +16 -0
  3. package/.tshy/esm.json +15 -0
  4. package/README.md +53 -0
  5. package/dist/commonjs/InstantReactAbstractDatabase.d.ts +241 -0
  6. package/dist/commonjs/InstantReactAbstractDatabase.d.ts.map +1 -0
  7. package/dist/commonjs/InstantReactAbstractDatabase.js +323 -0
  8. package/dist/commonjs/InstantReactAbstractDatabase.js.map +1 -0
  9. package/dist/commonjs/InstantReactRoom.d.ts +183 -0
  10. package/dist/commonjs/InstantReactRoom.d.ts.map +1 -0
  11. package/dist/commonjs/InstantReactRoom.js +284 -0
  12. package/dist/commonjs/InstantReactRoom.js.map +1 -0
  13. package/dist/commonjs/index.d.ts +4 -0
  14. package/dist/commonjs/index.d.ts.map +1 -0
  15. package/dist/commonjs/index.js +9 -0
  16. package/dist/commonjs/index.js.map +1 -0
  17. package/dist/commonjs/package.json +3 -0
  18. package/dist/commonjs/useQuery.d.ts +6 -0
  19. package/dist/commonjs/useQuery.d.ts.map +1 -0
  20. package/dist/commonjs/useQuery.js +48 -0
  21. package/dist/commonjs/useQuery.js.map +1 -0
  22. package/dist/commonjs/useTimeout.d.ts +5 -0
  23. package/dist/commonjs/useTimeout.d.ts.map +1 -0
  24. package/dist/commonjs/useTimeout.js +19 -0
  25. package/dist/commonjs/useTimeout.js.map +1 -0
  26. package/dist/commonjs/version.d.ts +3 -0
  27. package/dist/commonjs/version.d.ts.map +1 -0
  28. package/dist/commonjs/version.js +5 -0
  29. package/dist/commonjs/version.js.map +1 -0
  30. package/dist/esm/InstantReactAbstractDatabase.d.ts +241 -0
  31. package/dist/esm/InstantReactAbstractDatabase.d.ts.map +1 -0
  32. package/dist/esm/InstantReactAbstractDatabase.js +320 -0
  33. package/dist/esm/InstantReactAbstractDatabase.js.map +1 -0
  34. package/dist/esm/InstantReactRoom.d.ts +183 -0
  35. package/dist/esm/InstantReactRoom.d.ts.map +1 -0
  36. package/dist/esm/InstantReactRoom.js +275 -0
  37. package/dist/esm/InstantReactRoom.js.map +1 -0
  38. package/dist/esm/index.d.ts +4 -0
  39. package/dist/esm/index.d.ts.map +1 -0
  40. package/dist/esm/index.js +3 -0
  41. package/dist/esm/index.js.map +1 -0
  42. package/dist/esm/package.json +3 -0
  43. package/dist/esm/useQuery.d.ts +6 -0
  44. package/dist/esm/useQuery.d.ts.map +1 -0
  45. package/dist/esm/useQuery.js +45 -0
  46. package/dist/esm/useQuery.js.map +1 -0
  47. package/dist/esm/useTimeout.d.ts +5 -0
  48. package/dist/esm/useTimeout.d.ts.map +1 -0
  49. package/dist/esm/useTimeout.js +16 -0
  50. package/dist/esm/useTimeout.js.map +1 -0
  51. package/dist/esm/version.d.ts +3 -0
  52. package/dist/esm/version.d.ts.map +1 -0
  53. package/dist/esm/version.js +3 -0
  54. package/dist/esm/version.js.map +1 -0
  55. package/dist/standalone/index.js +5993 -0
  56. package/dist/standalone/index.umd.cjs +36 -0
  57. package/package.json +68 -0
  58. package/src/InstantReactAbstractDatabase.tsx +421 -0
  59. package/src/InstantReactRoom.ts +443 -0
  60. package/src/index.ts +4 -0
  61. package/src/useQuery.ts +99 -0
  62. package/src/useTimeout.ts +20 -0
  63. package/src/version.ts +3 -0
  64. package/tsconfig.json +11 -0
  65. package/vite.config.ts +35 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstantReactAbstractDatabase.js","sourceRoot":"","sources":["../../src/InstantReactAbstractDatabase.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n // types\n Auth,\n Storage,\n txInit,\n type AuthState,\n type User,\n type ConnectionStatus,\n type TransactionChunk,\n type RoomSchemaShape,\n type InstaQLParams,\n type InstaQLOptions,\n type InstantConfig,\n type PageInfoResponse,\n InstantCoreDatabase,\n init as core_init,\n InstaQLLifecycleState,\n InstaQLResponse,\n RoomsOf,\n InstantSchemaDef,\n IInstantDatabase,\n InstantError,\n ValidQuery,\n} from '@instantdb/core';\nimport {\n ReactNode,\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport { useQueryInternal } from './useQuery.ts';\nimport { InstantReactRoom, rooms } from './InstantReactRoom.ts';\n\nconst defaultAuthState = {\n isLoading: true,\n user: undefined,\n error: undefined,\n};\n\nexport default abstract class InstantReactAbstractDatabase<\n // need to pull this schema out to another generic for query params, not sure why\n Schema extends InstantSchemaDef<any, any, any>,\n Config extends InstantConfig<Schema, boolean> = InstantConfig<Schema, false>,\n Rooms extends RoomSchemaShape = RoomsOf<Schema>,\n> implements IInstantDatabase<Schema>\n{\n public tx = txInit<Schema>();\n\n public auth: Auth;\n public storage: Storage;\n public core: InstantCoreDatabase<Schema, Config['useDateObjects']>;\n\n /** @deprecated use `core` instead */\n public _core: InstantCoreDatabase<Schema, Config['useDateObjects']>;\n\n static Storage?: any;\n static NetworkListener?: any;\n static EventSourceImpl?: any;\n\n constructor(config: Config, versions?: { [key: string]: string }) {\n this.core = core_init<Schema, Config['useDateObjects']>(\n config,\n // @ts-expect-error because TS can't resolve subclass statics\n this.constructor.Storage,\n // @ts-expect-error because TS can't resolve subclass statics\n this.constructor.NetworkListener,\n versions,\n // @ts-expect-error because TS can't resolve subclass statics\n this.constructor.EventSourceImpl,\n );\n this._core = this.core;\n this.auth = this.core.auth;\n this.storage = this.core.storage;\n }\n\n /**\n * Returns a unique ID for a given `name`. It's stored in local storage,\n * so you will get the same ID across sessions.\n *\n * This is useful for generating IDs that could identify a local device or user.\n *\n * @example\n * const deviceId = await db.getLocalId('device');\n */\n getLocalId = (name: string): Promise<string> => {\n return this.core.getLocalId(name);\n };\n\n /**\n * A hook that returns a unique ID for a given `name`. localIds are\n * stored in local storage, so you will get the same ID across sessions.\n *\n * Initially returns `null`, and then loads the localId.\n *\n * @example\n * const deviceId = db.useLocalId('device');\n * if (!deviceId) return null; // loading\n * console.log('Device ID:', deviceId)\n */\n useLocalId = (name: string): string | null => {\n const [localId, setLocalId] = useState<string | null>(null);\n\n useEffect(() => {\n let mounted = true;\n const f = async () => {\n const id = await this.getLocalId(name);\n if (!mounted) return;\n setLocalId(id);\n };\n f();\n return;\n }, [name]);\n\n return localId;\n };\n\n /**\n * Obtain a handle to a room, which allows you to listen to topics and presence data\n *\n * If you don't provide a `type` or `id`, Instant will default to `_defaultRoomType` and `_defaultRoomId`\n * as the room type and id, respectively.\n *\n * @see https://instantdb.com/docs/presence-and-topics\n *\n * @example\n * const room = db.room('chat', roomId);\n * const { peers } = db.rooms.usePresence(room);\n */\n room<RoomType extends keyof Rooms>(\n type: RoomType = '_defaultRoomType' as RoomType,\n id: string = '_defaultRoomId',\n ) {\n return new InstantReactRoom<Schema, Rooms, RoomType>(this.core, type, id);\n }\n\n /**\n * Hooks for working with rooms\n *\n * @see https://instantdb.com/docs/presence-and-topics\n *\n * @example\n * const room = db.room('chat', roomId);\n * const { peers } = db.rooms.usePresence(room);\n * const publish = db.rooms.usePublishTopic(room, 'emoji');\n * // ...\n */\n rooms = rooms;\n\n /**\n * Use this to write data! You can create, update, delete, and link objects\n *\n * @see https://instantdb.com/docs/instaml\n *\n * @example\n * // Create a new object in the `goals` namespace\n * const goalId = id();\n * db.transact(db.tx.goals[goalId].update({title: \"Get fit\"}))\n *\n * // Update the title\n * db.transact(db.tx.goals[goalId].update({title: \"Get super fit\"}))\n *\n * // Delete it\n * db.transact(db.tx.goals[goalId].delete())\n *\n * // Or create an association:\n * todoId = id();\n * db.transact([\n * db.tx.todos[todoId].update({ title: 'Go on a run' }),\n * db.tx.goals[goalId].link({todos: todoId}),\n * ])\n */\n transact = (\n chunks: TransactionChunk<any, any> | TransactionChunk<any, any>[],\n ) => {\n return this.core.transact(chunks);\n };\n\n /**\n * Use this to query your data!\n *\n * @see https://instantdb.com/docs/instaql\n *\n * @example\n * // listen to all goals\n * const { isLoading, error, data } = db.useQuery({ goals: {} });\n *\n * // goals where the title is \"Get Fit\"\n * const { isLoading, error, data } = db.useQuery({\n * goals: { $: { where: { title: 'Get Fit' } } },\n * });\n *\n * // all goals, _alongside_ their todos\n * const { isLoading, error, data } = db.useQuery({\n * goals: { todos: {} },\n * });\n *\n * // skip if `user` is not logged in\n * const { isLoading, error, data } = db.useQuery(\n * auth.user ? { goals: {} } : null,\n * );\n */\n useQuery = <Q extends ValidQuery<Q, Schema>>(\n query: null | Q,\n opts?: InstaQLOptions,\n ): InstaQLLifecycleState<\n Schema,\n Q,\n NonNullable<Config['useDateObjects']>\n > => {\n return useQueryInternal<Q, Schema, Config['useDateObjects']>(\n this.core,\n query,\n opts,\n ).state;\n };\n\n /**\n * Listen for the logged in state. This is useful\n * for deciding when to show a login screen.\n *\n * Check out the docs for an example `Login` component too!\n *\n * @see https://instantdb.com/docs/auth\n * @example\n * function App() {\n * const { isLoading, user, error } = db.useAuth()\n * if (isLoading) {\n * return <div>Loading...</div>\n * }\n * if (error) {\n * return <div>Uh oh! {error.message}</div>\n * }\n * if (user) {\n * return <Main user={user} />\n * }\n * return <Login />\n * }\n *\n */\n useAuth = (): AuthState => {\n // We use a ref to store the result of the query.\n // This is becuase `useSyncExternalStore` uses `Object.is`\n // to compare the previous and next state.\n // If we don't use a ref, the state will always be considered different, so\n // the component will always re-render.\n const resultCacheRef = useRef<AuthState>(\n this.core._reactor._currentUserCached,\n );\n\n // Similar to `resultCacheRef`, `useSyncExternalStore` will unsubscribe\n // if `subscribe` changes, so we use `useCallback` to memoize the function.\n const subscribe = useCallback((cb: Function) => {\n const unsubscribe = this.core.subscribeAuth((auth) => {\n resultCacheRef.current = { isLoading: false, ...auth };\n cb();\n });\n\n return unsubscribe;\n }, []);\n\n const state = useSyncExternalStore<AuthState>(\n subscribe,\n () => resultCacheRef.current,\n () => defaultAuthState,\n );\n return state;\n };\n\n /**\n * Subscribe to the currently logged in user.\n * If the user is not logged in, this hook with throw an Error.\n * You will want to protect any calls of this hook with a\n * <db.SignedIn> component, or your own logic based on db.useAuth()\n *\n * @see https://instantdb.com/docs/auth\n * @throws Error indicating user not signed in\n * @example\n * function UserDisplay() {\n * const user = db.useUser()\n * return <div>Logged in as: {user.email}</div>\n * }\n *\n * <db.SignedIn>\n * <UserDisplay />\n * </db.SignedIn>\n *\n */\n useUser = (): User => {\n const { user } = this.useAuth();\n if (!user) {\n throw new InstantError(\n 'useUser must be used within an auth-protected route',\n );\n }\n return user;\n };\n\n /**\n * One time query for the logged in state. This is useful\n * for scenarios where you want to know the current auth\n * state without subscribing to changes.\n *\n * @see https://instantdb.com/docs/auth\n * @example\n * const user = await db.getAuth();\n * console.log('logged in as', user.email)\n */\n getAuth(): Promise<User | null> {\n return this.core.getAuth();\n }\n\n /**\n * Listen for connection status changes to Instant. Use this for things like\n * showing connection state to users\n *\n * @see https://www.instantdb.com/docs/patterns#connection-status\n * @example\n * function App() {\n * const status = db.useConnectionStatus()\n * const connectionState =\n * status === 'connecting' || status === 'opened'\n * ? 'authenticating'\n * : status === 'authenticated'\n * ? 'connected'\n * : status === 'closed'\n * ? 'closed'\n * : status === 'errored'\n * ? 'errored'\n * : 'unexpected state';\n *\n * return <div>Connection state: {connectionState}</div>\n * }\n */\n useConnectionStatus = (): ConnectionStatus => {\n const statusRef = useRef<ConnectionStatus>(\n this.core._reactor.status as ConnectionStatus,\n );\n\n const subscribe = useCallback((cb: Function) => {\n const unsubscribe = this.core.subscribeConnectionStatus((newStatus) => {\n if (newStatus !== statusRef.current) {\n statusRef.current = newStatus;\n cb();\n }\n });\n\n return unsubscribe;\n }, []);\n\n const status = useSyncExternalStore<ConnectionStatus>(\n subscribe,\n () => statusRef.current,\n // For SSR, always return 'connecting' as the initial state\n () => 'connecting',\n );\n\n return status;\n };\n\n /**\n * Use this for one-off queries.\n * Returns local data if available, otherwise fetches from the server.\n * Because we want to avoid stale data, this method will throw an error\n * if the user is offline or there is no active connection to the server.\n *\n * @see https://instantdb.com/docs/instaql\n *\n * @example\n *\n * const resp = await db.queryOnce({ goals: {} });\n * console.log(resp.data.goals)\n */\n queryOnce = <Q extends ValidQuery<Q, Schema>>(\n query: Q,\n opts?: InstaQLOptions,\n ): Promise<{\n data: InstaQLResponse<Schema, Q, Config['useDateObjects']>;\n pageInfo: PageInfoResponse<Q>;\n }> => {\n return this.core.queryOnce(query, opts);\n };\n\n /**\n * Only render children if the user is signed in.\n * @see https://instantdb.com/docs/auth\n *\n * @example\n * <db.SignedIn>\n * <MyComponent />\n * </db.SignedIn>\n *\n */\n SignedIn: React.FC<{\n children: ReactNode;\n }> = ({ children }) => {\n const auth = this.useAuth();\n if (auth.isLoading || auth.error || !auth.user) return null;\n\n return <>{children}</>;\n };\n\n /**\n * Only render children if the user is signed out.\n * @see https://instantdb.com/docs/auth\n *\n * @example\n * <db.SignedOut>\n * <MyComponent />\n * </db.SignedOut>\n *\n */\n SignedOut: React.FC<{\n children: ReactNode;\n }> = ({ children }) => {\n const auth = this.useAuth();\n if (auth.isLoading || auth.error || auth.user) return null;\n return <>{children}</>;\n };\n}\n"]}
@@ -0,0 +1,183 @@
1
+ import { type PresenceOpts, type PresenceResponse, type RoomSchemaShape, InstantCoreDatabase, InstantSchemaDef } from '@instantdb/core';
2
+ import { KeyboardEvent } from 'react';
3
+ export type PresenceHandle<PresenceShape, Keys extends keyof PresenceShape> = PresenceResponse<PresenceShape, Keys> & {
4
+ publishPresence: (data: Partial<PresenceShape>) => void;
5
+ };
6
+ export type TypingIndicatorOpts = {
7
+ timeout?: number | null;
8
+ stopOnEnter?: boolean;
9
+ writeOnly?: boolean;
10
+ };
11
+ export type TypingIndicatorHandle<PresenceShape> = {
12
+ active: PresenceShape[];
13
+ setActive(active: boolean): void;
14
+ inputProps: {
15
+ onKeyDown: (e: KeyboardEvent) => void;
16
+ onBlur: () => void;
17
+ };
18
+ };
19
+ export declare const defaultActivityStopTimeout = 1000;
20
+ /**
21
+ * Listen for broadcasted events given a room and topic.
22
+ *
23
+ * @see https://instantdb.com/docs/presence-and-topics
24
+ * @example
25
+ * function App({ roomId }) {
26
+ * const room = db.room('chats', roomId);
27
+ * db.rooms.useTopicEffect(room, 'emoji', (message, peer) => {
28
+ * console.log(peer.name, 'sent', message);
29
+ * });
30
+ * // ...
31
+ * }
32
+ */
33
+ export declare function useTopicEffect<RoomSchema extends RoomSchemaShape, RoomType extends keyof RoomSchema, TopicType extends keyof RoomSchema[RoomType]['topics']>(room: InstantReactRoom<any, RoomSchema, RoomType>, topic: TopicType, onEvent: (event: RoomSchema[RoomType]['topics'][TopicType], peer: RoomSchema[RoomType]['presence']) => any): void;
34
+ /**
35
+ * Broadcast an event to a room.
36
+ *
37
+ * @see https://instantdb.com/docs/presence-and-topics
38
+ * @example
39
+ * function App({ roomId }) {
40
+ * const room = db.room('chat', roomId);
41
+ * const publishTopic = db.rooms.usePublishTopic(room, "emoji");
42
+ *
43
+ * return (
44
+ * <button onClick={() => publishTopic({ emoji: "🔥" })}>Send emoji</button>
45
+ * );
46
+ * }
47
+ *
48
+ */
49
+ export declare function usePublishTopic<RoomSchema extends RoomSchemaShape, RoomType extends keyof RoomSchema, TopicType extends keyof RoomSchema[RoomType]['topics']>(room: InstantReactRoom<any, RoomSchema, RoomType>, topic: TopicType): (data: RoomSchema[RoomType]['topics'][TopicType]) => void;
50
+ /**
51
+ * Listen for peer's presence data in a room, and publish the current user's presence.
52
+ *
53
+ * @see https://instantdb.com/docs/presence-and-topics
54
+ * @example
55
+ * function App({ roomId }) {
56
+ * const {
57
+ * peers,
58
+ * publishPresence
59
+ * } = db.room(roomType, roomId).usePresence({ keys: ["name", "avatar"] });
60
+ *
61
+ * // ...
62
+ * }
63
+ */
64
+ export declare function usePresence<RoomSchema extends RoomSchemaShape, RoomType extends keyof RoomSchema, Keys extends keyof RoomSchema[RoomType]['presence']>(room: InstantReactRoom<any, RoomSchema, RoomType>, opts?: PresenceOpts<RoomSchema[RoomType]['presence'], Keys>): PresenceHandle<RoomSchema[RoomType]['presence'], Keys>;
65
+ /**
66
+ * Publishes presence data to a room
67
+ *
68
+ * @see https://instantdb.com/docs/presence-and-topics
69
+ * @example
70
+ * function App({ roomId, nickname }) {
71
+ * const room = db.room('chat', roomId);
72
+ * db.rooms.useSyncPresence(room, { nickname });
73
+ * }
74
+ */
75
+ export declare function useSyncPresence<RoomSchema extends RoomSchemaShape, RoomType extends keyof RoomSchema>(room: InstantReactRoom<any, RoomSchema, RoomType>, data: Partial<RoomSchema[RoomType]['presence']>, deps?: any[]): void;
76
+ /**
77
+ * Manage typing indicator state
78
+ *
79
+ * @see https://instantdb.com/docs/presence-and-topics
80
+ * @example
81
+ * function App({ roomId }) {
82
+ * const room = db.room('chat', roomId);
83
+ * const {
84
+ * active,
85
+ * setActive,
86
+ * inputProps,
87
+ * } = db.rooms.useTypingIndicator(room, "chat-input");
88
+ *
89
+ * return <input {...inputProps} />;
90
+ * }
91
+ */
92
+ export declare function useTypingIndicator<RoomSchema extends RoomSchemaShape, RoomType extends keyof RoomSchema>(room: InstantReactRoom<any, RoomSchema, RoomType>, inputName: string, opts?: TypingIndicatorOpts): TypingIndicatorHandle<RoomSchema[RoomType]['presence']>;
93
+ export declare const rooms: {
94
+ useTopicEffect: typeof useTopicEffect;
95
+ usePublishTopic: typeof usePublishTopic;
96
+ usePresence: typeof usePresence;
97
+ useSyncPresence: typeof useSyncPresence;
98
+ useTypingIndicator: typeof useTypingIndicator;
99
+ };
100
+ export declare class InstantReactRoom<Schema extends InstantSchemaDef<any, any, any>, RoomSchema extends RoomSchemaShape, RoomType extends keyof RoomSchema> {
101
+ core: InstantCoreDatabase<Schema, boolean>;
102
+ /** @deprecated use `core` instead */
103
+ _core: InstantCoreDatabase<Schema, boolean>;
104
+ type: RoomType;
105
+ id: string;
106
+ constructor(core: InstantCoreDatabase<Schema, boolean>, type: RoomType, id: string);
107
+ /**
108
+ * @deprecated
109
+ * `db.room(...).useTopicEffect` is deprecated. You can replace it with `db.rooms.useTopicEffect`.
110
+ *
111
+ * @example
112
+ *
113
+ * // Before
114
+ * const room = db.room('chat', 'room-id');
115
+ * room.useTopicEffect('emoji', (message, peer) => { });
116
+ *
117
+ * // After
118
+ * const room = db.room('chat', 'room-id');
119
+ * db.rooms.useTopicEffect(room, 'emoji', (message, peer) => { });
120
+ */
121
+ useTopicEffect: <TopicType extends keyof RoomSchema[RoomType]["topics"]>(topic: TopicType, onEvent: (event: RoomSchema[RoomType]["topics"][TopicType], peer: RoomSchema[RoomType]["presence"]) => any) => void;
122
+ /**
123
+ * @deprecated
124
+ * `db.room(...).usePublishTopic` is deprecated. You can replace it with `db.rooms.usePublishTopic`.
125
+ *
126
+ * @example
127
+ *
128
+ * // Before
129
+ * const room = db.room('chat', 'room-id');
130
+ * const publish = room.usePublishTopic('emoji');
131
+ *
132
+ * // After
133
+ * const room = db.room('chat', 'room-id');
134
+ * const publish = db.rooms.usePublishTopic(room, 'emoji');
135
+ */
136
+ usePublishTopic: <Topic extends keyof RoomSchema[RoomType]["topics"]>(topic: Topic) => ((data: RoomSchema[RoomType]["topics"][Topic]) => void);
137
+ /**
138
+ * @deprecated
139
+ * `db.room(...).usePresence` is deprecated. You can replace it with `db.rooms.usePresence`.
140
+ *
141
+ * @example
142
+ *
143
+ * // Before
144
+ * const room = db.room('chat', 'room-id');
145
+ * const { peers } = room.usePresence({ keys: ["name", "avatar"] });
146
+ *
147
+ * // After
148
+ * const room = db.room('chat', 'room-id');
149
+ * const { peers } = db.rooms.usePresence(room, { keys: ["name", "avatar"] });
150
+ */
151
+ usePresence: <Keys extends keyof RoomSchema[RoomType]["presence"]>(opts?: PresenceOpts<RoomSchema[RoomType]["presence"], Keys>) => PresenceHandle<RoomSchema[RoomType]["presence"], Keys>;
152
+ /**
153
+ * @deprecated
154
+ * `db.room(...).useSyncPresence` is deprecated. You can replace it with `db.rooms.useSyncPresence`.
155
+ *
156
+ * @example
157
+ *
158
+ * // Before
159
+ * const room = db.room('chat', 'room-id');
160
+ * room.useSyncPresence(room, { nickname });
161
+ *
162
+ * // After
163
+ * const room = db.room('chat', 'room-id');
164
+ * db.rooms.useSyncPresence(room, { nickname });
165
+ */
166
+ useSyncPresence: (data: Partial<RoomSchema[RoomType]["presence"]>, deps?: any[]) => void;
167
+ /**
168
+ * @deprecated
169
+ * `db.room(...).useTypingIndicator` is deprecated. You can replace it with `db.rooms.useTypingIndicator`.
170
+ *
171
+ * @example
172
+ *
173
+ * // Before
174
+ * const room = db.room('chat', 'room-id');
175
+ * const typing = room.useTypingIndiactor(room, 'chat-input');
176
+ *
177
+ * // After
178
+ * const room = db.room('chat', 'room-id');
179
+ * const typing = db.rooms.useTypingIndiactor(room, 'chat-input');
180
+ */
181
+ useTypingIndicator: (inputName: string, opts?: TypingIndicatorOpts) => TypingIndicatorHandle<RoomSchema[RoomType]["presence"]>;
182
+ }
183
+ //# sourceMappingURL=InstantReactRoom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstantReactRoom.d.ts","sourceRoot":"","sources":["../../src/InstantReactRoom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,275 @@
1
+ import { useCallback, useEffect, useMemo, useState, } from 'react';
2
+ import { useTimeout } from "./useTimeout.js";
3
+ export const defaultActivityStopTimeout = 1000;
4
+ // ------
5
+ // Topics
6
+ /**
7
+ * Listen for broadcasted events given a room and topic.
8
+ *
9
+ * @see https://instantdb.com/docs/presence-and-topics
10
+ * @example
11
+ * function App({ roomId }) {
12
+ * const room = db.room('chats', roomId);
13
+ * db.rooms.useTopicEffect(room, 'emoji', (message, peer) => {
14
+ * console.log(peer.name, 'sent', message);
15
+ * });
16
+ * // ...
17
+ * }
18
+ */
19
+ export function useTopicEffect(room, topic, onEvent) {
20
+ useEffect(() => {
21
+ const unsub = room.core._reactor.subscribeTopic(room.id, topic, (event, peer) => {
22
+ onEvent(event, peer);
23
+ });
24
+ return unsub;
25
+ }, [room.id, topic]);
26
+ }
27
+ /**
28
+ * Broadcast an event to a room.
29
+ *
30
+ * @see https://instantdb.com/docs/presence-and-topics
31
+ * @example
32
+ * function App({ roomId }) {
33
+ * const room = db.room('chat', roomId);
34
+ * const publishTopic = db.rooms.usePublishTopic(room, "emoji");
35
+ *
36
+ * return (
37
+ * <button onClick={() => publishTopic({ emoji: "🔥" })}>Send emoji</button>
38
+ * );
39
+ * }
40
+ *
41
+ */
42
+ export function usePublishTopic(room, topic) {
43
+ useEffect(() => room.core._reactor.joinRoom(room.id), [room.id]);
44
+ const publishTopic = useCallback((data) => {
45
+ room.core._reactor.publishTopic({
46
+ roomType: room.type,
47
+ roomId: room.id,
48
+ topic,
49
+ data,
50
+ });
51
+ }, [room.id, topic]);
52
+ return publishTopic;
53
+ }
54
+ // ---------
55
+ // Presence
56
+ /**
57
+ * Listen for peer's presence data in a room, and publish the current user's presence.
58
+ *
59
+ * @see https://instantdb.com/docs/presence-and-topics
60
+ * @example
61
+ * function App({ roomId }) {
62
+ * const {
63
+ * peers,
64
+ * publishPresence
65
+ * } = db.room(roomType, roomId).usePresence({ keys: ["name", "avatar"] });
66
+ *
67
+ * // ...
68
+ * }
69
+ */
70
+ export function usePresence(room, opts = {}) {
71
+ var _a, _b;
72
+ const [state, setState] = useState(() => {
73
+ var _a;
74
+ return ((_a = room.core._reactor.getPresence(room.type, room.id, opts)) !== null && _a !== void 0 ? _a : {
75
+ peers: {},
76
+ isLoading: true,
77
+ });
78
+ });
79
+ useEffect(() => {
80
+ const unsub = room.core._reactor.subscribePresence(room.type, room.id, opts, (data) => {
81
+ setState(data);
82
+ });
83
+ return unsub;
84
+ }, [room.id, opts.user, (_a = opts.peers) === null || _a === void 0 ? void 0 : _a.join(), (_b = opts.keys) === null || _b === void 0 ? void 0 : _b.join()]);
85
+ const publishPresence = useCallback((data) => {
86
+ room.core._reactor.publishPresence(room.type, room.id, data);
87
+ }, [room.type, room.id]);
88
+ const ret = useMemo(() => {
89
+ return Object.assign(Object.assign({}, state), { publishPresence });
90
+ }, [state, publishPresence]);
91
+ return ret;
92
+ }
93
+ /**
94
+ * Publishes presence data to a room
95
+ *
96
+ * @see https://instantdb.com/docs/presence-and-topics
97
+ * @example
98
+ * function App({ roomId, nickname }) {
99
+ * const room = db.room('chat', roomId);
100
+ * db.rooms.useSyncPresence(room, { nickname });
101
+ * }
102
+ */
103
+ export function useSyncPresence(room, data, deps) {
104
+ useEffect(() => room.core._reactor.joinRoom(room.id, data), [room.id]);
105
+ useEffect(() => {
106
+ return room.core._reactor.publishPresence(room.type, room.id, data);
107
+ }, [room.type, room.id, deps !== null && deps !== void 0 ? deps : JSON.stringify(data)]);
108
+ }
109
+ // -----------------
110
+ // Typing Indicator
111
+ /**
112
+ * Manage typing indicator state
113
+ *
114
+ * @see https://instantdb.com/docs/presence-and-topics
115
+ * @example
116
+ * function App({ roomId }) {
117
+ * const room = db.room('chat', roomId);
118
+ * const {
119
+ * active,
120
+ * setActive,
121
+ * inputProps,
122
+ * } = db.rooms.useTypingIndicator(room, "chat-input");
123
+ *
124
+ * return <input {...inputProps} />;
125
+ * }
126
+ */
127
+ export function useTypingIndicator(room, inputName, opts = {}) {
128
+ const timeout = useTimeout();
129
+ const observedPresence = rooms.usePresence(room, {
130
+ keys: [inputName],
131
+ });
132
+ const active = useMemo(() => {
133
+ var _a;
134
+ const presenceSnapshot = room._core._reactor.getPresence(room.type, room.id);
135
+ return (opts === null || opts === void 0 ? void 0 : opts.writeOnly)
136
+ ? []
137
+ : Object.values((_a = presenceSnapshot === null || presenceSnapshot === void 0 ? void 0 : presenceSnapshot.peers) !== null && _a !== void 0 ? _a : {}).filter((p) => p[inputName] === true);
138
+ }, [opts === null || opts === void 0 ? void 0 : opts.writeOnly, observedPresence]);
139
+ const setActive = useCallback((isActive) => {
140
+ var _a;
141
+ room.core._reactor.publishPresence(room.type, room.id, {
142
+ [inputName]: isActive,
143
+ });
144
+ if (!isActive)
145
+ return;
146
+ if ((opts === null || opts === void 0 ? void 0 : opts.timeout) === null || (opts === null || opts === void 0 ? void 0 : opts.timeout) === 0)
147
+ return;
148
+ timeout.set((_a = opts === null || opts === void 0 ? void 0 : opts.timeout) !== null && _a !== void 0 ? _a : defaultActivityStopTimeout, () => {
149
+ room.core._reactor.publishPresence(room.type, room.id, {
150
+ [inputName]: null,
151
+ });
152
+ });
153
+ }, [room.type, room.id, inputName, opts === null || opts === void 0 ? void 0 : opts.timeout, timeout]);
154
+ const onKeyDown = useCallback((e) => {
155
+ const isEnter = (opts === null || opts === void 0 ? void 0 : opts.stopOnEnter) && e.key === 'Enter';
156
+ const isActive = !isEnter;
157
+ setActive(isActive);
158
+ }, [opts.stopOnEnter, setActive]);
159
+ const onBlur = useCallback(() => {
160
+ setActive(false);
161
+ }, [setActive]);
162
+ const inputProps = useMemo(() => {
163
+ return { onKeyDown, onBlur };
164
+ }, [onKeyDown, onBlur]);
165
+ return {
166
+ active,
167
+ setActive,
168
+ inputProps,
169
+ };
170
+ }
171
+ // --------------
172
+ // Hooks
173
+ export const rooms = {
174
+ useTopicEffect,
175
+ usePublishTopic,
176
+ usePresence,
177
+ useSyncPresence,
178
+ useTypingIndicator,
179
+ };
180
+ // ------------
181
+ // Class
182
+ export class InstantReactRoom {
183
+ constructor(core, type, id) {
184
+ /**
185
+ * @deprecated
186
+ * `db.room(...).useTopicEffect` is deprecated. You can replace it with `db.rooms.useTopicEffect`.
187
+ *
188
+ * @example
189
+ *
190
+ * // Before
191
+ * const room = db.room('chat', 'room-id');
192
+ * room.useTopicEffect('emoji', (message, peer) => { });
193
+ *
194
+ * // After
195
+ * const room = db.room('chat', 'room-id');
196
+ * db.rooms.useTopicEffect(room, 'emoji', (message, peer) => { });
197
+ */
198
+ this.useTopicEffect = (topic, onEvent) => {
199
+ rooms.useTopicEffect(this, topic, onEvent);
200
+ };
201
+ /**
202
+ * @deprecated
203
+ * `db.room(...).usePublishTopic` is deprecated. You can replace it with `db.rooms.usePublishTopic`.
204
+ *
205
+ * @example
206
+ *
207
+ * // Before
208
+ * const room = db.room('chat', 'room-id');
209
+ * const publish = room.usePublishTopic('emoji');
210
+ *
211
+ * // After
212
+ * const room = db.room('chat', 'room-id');
213
+ * const publish = db.rooms.usePublishTopic(room, 'emoji');
214
+ */
215
+ this.usePublishTopic = (topic) => {
216
+ return rooms.usePublishTopic(this, topic);
217
+ };
218
+ /**
219
+ * @deprecated
220
+ * `db.room(...).usePresence` is deprecated. You can replace it with `db.rooms.usePresence`.
221
+ *
222
+ * @example
223
+ *
224
+ * // Before
225
+ * const room = db.room('chat', 'room-id');
226
+ * const { peers } = room.usePresence({ keys: ["name", "avatar"] });
227
+ *
228
+ * // After
229
+ * const room = db.room('chat', 'room-id');
230
+ * const { peers } = db.rooms.usePresence(room, { keys: ["name", "avatar"] });
231
+ */
232
+ this.usePresence = (opts = {}) => {
233
+ return rooms.usePresence(this, opts);
234
+ };
235
+ /**
236
+ * @deprecated
237
+ * `db.room(...).useSyncPresence` is deprecated. You can replace it with `db.rooms.useSyncPresence`.
238
+ *
239
+ * @example
240
+ *
241
+ * // Before
242
+ * const room = db.room('chat', 'room-id');
243
+ * room.useSyncPresence(room, { nickname });
244
+ *
245
+ * // After
246
+ * const room = db.room('chat', 'room-id');
247
+ * db.rooms.useSyncPresence(room, { nickname });
248
+ */
249
+ this.useSyncPresence = (data, deps) => {
250
+ return rooms.useSyncPresence(this, data, deps);
251
+ };
252
+ /**
253
+ * @deprecated
254
+ * `db.room(...).useTypingIndicator` is deprecated. You can replace it with `db.rooms.useTypingIndicator`.
255
+ *
256
+ * @example
257
+ *
258
+ * // Before
259
+ * const room = db.room('chat', 'room-id');
260
+ * const typing = room.useTypingIndiactor(room, 'chat-input');
261
+ *
262
+ * // After
263
+ * const room = db.room('chat', 'room-id');
264
+ * const typing = db.rooms.useTypingIndiactor(room, 'chat-input');
265
+ */
266
+ this.useTypingIndicator = (inputName, opts = {}) => {
267
+ return rooms.useTypingIndicator(this, inputName, opts);
268
+ };
269
+ this.core = core;
270
+ this._core = this.core;
271
+ this.type = type;
272
+ this.id = id;
273
+ }
274
+ }
275
+ //# sourceMappingURL=InstantReactRoom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstantReactRoom.js","sourceRoot":"","sources":["../../src/InstantReactRoom.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n // types\n type PresenceOpts,\n type PresenceResponse,\n type RoomSchemaShape,\n InstantCoreDatabase,\n InstantSchemaDef,\n} from '@instantdb/core';\n\nimport {\n KeyboardEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nimport { useTimeout } from './useTimeout.ts';\n\nexport type PresenceHandle<\n PresenceShape,\n Keys extends keyof PresenceShape,\n> = PresenceResponse<PresenceShape, Keys> & {\n publishPresence: (data: Partial<PresenceShape>) => void;\n};\n\nexport type TypingIndicatorOpts = {\n timeout?: number | null;\n stopOnEnter?: boolean;\n // Perf opt - `active` will always be an empty array\n writeOnly?: boolean;\n};\n\nexport type TypingIndicatorHandle<PresenceShape> = {\n active: PresenceShape[];\n setActive(active: boolean): void;\n inputProps: {\n onKeyDown: (e: KeyboardEvent) => void;\n onBlur: () => void;\n };\n};\n\nexport const defaultActivityStopTimeout = 1_000;\n\n// ------\n// Topics\n\n/**\n * Listen for broadcasted events given a room and topic.\n *\n * @see https://instantdb.com/docs/presence-and-topics\n * @example\n * function App({ roomId }) {\n * const room = db.room('chats', roomId);\n * db.rooms.useTopicEffect(room, 'emoji', (message, peer) => {\n * console.log(peer.name, 'sent', message);\n * });\n * // ...\n * }\n */\nexport function useTopicEffect<\n RoomSchema extends RoomSchemaShape,\n RoomType extends keyof RoomSchema,\n TopicType extends keyof RoomSchema[RoomType]['topics'],\n>(\n room: InstantReactRoom<any, RoomSchema, RoomType>,\n topic: TopicType,\n onEvent: (\n event: RoomSchema[RoomType]['topics'][TopicType],\n peer: RoomSchema[RoomType]['presence'],\n ) => any,\n): void {\n useEffect(() => {\n const unsub = room.core._reactor.subscribeTopic(\n room.id,\n topic,\n (event, peer) => {\n onEvent(event, peer);\n },\n );\n\n return unsub;\n }, [room.id, topic]);\n}\n\n/**\n * Broadcast an event to a room.\n *\n * @see https://instantdb.com/docs/presence-and-topics\n * @example\n * function App({ roomId }) {\n * const room = db.room('chat', roomId);\n * const publishTopic = db.rooms.usePublishTopic(room, \"emoji\");\n *\n * return (\n * <button onClick={() => publishTopic({ emoji: \"🔥\" })}>Send emoji</button>\n * );\n * }\n *\n */\nexport function usePublishTopic<\n RoomSchema extends RoomSchemaShape,\n RoomType extends keyof RoomSchema,\n TopicType extends keyof RoomSchema[RoomType]['topics'],\n>(\n room: InstantReactRoom<any, RoomSchema, RoomType>,\n topic: TopicType,\n): (data: RoomSchema[RoomType]['topics'][TopicType]) => void {\n useEffect(() => room.core._reactor.joinRoom(room.id), [room.id]);\n\n const publishTopic = useCallback(\n (data) => {\n room.core._reactor.publishTopic({\n roomType: room.type,\n roomId: room.id,\n topic,\n data,\n });\n },\n [room.id, topic],\n );\n\n return publishTopic;\n}\n\n// ---------\n// Presence\n\n/**\n * Listen for peer's presence data in a room, and publish the current user's presence.\n *\n * @see https://instantdb.com/docs/presence-and-topics\n * @example\n * function App({ roomId }) {\n * const {\n * peers,\n * publishPresence\n * } = db.room(roomType, roomId).usePresence({ keys: [\"name\", \"avatar\"] });\n *\n * // ...\n * }\n */\nexport function usePresence<\n RoomSchema extends RoomSchemaShape,\n RoomType extends keyof RoomSchema,\n Keys extends keyof RoomSchema[RoomType]['presence'],\n>(\n room: InstantReactRoom<any, RoomSchema, RoomType>,\n opts: PresenceOpts<RoomSchema[RoomType]['presence'], Keys> = {},\n): PresenceHandle<RoomSchema[RoomType]['presence'], Keys> {\n const [state, setState] = useState<\n PresenceResponse<RoomSchema[RoomType]['presence'], Keys>\n >(() => {\n return (\n room.core._reactor.getPresence(room.type, room.id, opts) ?? {\n peers: {},\n isLoading: true,\n }\n );\n });\n\n useEffect(() => {\n const unsub = room.core._reactor.subscribePresence(\n room.type,\n room.id,\n opts,\n (data) => {\n setState(data);\n },\n );\n\n return unsub;\n }, [room.id, opts.user, opts.peers?.join(), opts.keys?.join()]);\n\n const publishPresence = useCallback(\n (data) => {\n room.core._reactor.publishPresence(room.type, room.id, data);\n },\n [room.type, room.id],\n );\n const ret = useMemo(() => {\n return {\n ...state,\n publishPresence,\n };\n }, [state, publishPresence]);\n return ret;\n}\n\n/**\n * Publishes presence data to a room\n *\n * @see https://instantdb.com/docs/presence-and-topics\n * @example\n * function App({ roomId, nickname }) {\n * const room = db.room('chat', roomId);\n * db.rooms.useSyncPresence(room, { nickname });\n * }\n */\nexport function useSyncPresence<\n RoomSchema extends RoomSchemaShape,\n RoomType extends keyof RoomSchema,\n>(\n room: InstantReactRoom<any, RoomSchema, RoomType>,\n data: Partial<RoomSchema[RoomType]['presence']>,\n deps?: any[],\n): void {\n useEffect(() => room.core._reactor.joinRoom(room.id, data), [room.id]);\n useEffect(() => {\n return room.core._reactor.publishPresence(room.type, room.id, data);\n }, [room.type, room.id, deps ?? JSON.stringify(data)]);\n}\n\n// -----------------\n// Typing Indicator\n\n/**\n * Manage typing indicator state\n *\n * @see https://instantdb.com/docs/presence-and-topics\n * @example\n * function App({ roomId }) {\n * const room = db.room('chat', roomId);\n * const {\n * active,\n * setActive,\n * inputProps,\n * } = db.rooms.useTypingIndicator(room, \"chat-input\");\n *\n * return <input {...inputProps} />;\n * }\n */\nexport function useTypingIndicator<\n RoomSchema extends RoomSchemaShape,\n RoomType extends keyof RoomSchema,\n>(\n room: InstantReactRoom<any, RoomSchema, RoomType>,\n inputName: string,\n opts: TypingIndicatorOpts = {},\n): TypingIndicatorHandle<RoomSchema[RoomType]['presence']> {\n const timeout = useTimeout();\n\n const observedPresence = rooms.usePresence(room, {\n keys: [inputName],\n });\n\n const active = useMemo(() => {\n const presenceSnapshot = room._core._reactor.getPresence(\n room.type,\n room.id,\n );\n\n return opts?.writeOnly\n ? []\n : Object.values(presenceSnapshot?.peers ?? {}).filter(\n (p) => p[inputName] === true,\n );\n }, [opts?.writeOnly, observedPresence]);\n\n const setActive = useCallback(\n (isActive: boolean) => {\n room.core._reactor.publishPresence(room.type, room.id, {\n [inputName]: isActive,\n } as unknown as Partial<RoomSchema[RoomType]>);\n\n if (!isActive) return;\n\n if (opts?.timeout === null || opts?.timeout === 0) return;\n\n timeout.set(opts?.timeout ?? defaultActivityStopTimeout, () => {\n room.core._reactor.publishPresence(room.type, room.id, {\n [inputName]: null,\n } as Partial<RoomSchema[RoomType]>);\n });\n },\n [room.type, room.id, inputName, opts?.timeout, timeout],\n );\n const onKeyDown = useCallback(\n (e: KeyboardEvent) => {\n const isEnter = opts?.stopOnEnter && e.key === 'Enter';\n const isActive = !isEnter;\n\n setActive(isActive);\n },\n [opts.stopOnEnter, setActive],\n );\n const onBlur = useCallback(() => {\n setActive(false);\n }, [setActive]);\n\n const inputProps = useMemo(() => {\n return { onKeyDown, onBlur };\n }, [onKeyDown, onBlur]);\n\n return {\n active,\n setActive,\n inputProps,\n };\n}\n\n// --------------\n// Hooks\n\nexport const rooms = {\n useTopicEffect,\n usePublishTopic,\n usePresence,\n useSyncPresence,\n useTypingIndicator,\n};\n\n// ------------\n// Class\n\nexport class InstantReactRoom<\n Schema extends InstantSchemaDef<any, any, any>,\n RoomSchema extends RoomSchemaShape,\n RoomType extends keyof RoomSchema,\n> {\n core: InstantCoreDatabase<Schema, boolean>;\n /** @deprecated use `core` instead */\n _core: InstantCoreDatabase<Schema, boolean>;\n type: RoomType;\n id: string;\n\n constructor(\n core: InstantCoreDatabase<Schema, boolean>,\n type: RoomType,\n id: string,\n ) {\n this.core = core;\n this._core = this.core;\n this.type = type;\n this.id = id;\n }\n\n /**\n * @deprecated\n * `db.room(...).useTopicEffect` is deprecated. You can replace it with `db.rooms.useTopicEffect`.\n *\n * @example\n *\n * // Before\n * const room = db.room('chat', 'room-id');\n * room.useTopicEffect('emoji', (message, peer) => { });\n *\n * // After\n * const room = db.room('chat', 'room-id');\n * db.rooms.useTopicEffect(room, 'emoji', (message, peer) => { });\n */\n useTopicEffect = <TopicType extends keyof RoomSchema[RoomType]['topics']>(\n topic: TopicType,\n onEvent: (\n event: RoomSchema[RoomType]['topics'][TopicType],\n peer: RoomSchema[RoomType]['presence'],\n ) => any,\n ): void => {\n rooms.useTopicEffect(this, topic, onEvent);\n };\n\n /**\n * @deprecated\n * `db.room(...).usePublishTopic` is deprecated. You can replace it with `db.rooms.usePublishTopic`.\n *\n * @example\n *\n * // Before\n * const room = db.room('chat', 'room-id');\n * const publish = room.usePublishTopic('emoji');\n *\n * // After\n * const room = db.room('chat', 'room-id');\n * const publish = db.rooms.usePublishTopic(room, 'emoji');\n */\n usePublishTopic = <Topic extends keyof RoomSchema[RoomType]['topics']>(\n topic: Topic,\n ): ((data: RoomSchema[RoomType]['topics'][Topic]) => void) => {\n return rooms.usePublishTopic(this, topic);\n };\n\n /**\n * @deprecated\n * `db.room(...).usePresence` is deprecated. You can replace it with `db.rooms.usePresence`.\n *\n * @example\n *\n * // Before\n * const room = db.room('chat', 'room-id');\n * const { peers } = room.usePresence({ keys: [\"name\", \"avatar\"] });\n *\n * // After\n * const room = db.room('chat', 'room-id');\n * const { peers } = db.rooms.usePresence(room, { keys: [\"name\", \"avatar\"] });\n */\n usePresence = <Keys extends keyof RoomSchema[RoomType]['presence']>(\n opts: PresenceOpts<RoomSchema[RoomType]['presence'], Keys> = {},\n ): PresenceHandle<RoomSchema[RoomType]['presence'], Keys> => {\n return rooms.usePresence(this, opts);\n };\n\n /**\n * @deprecated\n * `db.room(...).useSyncPresence` is deprecated. You can replace it with `db.rooms.useSyncPresence`.\n *\n * @example\n *\n * // Before\n * const room = db.room('chat', 'room-id');\n * room.useSyncPresence(room, { nickname });\n *\n * // After\n * const room = db.room('chat', 'room-id');\n * db.rooms.useSyncPresence(room, { nickname });\n */\n useSyncPresence = (\n data: Partial<RoomSchema[RoomType]['presence']>,\n deps?: any[],\n ): void => {\n return rooms.useSyncPresence(this, data, deps);\n };\n\n /**\n * @deprecated\n * `db.room(...).useTypingIndicator` is deprecated. You can replace it with `db.rooms.useTypingIndicator`.\n *\n * @example\n *\n * // Before\n * const room = db.room('chat', 'room-id');\n * const typing = room.useTypingIndiactor(room, 'chat-input');\n *\n * // After\n * const room = db.room('chat', 'room-id');\n * const typing = db.rooms.useTypingIndiactor(room, 'chat-input');\n */\n useTypingIndicator = (\n inputName: string,\n opts: TypingIndicatorOpts = {},\n ): TypingIndicatorHandle<RoomSchema[RoomType]['presence']> => {\n return rooms.useTypingIndicator(this, inputName, opts);\n };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import InstantReactAbstractDatabase from './InstantReactAbstractDatabase.tsx';
2
+ import type { InstantReactRoom } from './InstantReactRoom.ts';
3
+ export { InstantReactAbstractDatabase, type InstantReactRoom };
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,4BAA4B,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,4BAA4B,EAAE,KAAK,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import InstantReactAbstractDatabase from "./InstantReactAbstractDatabase.js";
2
+ export { InstantReactAbstractDatabase };
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,4BAA4B,MAAM,mCAAoC,CAAC;AAG9E,OAAO,EAAE,4BAA4B,EAAyB,CAAC","sourcesContent":["import InstantReactAbstractDatabase from './InstantReactAbstractDatabase.tsx';\nimport type { InstantReactRoom } from './InstantReactRoom.ts';\n\nexport { InstantReactAbstractDatabase, type InstantReactRoom };\n"]}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,6 @@
1
+ import { type InstaQLOptions, InstantCoreDatabase, InstaQLLifecycleState, InstantSchemaDef, ValidQuery } from '@instantdb/core';
2
+ export declare function useQueryInternal<Q extends ValidQuery<Q, Schema>, Schema extends InstantSchemaDef<any, any, any>, UseDates extends boolean>(_core: InstantCoreDatabase<Schema, UseDates>, _query: null | Q, _opts?: InstaQLOptions): {
3
+ state: InstaQLLifecycleState<Schema, Q, UseDates>;
4
+ query: any;
5
+ };
6
+ //# sourceMappingURL=useQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQuery.d.ts","sourceRoot":"","sources":["../../src/useQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EAEnB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACX,MAAM,iBAAiB,CAAC;AAoBzB,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,EAC/B,MAAM,SAAS,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAC9C,QAAQ,SAAS,OAAO,EAExB,KAAK,EAAE,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAC5C,MAAM,EAAE,IAAI,GAAG,CAAC,EAChB,KAAK,CAAC,EAAE,cAAc,GACrB;IACD,KAAK,EAAE,qBAAqB,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClD,KAAK,EAAE,GAAG,CAAC;CACZ,CAyDA"}
@@ -0,0 +1,45 @@
1
+ import { weakHash, coerceQuery, } from '@instantdb/core';
2
+ import { useCallback, useRef, useSyncExternalStore } from 'react';
3
+ const defaultState = {
4
+ isLoading: true,
5
+ data: undefined,
6
+ pageInfo: undefined,
7
+ error: undefined,
8
+ };
9
+ function stateForResult(result) {
10
+ return Object.assign({ isLoading: !Boolean(result), data: undefined, pageInfo: undefined, error: undefined }, (result ? result : {}));
11
+ }
12
+ export function useQueryInternal(_core, _query, _opts) {
13
+ if (_query && _opts && 'ruleParams' in _opts) {
14
+ _query = Object.assign({ $$ruleParams: _opts['ruleParams'] }, _query);
15
+ }
16
+ const query = _query ? coerceQuery(_query) : null;
17
+ const queryHash = weakHash(query);
18
+ // We use a ref to store the result of the query.
19
+ // This is becuase `useSyncExternalStore` uses `Object.is`
20
+ // to compare the previous and next state.
21
+ // If we don't use a ref, the state will always be considered different, so
22
+ // the component will always re-render.
23
+ const resultCacheRef = useRef(stateForResult(_core._reactor.getPreviousResult(query)));
24
+ // Similar to `resultCacheRef`, `useSyncExternalStore` will unsubscribe
25
+ // if `subscribe` changes, so we use `useCallback` to memoize the function.
26
+ const subscribe = useCallback((cb) => {
27
+ // Update the ref when the query changes to avoid showing stale data
28
+ resultCacheRef.current = stateForResult(_core._reactor.getPreviousResult(query));
29
+ // Don't subscribe if query is null
30
+ if (!query) {
31
+ const unsubscribe = () => { };
32
+ return unsubscribe;
33
+ }
34
+ const unsubscribe = _core.subscribeQuery(query, (result) => {
35
+ resultCacheRef.current = Object.assign({ isLoading: !Boolean(result), data: undefined, pageInfo: undefined, error: undefined }, result);
36
+ cb();
37
+ });
38
+ return unsubscribe;
39
+ },
40
+ // Build a new subscribe function if the query changes
41
+ [queryHash]);
42
+ const state = useSyncExternalStore(subscribe, () => resultCacheRef.current, () => defaultState);
43
+ return { state, query };
44
+ }
45
+ //# sourceMappingURL=useQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../../src/useQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,WAAW,GAQZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElE,MAAM,YAAY,GAAG;IACnB,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,SAAS;IACf,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,SAAS;CACjB,CAAC;AAEF,SAAS,cAAc,CAAC,MAAW;IACjC,uBACE,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAC3B,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,SAAS,IACb,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EACzB;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAK9B,KAA4C,EAC5C,MAAgB,EAChB,KAAsB;IAKtB,IAAI,MAAM,IAAI,KAAK,IAAI,YAAY,IAAI,KAAK,EAAE,CAAC;QAC7C,MAAM,mBAAK,YAAY,EAAE,KAAK,CAAC,YAAY,CAAC,IAAK,MAAM,CAAE,CAAC;IAC5D,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElC,iDAAiD;IACjD,0DAA0D;IAC1D,0CAA0C;IAC1C,2EAA2E;IAC3E,uCAAuC;IACvC,MAAM,cAAc,GAAG,MAAM,CAC3B,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CACxD,CAAC;IAEF,uEAAuE;IACvE,2EAA2E;IAC3E,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,EAAE,EAAE,EAAE;QACL,oEAAoE;QACpE,cAAc,CAAC,OAAO,GAAG,cAAc,CACrC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CACxC,CAAC;QAEF,mCAAmC;QACnC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,WAAW,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;YAC7B,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAc,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE;YACtE,cAAc,CAAC,OAAO,mBACpB,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAC3B,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,SAAS,IACb,MAAM,CACV,CAAC;YAEF,EAAE,EAAE,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,sDAAsD;IACtD,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,MAAM,KAAK,GAAG,oBAAoB,CAGhC,SAAS,EACT,GAAG,EAAE,CAAC,cAAc,CAAC,OAAO,EAC5B,GAAG,EAAE,CAAC,YAAY,CACnB,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC","sourcesContent":["import {\n weakHash,\n coerceQuery,\n type InstaQLParams,\n type InstaQLOptions,\n type InstantGraph,\n InstantCoreDatabase,\n InstaQLLifecycleState,\n InstantSchemaDef,\n ValidQuery,\n} from '@instantdb/core';\nimport { useCallback, useRef, useSyncExternalStore } from 'react';\n\nconst defaultState = {\n isLoading: true,\n data: undefined,\n pageInfo: undefined,\n error: undefined,\n};\n\nfunction stateForResult(result: any) {\n return {\n isLoading: !Boolean(result),\n data: undefined,\n pageInfo: undefined,\n error: undefined,\n ...(result ? result : {}),\n };\n}\n\nexport function useQueryInternal<\n Q extends ValidQuery<Q, Schema>,\n Schema extends InstantSchemaDef<any, any, any>,\n UseDates extends boolean,\n>(\n _core: InstantCoreDatabase<Schema, UseDates>,\n _query: null | Q,\n _opts?: InstaQLOptions,\n): {\n state: InstaQLLifecycleState<Schema, Q, UseDates>;\n query: any;\n} {\n if (_query && _opts && 'ruleParams' in _opts) {\n _query = { $$ruleParams: _opts['ruleParams'], ..._query };\n }\n const query = _query ? coerceQuery(_query) : null;\n const queryHash = weakHash(query);\n\n // We use a ref to store the result of the query.\n // This is becuase `useSyncExternalStore` uses `Object.is`\n // to compare the previous and next state.\n // If we don't use a ref, the state will always be considered different, so\n // the component will always re-render.\n const resultCacheRef = useRef<InstaQLLifecycleState<Schema, Q, UseDates>>(\n stateForResult(_core._reactor.getPreviousResult(query)),\n );\n\n // Similar to `resultCacheRef`, `useSyncExternalStore` will unsubscribe\n // if `subscribe` changes, so we use `useCallback` to memoize the function.\n const subscribe = useCallback(\n (cb) => {\n // Update the ref when the query changes to avoid showing stale data\n resultCacheRef.current = stateForResult(\n _core._reactor.getPreviousResult(query),\n );\n\n // Don't subscribe if query is null\n if (!query) {\n const unsubscribe = () => {};\n return unsubscribe;\n }\n\n const unsubscribe = _core.subscribeQuery<Q, UseDates>(query, (result) => {\n resultCacheRef.current = {\n isLoading: !Boolean(result),\n data: undefined,\n pageInfo: undefined,\n error: undefined,\n ...result,\n };\n\n cb();\n });\n\n return unsubscribe;\n },\n // Build a new subscribe function if the query changes\n [queryHash],\n );\n\n const state = useSyncExternalStore<\n InstaQLLifecycleState<Schema, Q, UseDates>\n >(\n subscribe,\n () => resultCacheRef.current,\n () => defaultState,\n );\n return { state, query };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export declare function useTimeout(): {
2
+ set: (delay: number, fn: () => void) => void;
3
+ clear: () => void;
4
+ };
5
+ //# sourceMappingURL=useTimeout.d.ts.map