@instantdb/react 0.22.95 → 0.22.96-experimental.add-posthog-frontend.20386914944.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 (58) hide show
  1. package/dist/standalone/index.js +1507 -1563
  2. package/dist/standalone/index.umd.cjs +14 -14
  3. package/package.json +6 -18
  4. package/tsconfig.json +0 -1
  5. package/dist/commonjs/next-ssr/HydrationStreamProvider.d.ts +0 -66
  6. package/dist/commonjs/next-ssr/HydrationStreamProvider.d.ts.map +0 -1
  7. package/dist/commonjs/next-ssr/HydrationStreamProvider.js +0 -140
  8. package/dist/commonjs/next-ssr/HydrationStreamProvider.js.map +0 -1
  9. package/dist/commonjs/next-ssr/InstantNextDatabase.d.ts +0 -12
  10. package/dist/commonjs/next-ssr/InstantNextDatabase.d.ts.map +0 -1
  11. package/dist/commonjs/next-ssr/InstantNextDatabase.js +0 -42
  12. package/dist/commonjs/next-ssr/InstantNextDatabase.js.map +0 -1
  13. package/dist/commonjs/next-ssr/InstantSuspenseProvider.d.ts +0 -28
  14. package/dist/commonjs/next-ssr/InstantSuspenseProvider.d.ts.map +0 -1
  15. package/dist/commonjs/next-ssr/InstantSuspenseProvider.js +0 -99
  16. package/dist/commonjs/next-ssr/InstantSuspenseProvider.js.map +0 -1
  17. package/dist/commonjs/next-ssr/getUserFromInstantCookie.d.ts +0 -3
  18. package/dist/commonjs/next-ssr/getUserFromInstantCookie.d.ts.map +0 -1
  19. package/dist/commonjs/next-ssr/getUserFromInstantCookie.js +0 -21
  20. package/dist/commonjs/next-ssr/getUserFromInstantCookie.js.map +0 -1
  21. package/dist/commonjs/next-ssr/htmlescape.d.ts +0 -3
  22. package/dist/commonjs/next-ssr/htmlescape.d.ts.map +0 -1
  23. package/dist/commonjs/next-ssr/htmlescape.js +0 -25
  24. package/dist/commonjs/next-ssr/htmlescape.js.map +0 -1
  25. package/dist/commonjs/next-ssr/index.d.ts +0 -28
  26. package/dist/commonjs/next-ssr/index.d.ts.map +0 -1
  27. package/dist/commonjs/next-ssr/index.js +0 -43
  28. package/dist/commonjs/next-ssr/index.js.map +0 -1
  29. package/dist/esm/next-ssr/HydrationStreamProvider.d.ts +0 -66
  30. package/dist/esm/next-ssr/HydrationStreamProvider.d.ts.map +0 -1
  31. package/dist/esm/next-ssr/HydrationStreamProvider.js +0 -103
  32. package/dist/esm/next-ssr/HydrationStreamProvider.js.map +0 -1
  33. package/dist/esm/next-ssr/InstantNextDatabase.d.ts +0 -12
  34. package/dist/esm/next-ssr/InstantNextDatabase.d.ts.map +0 -1
  35. package/dist/esm/next-ssr/InstantNextDatabase.js +0 -35
  36. package/dist/esm/next-ssr/InstantNextDatabase.js.map +0 -1
  37. package/dist/esm/next-ssr/InstantSuspenseProvider.d.ts +0 -28
  38. package/dist/esm/next-ssr/InstantSuspenseProvider.d.ts.map +0 -1
  39. package/dist/esm/next-ssr/InstantSuspenseProvider.js +0 -94
  40. package/dist/esm/next-ssr/InstantSuspenseProvider.js.map +0 -1
  41. package/dist/esm/next-ssr/getUserFromInstantCookie.d.ts +0 -3
  42. package/dist/esm/next-ssr/getUserFromInstantCookie.d.ts.map +0 -1
  43. package/dist/esm/next-ssr/getUserFromInstantCookie.js +0 -17
  44. package/dist/esm/next-ssr/getUserFromInstantCookie.js.map +0 -1
  45. package/dist/esm/next-ssr/htmlescape.d.ts +0 -3
  46. package/dist/esm/next-ssr/htmlescape.d.ts.map +0 -1
  47. package/dist/esm/next-ssr/htmlescape.js +0 -21
  48. package/dist/esm/next-ssr/htmlescape.js.map +0 -1
  49. package/dist/esm/next-ssr/index.d.ts +0 -28
  50. package/dist/esm/next-ssr/index.d.ts.map +0 -1
  51. package/dist/esm/next-ssr/index.js +0 -32
  52. package/dist/esm/next-ssr/index.js.map +0 -1
  53. package/src/next-ssr/HydrationStreamProvider.tsx +0 -200
  54. package/src/next-ssr/InstantNextDatabase.tsx +0 -56
  55. package/src/next-ssr/InstantSuspenseProvider.tsx +0 -189
  56. package/src/next-ssr/getUserFromInstantCookie.ts +0 -11
  57. package/src/next-ssr/htmlescape.ts +0 -24
  58. package/src/next-ssr/index.tsx +0 -47
