houdini-react 2.0.0-next.35 → 2.0.0-next.37

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "houdini-react",
3
- "version": "2.0.0-next.35",
3
+ "version": "2.0.0-next.37",
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.35",
85
- "houdini-react-darwin-arm64": "2.0.0-next.35",
86
- "houdini-react-linux-x64": "2.0.0-next.35",
87
- "houdini-react-linux-arm64": "2.0.0-next.35",
88
- "houdini-react-win32-x64": "2.0.0-next.35",
89
- "houdini-react-win32-arm64": "2.0.0-next.35",
90
- "houdini-react-wasm": "2.0.0-next.35"
84
+ "houdini-react-darwin-x64": "2.0.0-next.37",
85
+ "houdini-react-darwin-arm64": "2.0.0-next.37",
86
+ "houdini-react-linux-x64": "2.0.0-next.37",
87
+ "houdini-react-linux-arm64": "2.0.0-next.37",
88
+ "houdini-react-win32-x64": "2.0.0-next.37",
89
+ "houdini-react-win32-arm64": "2.0.0-next.37",
90
+ "houdini-react-wasm": "2.0.0-next.37"
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.35'
8
+ const BINARY_DISTRIBUTION_VERSION = '2.0.0-next.37'
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'
@@ -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: { message: string }[] | null
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
- }): [boolean, MutationHandler<_Result, _Input, _Optimistic>] {
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 [pending, mutate]
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 { SubscriptionArtifact, GraphQLObject, GraphQLVariables } from 'houdini/runtime'
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: { message: string }[] | null
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
+ }
@@ -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 (!id.includes("virtual:houdini")) {
90
- return;
141
+ if (id.includes("virtual:houdini")) {
142
+ return id.substring(id.indexOf("virtual:houdini"));
91
143
  }
92
- return id.substring(id.indexOf("virtual:houdini"));
144
+ return null;
93
145
  },
94
146
  hotUpdate() {
95
147
  cfCache = null;