houdini-react 2.0.0-next.35 → 2.0.0-next.38
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/package.json +8 -8
- package/postInstall.js +1 -1
- package/runtime/Link.tsx +75 -0
- package/runtime/hooks/recycleNodesInto.ts +7 -0
- package/runtime/hooks/useDocumentHandle.ts +2 -1
- package/runtime/hooks/useMutation.ts +2 -2
- package/runtime/hooks/useQuery.ts +1 -1
- package/runtime/hooks/useQueryHandle.ts +1 -1
- package/runtime/hooks/useSubscriptionHandle.ts +7 -2
- package/runtime/index.tsx +2 -1
- package/runtime/resolve-href.ts +14 -0
- package/runtime/routing/Router.tsx +6 -2
- package/runtime/tsconfig.json +39 -0
- package/vite/index.js +56 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "houdini-react",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.38",
|
|
4
4
|
"description": "The React plugin for houdini",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -81,13 +81,13 @@
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"optionalDependencies": {
|
|
84
|
-
"houdini-react-darwin-x64": "2.0.0-next.
|
|
85
|
-
"houdini-react-darwin-arm64": "2.0.0-next.
|
|
86
|
-
"houdini-react-linux-x64": "2.0.0-next.
|
|
87
|
-
"houdini-react-linux-arm64": "2.0.0-next.
|
|
88
|
-
"houdini-react-win32-x64": "2.0.0-next.
|
|
89
|
-
"houdini-react-win32-arm64": "2.0.0-next.
|
|
90
|
-
"houdini-react-wasm": "2.0.0-next.
|
|
84
|
+
"houdini-react-darwin-x64": "2.0.0-next.38",
|
|
85
|
+
"houdini-react-darwin-arm64": "2.0.0-next.38",
|
|
86
|
+
"houdini-react-linux-x64": "2.0.0-next.38",
|
|
87
|
+
"houdini-react-linux-arm64": "2.0.0-next.38",
|
|
88
|
+
"houdini-react-win32-x64": "2.0.0-next.38",
|
|
89
|
+
"houdini-react-win32-arm64": "2.0.0-next.38",
|
|
90
|
+
"houdini-react-wasm": "2.0.0-next.38"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"compile": "scripts build-go",
|
package/postInstall.js
CHANGED
|
@@ -5,7 +5,7 @@ const https = require('https')
|
|
|
5
5
|
const child_process = require('child_process')
|
|
6
6
|
|
|
7
7
|
// Adjust the version you want to install. You can also make this dynamic.
|
|
8
|
-
const BINARY_DISTRIBUTION_VERSION = '2.0.0-next.
|
|
8
|
+
const BINARY_DISTRIBUTION_VERSION = '2.0.0-next.38'
|
|
9
9
|
|
|
10
10
|
// Windows binaries end with .exe so we need to special case them.
|
|
11
11
|
const binaryName = process.platform === 'win32' ? 'houdini-react.exe' : 'houdini-react'
|
package/runtime/Link.tsx
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// this file is generated by houdini — do not edit
|
|
2
|
+
// @refresh reset
|
|
3
|
+
import type { AnchorHTMLAttributes, DetailedHTMLProps } from 'react'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
import type rawManifest from './manifest.js'
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
import type { RouteScalars } from './manifest.js'
|
|
10
|
+
|
|
11
|
+
import { resolveHref } from './resolve-href.js'
|
|
12
|
+
|
|
13
|
+
type _Pages = (typeof rawManifest)['pages']
|
|
14
|
+
type _TSType<T extends string> = T extends keyof RouteScalars
|
|
15
|
+
? RouteScalars[T]
|
|
16
|
+
: T extends 'Int' | 'Float'
|
|
17
|
+
? number
|
|
18
|
+
: T extends 'ID'
|
|
19
|
+
? string | number
|
|
20
|
+
: T extends 'Boolean'
|
|
21
|
+
? boolean
|
|
22
|
+
: string
|
|
23
|
+
type _Param = { readonly name: string; readonly type: string; readonly optional: boolean }
|
|
24
|
+
type _ParamObj<Ps extends readonly _Param[]> = {
|
|
25
|
+
[P in Ps[number] as P['optional'] extends true ? P['name'] : never]?: _TSType<P['type']>
|
|
26
|
+
} & {
|
|
27
|
+
[P in Ps[number] as P['optional'] extends true ? never : P['name']]: _TSType<P['type']>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type _ExternalHref =
|
|
31
|
+
| `http://${string}`
|
|
32
|
+
| `https://${string}`
|
|
33
|
+
| `mailto:${string}`
|
|
34
|
+
| `tel:${string}`
|
|
35
|
+
| `blob:${string}`
|
|
36
|
+
| `data:${string}`
|
|
37
|
+
| `//${string}`
|
|
38
|
+
| `#${string}`
|
|
39
|
+
| `./${string}`
|
|
40
|
+
| `../${string}`
|
|
41
|
+
|
|
42
|
+
// All known app route URL strings — useful as a constraint for custom link wrappers.
|
|
43
|
+
export type RouteHrefs = _Pages[keyof _Pages] extends { readonly url: infer U extends string }
|
|
44
|
+
? U
|
|
45
|
+
: never
|
|
46
|
+
|
|
47
|
+
// Separate 'to' from 'params' so TypeScript evaluates them independently:
|
|
48
|
+
// - 'to' completions show all routes (including parameterized) because 'to' itself is always valid
|
|
49
|
+
// - 'params' is a separate intersection that errors when required but absent
|
|
50
|
+
type _PageForRoute<H extends string> = Extract<_Pages[keyof _Pages], { readonly url: H }>
|
|
51
|
+
type _ParamsForRoute<H extends string> = [_PageForRoute<H>] extends [never]
|
|
52
|
+
? { params?: never }
|
|
53
|
+
: _PageForRoute<H> extends { readonly params: readonly [] }
|
|
54
|
+
? { params?: never }
|
|
55
|
+
: _PageForRoute<H> extends { readonly params: infer Ps extends readonly _Param[] }
|
|
56
|
+
? { params: _ParamObj<Ps> }
|
|
57
|
+
: { params?: never }
|
|
58
|
+
|
|
59
|
+
export type LinkProps<H extends RouteHrefs | _ExternalHref = RouteHrefs | _ExternalHref> = Omit<
|
|
60
|
+
DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>,
|
|
61
|
+
'href'
|
|
62
|
+
> & { to: H; preload?: boolean | 'data' | 'component' | 'page' } & _ParamsForRoute<H>
|
|
63
|
+
|
|
64
|
+
export function Link<H extends RouteHrefs | _ExternalHref>({
|
|
65
|
+
to,
|
|
66
|
+
params,
|
|
67
|
+
preload,
|
|
68
|
+
...rest
|
|
69
|
+
}: LinkProps<H>): React.ReactElement {
|
|
70
|
+
const href =
|
|
71
|
+
params != null
|
|
72
|
+
? resolveHref(to as string, params as Record<string, string | number | boolean>)
|
|
73
|
+
: (to as string)
|
|
74
|
+
return React.createElement('a', { ...rest, href, 'data-houdini-preload': preload })
|
|
75
|
+
}
|
|
@@ -33,6 +33,13 @@ export function recycleNodesInto<T>(prev: T | null | undefined, next: T): T {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
if (!changed && prevLen === nextLen) return prev as T
|
|
36
|
+
|
|
37
|
+
// Copy non-index own properties from next (e.g. __id from @includeListID)
|
|
38
|
+
for (const key of Object.keys(next as any)) {
|
|
39
|
+
if (isNaN(Number(key))) {
|
|
40
|
+
;(result as any)[key] = (next as any)[key]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
36
43
|
return result as unknown as T
|
|
37
44
|
}
|
|
38
45
|
|
|
@@ -4,6 +4,7 @@ import { ArtifactKind } from 'houdini/runtime'
|
|
|
4
4
|
import type {
|
|
5
5
|
GraphQLObject,
|
|
6
6
|
GraphQLVariables,
|
|
7
|
+
GraphQLError,
|
|
7
8
|
CursorHandlers,
|
|
8
9
|
OffsetHandlers,
|
|
9
10
|
PageInfo,
|
|
@@ -205,7 +206,7 @@ export type DocumentHandle<
|
|
|
205
206
|
data: _Data
|
|
206
207
|
partial: boolean
|
|
207
208
|
fetching: boolean
|
|
208
|
-
errors:
|
|
209
|
+
errors: GraphQLError[] | null
|
|
209
210
|
fetch: FetchFn<_Data, Partial<_Input>>
|
|
210
211
|
variables: _Input
|
|
211
212
|
} & RefetchHandlers<_Artifact, _Data, _Input>
|
|
@@ -25,7 +25,7 @@ export function useMutation<
|
|
|
25
25
|
artifact,
|
|
26
26
|
}: {
|
|
27
27
|
artifact: MutationArtifact
|
|
28
|
-
}): [
|
|
28
|
+
}): [MutationHandler<_Result, _Input, _Optimistic>, boolean] {
|
|
29
29
|
// build the live document we'll use to send values
|
|
30
30
|
const [storeValue, observer] = useDocumentStore<_Result, _Input>({ artifact })
|
|
31
31
|
|
|
@@ -62,7 +62,7 @@ export function useMutation<
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
return [
|
|
65
|
+
return [mutate, pending]
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export class RuntimeGraphQLError extends Error {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphQLObject, QueryArtifact } from 'houdini/runtime'
|
|
1
|
+
import type { GraphQLObject, GraphQLVariables, QueryArtifact } from 'houdini/runtime'
|
|
2
2
|
|
|
3
3
|
import type { UseQueryConfig } from './useQueryHandle.js'
|
|
4
4
|
import { useQueryHandle } from './useQueryHandle.js'
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
SubscriptionArtifact,
|
|
3
|
+
GraphQLObject,
|
|
4
|
+
GraphQLVariables,
|
|
5
|
+
GraphQLError,
|
|
6
|
+
} from 'houdini/runtime'
|
|
2
7
|
|
|
3
8
|
import { useDocumentSubscription } from './useDocumentSubscription.js'
|
|
4
9
|
|
|
5
10
|
export type SubscriptionHandle<_Result extends GraphQLObject, _Input extends GraphQLVariables> = {
|
|
6
11
|
data: _Result | null
|
|
7
|
-
errors:
|
|
12
|
+
errors: GraphQLError[] | null
|
|
8
13
|
variables: _Input
|
|
9
14
|
listen: (args: { variables?: _Input }) => void
|
|
10
15
|
unlisten: () => void
|
package/runtime/index.tsx
CHANGED
|
@@ -6,7 +6,8 @@ import manifest from './manifest.js'
|
|
|
6
6
|
import { Router as RouterImpl, type RouterCache, RouterContextProvider } from './routing/index.js'
|
|
7
7
|
|
|
8
8
|
export * from './hooks/index.js'
|
|
9
|
-
export { router_cache, useSession, useLocation, useRoute } from './routing/index.js'
|
|
9
|
+
export { router_cache, useCache, useSession, useLocation, useRoute } from './routing/index.js'
|
|
10
|
+
export * from './Link.js'
|
|
10
11
|
|
|
11
12
|
export function Router({
|
|
12
13
|
cache,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function resolveHref(
|
|
2
|
+
href: string,
|
|
3
|
+
params: Record<string, string | number | boolean>
|
|
4
|
+
): string {
|
|
5
|
+
// optional [[param]] — strip the whole /[[param]] segment when the value is absent
|
|
6
|
+
href = href.replace(/\/\[\[([^\]]+)\]\]/g, (_, key: string) => {
|
|
7
|
+
const val = params[key]
|
|
8
|
+
return val !== undefined ? '/' + String(val) : ''
|
|
9
|
+
})
|
|
10
|
+
// rest [...slug] — substitute [..slug] with the value (or empty string when absent)
|
|
11
|
+
href = href.replace(/\[\.\.\.([^\]]+)\]/g, (_, key: string) => String(params[key] ?? ''))
|
|
12
|
+
// regular [param]
|
|
13
|
+
return href.replace(/\[([^\]]+)\]/g, (_, key: string) => String(params[key] ?? key))
|
|
14
|
+
}
|
|
@@ -760,8 +760,12 @@ function usePreload({ preload }: { preload: (url: string, which: PreloadWhichVal
|
|
|
760
760
|
return
|
|
761
761
|
}
|
|
762
762
|
|
|
763
|
-
// if the anchor doesn't
|
|
764
|
-
const
|
|
763
|
+
// if the anchor doesn't explicitly opt in to preloading, don't do anything
|
|
764
|
+
const preloadAttr = anchor.attributes.getNamedItem('data-houdini-preload')
|
|
765
|
+
if (!preloadAttr) {
|
|
766
|
+
return
|
|
767
|
+
}
|
|
768
|
+
const preloadWhichRaw = preloadAttr.value
|
|
765
769
|
const preloadWhich: PreloadWhichValue =
|
|
766
770
|
!preloadWhichRaw || preloadWhichRaw === 'true'
|
|
767
771
|
? 'page'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": ".",
|
|
4
|
+
"paths": {
|
|
5
|
+
"$houdini": ["."],
|
|
6
|
+
"$houdini/*": ["./*"],
|
|
7
|
+
"~": ["../src"],
|
|
8
|
+
"~/*": ["../src/*"]
|
|
9
|
+
},
|
|
10
|
+
"rootDirs": ["..", "./types"],
|
|
11
|
+
"target": "ESNext",
|
|
12
|
+
"useDefineForClassFields": true,
|
|
13
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
14
|
+
"allowJs": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"esModuleInterop": false,
|
|
17
|
+
"allowSyntheticDefaultImports": true,
|
|
18
|
+
"strict": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true,
|
|
20
|
+
"module": "ESNext",
|
|
21
|
+
"moduleResolution": "Bundler",
|
|
22
|
+
"allowImportingTsExtensions": true,
|
|
23
|
+
"resolveJsonModule": true,
|
|
24
|
+
"isolatedModules": true,
|
|
25
|
+
"noEmit": true,
|
|
26
|
+
"jsx": "react-jsx"
|
|
27
|
+
},
|
|
28
|
+
"include": [
|
|
29
|
+
"ambient.d.ts",
|
|
30
|
+
"./types/**/$types.d.ts",
|
|
31
|
+
"../vite.config.ts",
|
|
32
|
+
"../src/**/*.js",
|
|
33
|
+
"../src/**/*.ts",
|
|
34
|
+
"../src/**/*.jsx",
|
|
35
|
+
"../src/**/*.tsx",
|
|
36
|
+
"../src/+app.d.ts"
|
|
37
|
+
],
|
|
38
|
+
"exclude": ["../node_modules/**", "./[!ambient.d.ts]**"]
|
|
39
|
+
}
|
package/vite/index.js
CHANGED
|
@@ -6,10 +6,50 @@ import {
|
|
|
6
6
|
client_build_directory
|
|
7
7
|
} from "houdini/router/conventions";
|
|
8
8
|
import { load_manifest } from "houdini/router/manifest";
|
|
9
|
-
import { existsSync } from "node:fs";
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { build } from "vite";
|
|
12
12
|
import { transform_file } from "./transform.js";
|
|
13
|
+
const REACT_TSCONFIG_STUB = `{
|
|
14
|
+
"compilerOptions": {
|
|
15
|
+
"baseUrl": ".",
|
|
16
|
+
"paths": {
|
|
17
|
+
"$houdini": ["."],
|
|
18
|
+
"$houdini/*": ["./*"],
|
|
19
|
+
"~": ["../src"],
|
|
20
|
+
"~/*": ["../src/*"]
|
|
21
|
+
},
|
|
22
|
+
"rootDirs": ["..", "./types"],
|
|
23
|
+
"target": "ESNext",
|
|
24
|
+
"useDefineForClassFields": true,
|
|
25
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
26
|
+
"allowJs": true,
|
|
27
|
+
"skipLibCheck": true,
|
|
28
|
+
"esModuleInterop": false,
|
|
29
|
+
"allowSyntheticDefaultImports": true,
|
|
30
|
+
"strict": true,
|
|
31
|
+
"forceConsistentCasingInFileNames": true,
|
|
32
|
+
"module": "ESNext",
|
|
33
|
+
"moduleResolution": "Bundler",
|
|
34
|
+
"allowImportingTsExtensions": true,
|
|
35
|
+
"resolveJsonModule": true,
|
|
36
|
+
"isolatedModules": true,
|
|
37
|
+
"noEmit": true,
|
|
38
|
+
"jsx": "react-jsx"
|
|
39
|
+
},
|
|
40
|
+
"include": [
|
|
41
|
+
"ambient.d.ts",
|
|
42
|
+
"./types/**/$types.d.ts",
|
|
43
|
+
"../vite.config.ts",
|
|
44
|
+
"../src/**/*.js",
|
|
45
|
+
"../src/**/*.ts",
|
|
46
|
+
"../src/**/*.jsx",
|
|
47
|
+
"../src/**/*.tsx",
|
|
48
|
+
"../src/+app.d.ts"
|
|
49
|
+
],
|
|
50
|
+
"exclude": ["../node_modules/**", "./[!ambient.d.ts]**"]
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
13
53
|
const _require = createRequire(import.meta.url);
|
|
14
54
|
let reactStreamingServerPath = "";
|
|
15
55
|
try {
|
|
@@ -31,6 +71,18 @@ function index_default(ctx) {
|
|
|
31
71
|
},
|
|
32
72
|
async config(userConfig, env) {
|
|
33
73
|
viteEnv = env;
|
|
74
|
+
const runtimeDir = path.join(
|
|
75
|
+
ctx.config.root_dir,
|
|
76
|
+
ctx.config.config_file.runtimeDir ?? ".houdini"
|
|
77
|
+
);
|
|
78
|
+
try {
|
|
79
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
80
|
+
const tsconfigPath = path.join(runtimeDir, "tsconfig.json");
|
|
81
|
+
if (!existsSync(tsconfigPath)) {
|
|
82
|
+
writeFileSync(tsconfigPath, REACT_TSCONFIG_STUB);
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
34
86
|
if (userConfig.build?.ssr) {
|
|
35
87
|
return reactStreamingServerPath ? { resolve: { alias: { "react-streaming/server": reactStreamingServerPath } } } : {};
|
|
36
88
|
}
|
|
@@ -86,10 +138,10 @@ function index_default(ctx) {
|
|
|
86
138
|
} : conf;
|
|
87
139
|
},
|
|
88
140
|
resolveId(id) {
|
|
89
|
-
if (
|
|
90
|
-
return;
|
|
141
|
+
if (id.includes("virtual:houdini")) {
|
|
142
|
+
return id.substring(id.indexOf("virtual:houdini"));
|
|
91
143
|
}
|
|
92
|
-
return
|
|
144
|
+
return null;
|
|
93
145
|
},
|
|
94
146
|
hotUpdate() {
|
|
95
147
|
cfCache = null;
|