@@ -1,200 +0,0 @@
1
- 'use client';
2
-
3
- // This allows us to send serialized json from the server to the client using 'useServerInsertedHTML'
4
- // We are allowed to send whatever json we want, however it must be triggered at the same time as the client is recieving new html to display
5
- // after a suspsense boundary resolves
6
- // We do this to send a list of triples and attrs for each query that the server made so they can be pre-filled on the client render.
7
- // useServerInsertedHTML is called whenever a suspense boundary resolves, resulting in new html being streamed down to the client.
8
-
9
- export const isServer = typeof window === 'undefined' || 'Deno' in globalThis;
10
-
11
- import { useServerInsertedHTML } from 'next/navigation.js';
12
-
13
- import * as React from 'react';
14
- import { htmlEscapeJsonString } from './htmlescape.js';
15
-
16
- const serializedSymbol = Symbol('serialized');
17
-
18
- interface DataTransformer {
19
- serialize: (object: any) => any;
20
- deserialize: (object: any) => any;
21
- }
22
-
23
- type Serialized<TData> = unknown & {
24
- [serializedSymbol]: TData;
25
- };
26
-
27
- interface TypedDataTransformer<TData> {
28
- serialize: (obj: TData) => Serialized<TData>;
29
- deserialize: (obj: Serialized<TData>) => TData;
30
- }
31
-
32
- interface HydrationStreamContext<TShape> {
33
- id: string;
34
- stream: {
35
- /**
36
- * **Server method**
37
- * Push a new entry to the stream
38
- * Will be ignored on the client
39
- */
40
- push: (...shape: Array<TShape>) => void;
41
- };
42
- }
43
-
44
- export interface HydrationStreamProviderProps<TShape> {
45
- children: React.ReactNode;
46
- /**
47
- * Optional transformer to serialize/deserialize the data
48
- * Example devalue, superjson et al
49
- */
50
- transformer?: DataTransformer;
51
- /**
52
- * **Client method**
53
- * Called in the browser when new entries are received
54
- */
55
- onEntries: (entries: Array<TShape>) => void;
56
- /**
57
- * **Server method**
58
- * onFlush is called on the server when the cache is flushed
59
- */
60
- onFlush?: () => Array<TShape>;
61
- /**
62
- * A nonce that'll allow the inline script to be executed when Content Security Policy is enforced
63
- */
64
- nonce?: string;
65
- }
66
-
67
- export function createHydrationStreamProvider<TShape>() {
68
- const context = React.createContext<HydrationStreamContext<TShape>>(
69
- null as any,
70
- );
71
- /**
72
-
73
- * 1. (Happens on server): `useServerInsertedHTML()` is called **on the server** whenever a `Suspense`-boundary completes
74
- * - This means that we might have some new entries in the cache that needs to be flushed
75
- * - We pass these to the client by inserting a `<script>`-tag where we do `window[id].push(serializedVersionOfCache)`
76
- * 2. (Happens in browser) In `useEffect()`:
77
- * - We check if `window[id]` is set to an array and call `push()` on all the entries which will call `onEntries()` with the new entries
78
- * - We replace `window[id]` with a `push()`-method that will be called whenever new entries are received
79
- **/
80
- function UseClientHydrationStreamProvider(props: {
81
- children: React.ReactNode;
82
- /**
83
- * Optional transformer to serialize/deserialize the data
84
- * Example devalue, superjson et al
85
- */
86
- transformer?: DataTransformer;
87
- /**
88
- * **Client method**
89
- * Called in the browser when new entries are received
90
- */
91
- onEntries: (entries: Array<TShape>) => void;
92
- /**
93
- * **Server method**
94
- * onFlush is called on the server when the cache is flushed
95
- */
96
- onFlush?: () => Array<TShape>;
97
- /**
98
- * A nonce that'll allow the inline script to be executed when Content Security Policy is enforced
99
- */
100
- nonce?: string;
101
- }) {
102
- // unique id for the cache provider
103
- const id = `__RQ${React.useId()}`;
104
- const idJSON = htmlEscapeJsonString(JSON.stringify(id));
105
-
106
- const [transformer] = React.useState(
107
- () =>
108
- (props.transformer ?? {
109
- // noop
110
- serialize: (obj: any) => obj,
111
- deserialize: (obj: any) => obj,
112
- }) as unknown as TypedDataTransformer<TShape>,
113
- );
114
-
115
- // <server stuff>
116
- const [stream] = React.useState<Array<TShape>>(() => {
117
- if (!isServer) {
118
- return {
119
- push() {
120
- // no-op on the client
121
- },
122
- } as unknown as Array<TShape>;
123
- }
124
- return [];
125
- });
126
- const count = React.useRef(0);
127
- useServerInsertedHTML(() => {
128
- // This only happens on the server
129
- stream.push(...(props.onFlush?.() ?? []));
130
-
131
- if (!stream.length) {
132
- return null;
133
- }
134
- // console.log(`pushing ${stream.length} entries`)
135
- const serializedCacheArgs = stream
136
- .map((entry) => transformer.serialize(entry))
137
- .map((entry) => JSON.stringify(entry))
138
- .join(',');
139
-
140
- // Flush stream
141
- // eslint-disable-next-line react-hooks/immutability
142
- stream.length = 0;
143
-
144
- const html: Array<string> = [
145
- `window[${idJSON}] = window[${idJSON}] || [];`,
146
- `window[${idJSON}].push(${htmlEscapeJsonString(serializedCacheArgs)});`,
147
- ];
148
- return (
149
- <script
150
- key={count.current++}
151
- nonce={props.nonce}
152
- dangerouslySetInnerHTML={{
153
- __html: html.join(''),
154
- }}
155
- />
156
- );
157
- });
158
- // </server stuff>
159
-
160
- // <client stuff>
161
- // Setup and run the onEntries handler on the client only, but do it during
162
- // the initial render so children have access to the data immediately
163
- // This is important to avoid the client suspending during the initial render
164
- // if the data has not yet been hydrated.
165
- if (!isServer) {
166
- const win = window as any;
167
- if (!win[id]?.initialized) {
168
- // Client: consume cache:
169
- const onEntries = (...serializedEntries: Array<Serialized<TShape>>) => {
170
- const entries = serializedEntries.map((serialized) =>
171
- transformer.deserialize(serialized),
172
- );
173
- props.onEntries(entries);
174
- };
175
-
176
- const winStream: Array<Serialized<TShape>> = win[id] ?? [];
177
-
178
- onEntries(...winStream);
179
-
180
- // eslint-disable-next-line react-hooks/immutability
181
- win[id] = {
182
- initialized: true,
183
- push: onEntries,
184
- };
185
- }
186
- }
187
- // </client stuff>
188
-
189
- return (
190
- <context.Provider value={{ stream, id }}>
191
- {props.children}
192
- </context.Provider>
193
- );
194
- }
195
-
196
- return {
197
- Provider: UseClientHydrationStreamProvider,
198
- context,
199
- };
200
- }
@@ -1,56 +0,0 @@
1
- import {
2
- AuthState,
3
- InstantSchemaDef,
4
- InstaQLResponse,
5
- PageInfoResponse,
6
- RuleParams,
7
- ValidQuery,
8
- } from '@instantdb/core';
9
- import InstantReactWebDatabase from '../InstantReactWebDatabase.ts';
10
- import { useContext } from 'react';
11
- import { SuspsenseQueryContext } from './InstantSuspenseProvider.tsx';
12
-
13
- export class InstantNextDatabase<
14
- Schema extends InstantSchemaDef<any, any, any>,
15
- UseDates extends boolean,
16
- > extends InstantReactWebDatabase<Schema, UseDates> {
17
- public useSuspenseQuery = <Q extends ValidQuery<Q, Schema>>(
18
- q: Q,
19
- opts?: {
20
- ruleParams: RuleParams;
21
- },
22
- ): {
23
- data: InstaQLResponse<Schema, Q, NonNullable<UseDates>>;
24
- pageInfo?: PageInfoResponse<Q>;
25
- } => {
26
- const ctx = useContext(SuspsenseQueryContext);
27
- if (!ctx) {
28
- throw new Error(
29
- 'useSuspenseQuery must be used within a SuspenseQueryProvider',
30
- );
31
- }
32
- return ctx.useSuspenseQuery(q, opts) as any;
33
- };
34
-
35
- useAuth = (): AuthState => {
36
- const ctx = useContext(SuspsenseQueryContext);
37
- const realAuthResult = this._useAuth();
38
- if (!ctx) {
39
- return realAuthResult;
40
- }
41
-
42
- const { ssrUser } = ctx;
43
- if (ssrUser === undefined) {
44
- return realAuthResult;
45
- }
46
- if (realAuthResult.isLoading) {
47
- return {
48
- error: undefined,
49
- isLoading: false,
50
- user: ssrUser ?? undefined, // null -> undefined for the response
51
- };
52
- }
53
-
54
- return realAuthResult;
55
- };
56
- }
@@ -1,189 +0,0 @@
1
- 'use client';
2
- // InstantSuspenseProvider can only be used in a client context so this prevents errors from trying to use it in a server component.
3
-
4
- import {
5
- FrameworkClient,
6
- InstantConfig,
7
- InstantSchemaDef,
8
- InstaQLResponse,
9
- PageInfoResponse,
10
- RuleParams,
11
- User,
12
- ValidQuery,
13
- } from '@instantdb/core';
14
- import InstantReactWebDatabase from '../InstantReactWebDatabase.ts';
15
- import {
16
- createHydrationStreamProvider,
17
- isServer,
18
- } from './HydrationStreamProvider.tsx';
19
- import { createContext, useContext, useRef, useState } from 'react';
20
- import { InstantReactAbstractDatabase } from '@instantdb/react-common';
21
-
22
- type InstantSuspenseProviderProps<
23
- Schema extends InstantSchemaDef<any, any, any>,
24
- > = {
25
- nonce?: string;
26
- children: React.ReactNode;
27
- db?: InstantReactWebDatabase<Schema, any>;
28
- config?: Omit<InstantConfig<any, any>, 'schema'> & {
29
- schema: string;
30
- };
31
- user?: User | null;
32
- };
33
-
34
- const stream = createHydrationStreamProvider<any>();
35
-
36
- type SuspenseQueryContextValue = {
37
- useSuspenseQuery: (query: any, opts?: SuspenseQueryOpts) => any;
38
- ssrUser: User | null | undefined;
39
- };
40
-
41
- export const SuspsenseQueryContext =
42
- createContext<SuspenseQueryContextValue | null>(null);
43
-
44
- // Creates a typed useSuspense hook
45
- export const createUseSuspenseQuery = <
46
- Schema extends InstantSchemaDef<any, any, any>,
47
- UseDates extends boolean,
48
- >(
49
- _db: InstantReactWebDatabase<Schema, UseDates>,
50
- ): (<Q extends ValidQuery<Q, Schema>>(
51
- q: Q,
52
- opts?: {
53
- ruleParams: RuleParams;
54
- },
55
- ) => {
56
- data: InstaQLResponse<Schema, Q, NonNullable<UseDates>>;
57
- pageInfo?: PageInfoResponse<Q>;
58
- }) => {
59
- return <Q extends ValidQuery<Q, Schema>>(q: any, opts: any) => {
60
- const ctx = useContext(SuspsenseQueryContext);
61
- if (!ctx) {
62
- throw new Error(
63
- 'useSuspenseQuery must be used within a SuspenseQueryProvider',
64
- );
65
- }
66
- return ctx.useSuspenseQuery(q, opts) as any;
67
- };
68
- };
69
-
70
- type SuspenseQueryOpts = {
71
- ruleParams: RuleParams;
72
- };
73
-
74
- export const InstantSuspenseProvider = (
75
- props: InstantSuspenseProviderProps<any>,
76
- ) => {
77
- const clientRef = useRef<FrameworkClient | null>(null);
78
-
79
- if (!props.db) {
80
- throw new Error(
81
- 'Must provide either a db or config to InstantSuspenseProvider',
82
- );
83
- }
84
-
85
- const db = useRef<InstantReactAbstractDatabase<any, any>>(props.db);
86
-
87
- const [trackedKeys] = useState(() => new Set<string>());
88
-
89
- if (!clientRef.current) {
90
- if (props.user && !props.user.refresh_token) {
91
- throw new Error(
92
- 'User must have a refresh_token field. Recieved: ' +
93
- JSON.stringify(props.user, null, 2),
94
- );
95
- }
96
- clientRef.current = new FrameworkClient({
97
- token: props.user?.refresh_token,
98
- db: db.current.core,
99
- });
100
- }
101
-
102
- if (isServer) {
103
- clientRef.current.subscribe((result) => {
104
- const { queryHash } = result;
105
- trackedKeys.add(queryHash);
106
- });
107
- }
108
-
109
- const useSuspenseQuery = (query: any, opts: SuspenseQueryOpts) => {
110
- const nonSuspenseResult = db.current.useQuery(query, {
111
- ...opts,
112
- });
113
-
114
- if (nonSuspenseResult.data) {
115
- return {
116
- data: nonSuspenseResult.data,
117
- pageInfo: nonSuspenseResult.pageInfo,
118
- };
119
- }
120
-
121
- // should never happen (typeguard)
122
- if (!clientRef.current) {
123
- throw new Error('Client ref not set up');
124
- }
125
-
126
- let entry = clientRef.current.getExistingResultForQuery(query, {
127
- ruleParams: opts?.ruleParams,
128
- });
129
-
130
- if (!entry) {
131
- entry = clientRef.current!.query(query, opts);
132
- }
133
-
134
- if (entry.status === 'pending') {
135
- throw entry.promise;
136
- }
137
-
138
- if (entry.status === 'error') {
139
- throw entry.error;
140
- }
141
-
142
- if (entry.status === 'success' && entry.type === 'session') {
143
- return entry.data;
144
- }
145
-
146
- if (entry.status === 'success') {
147
- const data = entry.data;
148
- const result = clientRef.current.completeIsomorphic(
149
- query,
150
- data.triples,
151
- data.attrs,
152
- data.pageInfo,
153
- );
154
-
155
- return result;
156
- }
157
- };
158
-
159
- return (
160
- <SuspsenseQueryContext.Provider
161
- value={{ useSuspenseQuery, ssrUser: props.user }}
162
- >
163
- <stream.Provider
164
- nonce={props.nonce}
165
- onFlush={() => {
166
- const toSend: { queryKey: string; value: any }[] = [];
167
- for (const [key, value] of clientRef.current!.resultMap.entries()) {
168
- if (trackedKeys.has(key) && value.status === 'success') {
169
- toSend.push({
170
- queryKey: key,
171
- value: value.data,
172
- });
173
- }
174
- }
175
-
176
- trackedKeys.clear();
177
- return toSend;
178
- }}
179
- onEntries={(entries) => {
180
- entries.forEach((entry) => {
181
- clientRef.current!.addQueryResult(entry.queryKey, entry.value);
182
- });
183
- }}
184
- >
185
- {props.children}
186
- </stream.Provider>
187
- </SuspsenseQueryContext.Provider>
188
- );
189
- };
@@ -1,11 +0,0 @@
1
- import { User } from '@instantdb/core';
2
- import { cookies } from 'next/headers.js';
3
-
4
- export const getUserFromInstantCookie = async (
5
- appId: string,
6
- ): Promise<User | null> => {
7
- const cookieStore = await cookies();
8
- const userJSON = cookieStore.get('instant_user_' + appId);
9
- const user = userJSON ? JSON.parse(userJSON.value) : null;
10
- return user;
11
- };
@@ -1,24 +0,0 @@
1
- // --------------------------------------------------------------------------------
2
- //
3
- // copied from
4
- // https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/src/server/htmlescape.ts
5
- // License: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/license.md
6
- //
7
- // --------------------------------------------------------------------------------
8
-
9
- // This utility is based on https://github.com/zertosh/htmlescape
10
- // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
11
-
12
- const ESCAPE_LOOKUP: Record<string, string> = {
13
- '&': '\\u0026',
14
- '>': '\\u003e',
15
- '<': '\\u003c',
16
- '\u2028': '\\u2028',
17
- '\u2029': '\\u2029',
18
- };
19
-
20
- export const ESCAPE_REGEX = /[&><\u2028\u2029]/g;
21
-
22
- export function htmlEscapeJsonString(str: string): string {
23
- return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]!);
24
- }
@@ -1,47 +0,0 @@
1
- import {
2
- InstantConfig,
3
- InstantSchemaDef,
4
- InstantUnknownSchema,
5
- } from '@instantdb/core';
6
-
7
- import version from '../version.ts';
8
-
9
- import { InstantNextDatabase } from './InstantNextDatabase.tsx';
10
-
11
- export { getUserFromInstantCookie } from './getUserFromInstantCookie.ts';
12
-
13
- export { InstantNextDatabase } from './InstantNextDatabase.tsx';
14
- export { InstantSuspenseProvider } from './InstantSuspenseProvider.tsx';
15
-
16
- export { createInstantRouteHandler } from '@instantdb/core';
17
-
18
- /**
19
- *
20
- * The first step: init your application!
21
- *
22
- * Visit https://instantdb.com/dash to get your `appId` :)
23
- *
24
- * @example
25
- * import { init } from "@instantdb/react"
26
- *
27
- * const db = init({ appId: "my-app-id" })
28
- *
29
- * // You can also provide a schema for type safety and editor autocomplete!
30
- *
31
- * import { init } from "@instantdb/react"
32
- * import schema from ""../instant.schema.ts";
33
- *
34
- * const db = init({ appId: "my-app-id", schema })
35
- *
36
- * // To learn more: https://instantdb.com/docs/modeling-data
37
- */
38
- export function init<
39
- Schema extends InstantSchemaDef<any, any, any> = InstantUnknownSchema,
40
- UseDates extends boolean = false,
41
- >(
42
- config: InstantConfig<Schema, UseDates>,
43
- ): InstantNextDatabase<Schema, UseDates> {
44
- return new InstantNextDatabase<Schema, UseDates>(config, {
45
- '@instantdb/react': version,
46
- });
47
- }