houdini 2.0.0-next.1 → 2.0.0-next.10

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 (54) hide show
  1. package/build/adapter/index.d.ts +1 -1
  2. package/build/cmd-cjs/index.js +10068 -10551
  3. package/build/cmd-esm/index.js +10065 -10548
  4. package/build/codegen/generators/typescript/addReferencedInputTypes.d.ts +1 -1
  5. package/build/codegen/generators/typescript/inlineType.d.ts +2 -1
  6. package/build/codegen-cjs/index.js +9887 -10448
  7. package/build/codegen-esm/index.js +9884 -10445
  8. package/build/lib/fs.d.ts +2 -2
  9. package/build/lib/types.d.ts +3 -3
  10. package/build/lib/typescript.d.ts +3 -3
  11. package/build/lib-cjs/index.js +9394 -10158
  12. package/build/lib-esm/index.js +9394 -10158
  13. package/build/runtime/lib/types.d.ts +2 -2
  14. package/build/runtime/public/cache.d.ts +0 -1
  15. package/build/runtime/router/cookies.d.ts +9 -9
  16. package/build/runtime/router/server.d.ts +6 -6
  17. package/build/runtime/router/session.d.ts +1 -0
  18. package/build/runtime/server/index.d.ts +17 -0
  19. package/build/runtime-cjs/cache/cache.js +36 -29
  20. package/build/runtime-cjs/client/documentStore.js +2 -2
  21. package/build/runtime-cjs/client/index.js +1 -1
  22. package/build/runtime-cjs/client/plugins/test.js +2 -2
  23. package/build/runtime-cjs/lib/types.d.ts +2 -2
  24. package/build/runtime-cjs/public/cache.d.ts +0 -1
  25. package/build/runtime-cjs/public/cache.js +0 -14
  26. package/build/runtime-cjs/router/cookies.d.ts +9 -9
  27. package/build/runtime-cjs/router/cookies.js +1 -1
  28. package/build/runtime-cjs/router/server.d.ts +6 -6
  29. package/build/runtime-cjs/router/server.js +32 -17
  30. package/build/runtime-cjs/router/session.d.ts +1 -0
  31. package/build/runtime-cjs/router/session.js +7 -2
  32. package/build/runtime-cjs/server/index.d.ts +17 -0
  33. package/build/runtime-cjs/server/index.js +62 -0
  34. package/build/runtime-esm/cache/cache.js +36 -29
  35. package/build/runtime-esm/client/documentStore.js +2 -2
  36. package/build/runtime-esm/client/index.js +1 -1
  37. package/build/runtime-esm/client/plugins/test.js +2 -2
  38. package/build/runtime-esm/lib/types.d.ts +2 -2
  39. package/build/runtime-esm/public/cache.d.ts +0 -1
  40. package/build/runtime-esm/public/cache.js +0 -14
  41. package/build/runtime-esm/router/cookies.d.ts +9 -9
  42. package/build/runtime-esm/router/cookies.js +1 -1
  43. package/build/runtime-esm/router/server.d.ts +6 -6
  44. package/build/runtime-esm/router/server.js +36 -21
  45. package/build/runtime-esm/router/session.d.ts +1 -0
  46. package/build/runtime-esm/router/session.js +5 -1
  47. package/build/runtime-esm/server/index.d.ts +17 -0
  48. package/build/runtime-esm/server/index.js +38 -0
  49. package/build/test-cjs/index.js +9885 -10447
  50. package/build/test-esm/index.js +9882 -10444
  51. package/build/vite/hmr.d.ts +0 -2
  52. package/build/vite-cjs/index.js +9804 -10365
  53. package/build/vite-esm/index.js +9801 -10362
  54. package/package.json +4 -4
@@ -387,20 +387,21 @@ class CacheInternal {
387
387
  } else if (Array.isArray(value) && // make typescript happy
388
388
  (typeof previousValue === "undefined" || previousValue === null || Array.isArray(previousValue))) {
389
389
  let oldIDs = [...previousValue || []];
390
- const emptyEdges = !updates ? [] : oldIDs.map((id) => {
391
- if (!id) {
392
- return "";
393
- }
394
- const { value: cursorField } = this.storage.get(id, "cursor");
395
- if (cursorField) {
396
- return "";
397
- }
398
- const { value: node } = this.storage.get(id, "node");
399
- if (!node) {
400
- return "";
401
- }
402
- return node;
403
- });
390
+ if (updates?.includes("append") || updates?.includes("prepend")) {
391
+ oldIDs = oldIDs.filter((id) => {
392
+ for (const layer2 of this.storage.data) {
393
+ for (const operation of Object.values(layer2.operations)) {
394
+ if (operation.fields?.[key])
395
+ for (const listOperation of operation.fields[key]) {
396
+ if ("id" in listOperation && listOperation.id === id) {
397
+ return false;
398
+ }
399
+ }
400
+ }
401
+ }
402
+ return true;
403
+ });
404
+ }
404
405
  let linkedIDs = [];
405
406
  const { newIDs, nestedIDs } = this.extractNestedListIDs({
406
407
  value,
@@ -419,39 +420,45 @@ class CacheInternal {
419
420
  layer.writeLink(parent, key, linkedIDs);
420
421
  };
421
422
  if (applyUpdates && updates) {
422
- if (key === "edges") {
423
- const newNodeIDs = [];
424
- for (const id of newIDs) {
423
+ const filterIDs = (keep, insert) => {
424
+ const existingIDs = /* @__PURE__ */ new Set();
425
+ for (const id of keep) {
425
426
  if (!id) {
426
427
  continue;
427
428
  }
428
429
  const { value: node } = this.storage.get(id, "node");
429
- if (typeof node !== "string") {
430
+ if (!node) {
430
431
  continue;
431
432
  }
432
- if (!node || !this.storage.get(node, "__typename")) {
433
+ const nodeID = this.storage.get(node, "id");
434
+ if (!nodeID) {
433
435
  continue;
434
436
  }
435
- newNodeIDs.push(node);
437
+ existingIDs.add(nodeID.value);
436
438
  }
437
- oldIDs = oldIDs.filter((id) => {
439
+ return insert.filter((id) => {
438
440
  if (!id) {
439
441
  return true;
440
442
  }
441
- const { value: value2 } = this.storage.get(id, "node");
442
- const node = value2;
443
- if (newNodeIDs.includes(node) && emptyEdges.includes(node)) {
444
- return false;
443
+ const { value: node } = this.storage.get(id, "node");
444
+ if (!node) {
445
+ return true;
446
+ }
447
+ const nodeID = this.storage.get(node, "id");
448
+ if (!nodeID) {
449
+ return true;
445
450
  }
446
- return true;
451
+ return !existingIDs.has(nodeID.value);
447
452
  });
448
- }
453
+ };
449
454
  for (const update of applyUpdates) {
450
455
  if (update !== "replace" && !updates.includes(update)) {
451
456
  continue;
452
457
  }
453
458
  if (update === "prepend") {
454
- linkedIDs = newIDs.concat(oldIDs);
459
+ linkedIDs = newIDs.concat(
460
+ filterIDs(newIDs, oldIDs)
461
+ );
455
462
  if (layer?.optimistic) {
456
463
  action = () => {
457
464
  for (const id of newIDs) {
@@ -462,7 +469,7 @@ class CacheInternal {
462
469
  };
463
470
  }
464
471
  } else if (update === "append") {
465
- linkedIDs = oldIDs.concat(newIDs);
472
+ linkedIDs = filterIDs(newIDs, oldIDs).concat(newIDs);
466
473
  if (layer?.optimistic) {
467
474
  action = () => {
468
475
  for (const id of newIDs) {
@@ -265,9 +265,9 @@ class DocumentStore extends Writable {
265
265
  handlers = {
266
266
  ...common,
267
267
  value,
268
- resolve: (ctx2, data) => {
268
+ resolve: ((ctx2, data) => {
269
269
  return common.resolve(ctx2, data ?? value);
270
- }
270
+ })
271
271
  };
272
272
  } else if (direction === "error") {
273
273
  handlers = {
@@ -45,7 +45,7 @@ class HoudiniClient {
45
45
  }
46
46
  this.throwOnError_operations = throwOnError?.operations ?? [];
47
47
  let serverPort = globalThis.process?.env?.HOUDINI_PORT ?? "5173";
48
- this.url = url ?? (globalThis.window ? "" : `https://localhost:${serverPort}`) + localApiEndpoint(getCurrentConfig());
48
+ this.url = url ?? (globalThis.window ? "" : `http://localhost:${serverPort}`) + localApiEndpoint(getCurrentConfig());
49
49
  this.throwOnError = throwOnError;
50
50
  this.fetchParams = fetchParams;
51
51
  this.pipeline = pipeline;
@@ -76,7 +76,7 @@ function fakeFetch({
76
76
  partial: false,
77
77
  stale: false
78
78
  };
79
- return () => ({
79
+ return (() => ({
80
80
  network(ctx, { resolve }) {
81
81
  spy?.(ctx);
82
82
  if (onRequest) {
@@ -85,7 +85,7 @@ function fakeFetch({
85
85
  resolve(ctx, { ...result });
86
86
  }
87
87
  }
88
- });
88
+ }));
89
89
  }
90
90
  export {
91
91
  createStore,
@@ -372,8 +372,8 @@ export type ProjectManifest = {
372
372
  artifacts: string[];
373
373
  /** Whether or not there is a local schema defined */
374
374
  local_schema: boolean;
375
- /** Whether or not there is a custom instance of yoga defined */
376
- local_yoga: boolean;
375
+ /** Whether or not there is a custom server defined */
376
+ local_server: boolean;
377
377
  /** Information about componentFields defined in the project */
378
378
  component_fields: Record<string, {
379
379
  filepath: string;
@@ -6,7 +6,6 @@ import type { ArgType, CacheTypeDef, IDFields, QueryInput, QueryList, QueryValue
6
6
  export declare class Cache<Def extends CacheTypeDef> {
7
7
  _internal_unstable: _Cache;
8
8
  constructor(cache: _Cache);
9
- validateInstabilityWarning(): void;
10
9
  get<T extends TypeNames<Def>>(type: T, data: IDFields<Def, T>): Record<Def, T>;
11
10
  get config(): import("../lib").ConfigFile;
12
11
  list<Name extends ValidLists<Def>>(name: Name, { parentID, allLists }?: {
@@ -6,19 +6,8 @@ class Cache {
6
6
  constructor(cache) {
7
7
  this._internal_unstable = cache;
8
8
  }
9
- // if the user is using the imperative API, we want the ability to break the API
10
- // with any minor version. In order to do this, we require them to accept this contract
11
- // through their config file
12
- validateInstabilityWarning() {
13
- if (!this.config.acceptImperativeInstability && !this.config.features?.imperativeCache) {
14
- console.warn(`\u26A0\uFE0F The imperative cache API is considered unstable and will change in any minor version release
15
- Please acknowledge this by enabling the imperative cache feature flage in your config file.
16
- For more information: https://houdinigraphql.com/api/cache`);
17
- }
18
- }
19
9
  // return the record proxy for the given type/id combo
20
10
  get(type, data) {
21
- this.validateInstabilityWarning();
22
11
  let recordID = this._internal_unstable._internal_unstable.id(type, data);
23
12
  if (!recordID) {
24
13
  throw new Error("todo");
@@ -34,7 +23,6 @@ For more information: https://houdinigraphql.com/api/cache`);
34
23
  return getCurrentConfig();
35
24
  }
36
25
  list(name, { parentID, allLists } = {}) {
37
- this.validateInstabilityWarning();
38
26
  return new ListCollection({
39
27
  cache: this,
40
28
  name,
@@ -46,7 +34,6 @@ For more information: https://houdinigraphql.com/api/cache`);
46
34
  query,
47
35
  variables
48
36
  }) {
49
- this.validateInstabilityWarning();
50
37
  return this._internal_unstable.read({
51
38
  selection: query.artifact.selection,
52
39
  variables
@@ -57,7 +44,6 @@ For more information: https://houdinigraphql.com/api/cache`);
57
44
  variables,
58
45
  data
59
46
  }) {
60
- this.validateInstabilityWarning();
61
47
  this._internal_unstable.write({
62
48
  selection: query.artifact.selection,
63
49
  // @ts-expect-error
@@ -29,13 +29,13 @@ export declare function parse(str: string, options?: {
29
29
  *
30
30
  */
31
31
  export declare function serialize(name: string, val: string, options: {
32
- encode: boolean;
33
- maxAge: number;
34
- domain: string;
35
- path: string;
36
- expires: Date;
37
- httpOnly: boolean;
38
- priority: string | number;
39
- secure: boolean;
40
- sameSite: string | boolean;
32
+ encode?: boolean;
33
+ maxAge?: number;
34
+ domain?: string;
35
+ path?: string;
36
+ expires?: Date;
37
+ httpOnly?: boolean;
38
+ priority?: string | number;
39
+ secure?: boolean;
40
+ sameSite?: string | boolean;
41
41
  }): string;
@@ -52,7 +52,7 @@ function serialize(name, val, options) {
52
52
  throw new TypeError("argument val is invalid");
53
53
  }
54
54
  let str = name + "=" + value;
55
- if (opt.maxAge !== null) {
55
+ if (opt.maxAge) {
56
56
  let maxAge = opt.maxAge - 0;
57
57
  if (Number.isNaN(maxAge) || !isFinite(maxAge)) {
58
58
  throw new TypeError("option maxAge is invalid");
@@ -1,11 +1,11 @@
1
- import { createServerAdapter as createAdapter } from '@whatwg-node/server';
2
- import { type GraphQLSchema } from 'graphql';
3
- import { createYoga } from 'graphql-yoga';
1
+ import { createServerAdapter } from '@whatwg-node/server';
2
+ import type { GraphQLSchema } from 'graphql';
4
3
  import type { HoudiniClient } from '../client';
4
+ import { Server } from '../server';
5
5
  import type { RouterManifest, RouterPageManifest, YogaServerOptions } from './types';
6
- export declare function _serverHandler<ComponentType = unknown>({ schema, yoga, client, production, manifest, graphqlEndpoint, on_render, componentCache, }: {
6
+ export declare function _serverHandler<ComponentType = unknown>({ schema, server, client, production, manifest, graphqlEndpoint, on_render, componentCache, }: {
7
7
  schema?: GraphQLSchema | null;
8
- yoga?: ReturnType<typeof createYoga> | null;
8
+ server?: Server<any, any>;
9
9
  client: HoudiniClient;
10
10
  production: boolean;
11
11
  manifest: RouterManifest<ComponentType> | null;
@@ -20,5 +20,5 @@ export declare function _serverHandler<ComponentType = unknown>({ schema, yoga,
20
20
  componentCache: Record<string, any>;
21
21
  }) => Response | Promise<Response | undefined> | undefined;
22
22
  } & Omit<YogaServerOptions, 'schema'>): (request: Request) => Promise<Response>;
23
- export declare const serverAdapterFactory: (args: Parameters<typeof _serverHandler>[0]) => ReturnType<typeof createAdapter>;
23
+ export declare const serverAdapterFactory: (args: Parameters<typeof _serverHandler>[0]) => ReturnType<typeof createServerAdapter>;
24
24
  export type ServerAdapterFactory = typeof serverAdapterFactory;
@@ -1,14 +1,14 @@
1
- import { createServerAdapter as createAdapter } from "@whatwg-node/server";
2
- import { parse, execute } from "graphql";
3
- import { createYoga } from "graphql-yoga";
4
- import { localApiSessionKeys, localApiEndpoint, getCurrentConfig } from "../lib/config";
1
+ import { createServerAdapter } from "@whatwg-node/server";
2
+ import { localApiSessionKeys, getCurrentConfig } from "../lib/config";
3
+ import { Server } from "../server";
4
+ import { serialize as encodeCookie } from "./cookies";
5
5
  import { find_match } from "./match";
6
- import { get_session, handle_request } from "./session";
6
+ import { get_session, handle_request, session_cookie_name } from "./session";
7
7
  const config_file = getCurrentConfig();
8
8
  const session_keys = localApiSessionKeys(config_file);
9
9
  function _serverHandler({
10
10
  schema,
11
- yoga,
11
+ server,
12
12
  client,
13
13
  production,
14
14
  manifest,
@@ -16,23 +16,38 @@ function _serverHandler({
16
16
  on_render,
17
17
  componentCache
18
18
  }) {
19
- if (schema && !yoga) {
20
- yoga = createYoga({
19
+ if (schema && !server) {
20
+ server = new Server({
21
+ landingPage: !production
22
+ });
23
+ }
24
+ let requestHandler = null;
25
+ if (server && schema) {
26
+ requestHandler = server.init({
21
27
  schema,
22
- landingPage: !production,
23
- graphqlEndpoint
28
+ endpoint: graphqlEndpoint,
29
+ getSession: (request) => get_session(request.headers, session_keys)
24
30
  });
25
31
  }
26
32
  client.componentCache = componentCache;
27
- if (schema) {
33
+ if (requestHandler) {
28
34
  client.registerProxy(graphqlEndpoint, async ({ query, variables, session }) => {
29
- const parsed = parse(query);
30
- return await execute({
31
- schema,
32
- document: parsed,
33
- contextValue: session,
34
- variableValues: variables
35
- });
35
+ const response = await requestHandler(
36
+ new Request(`http://localhost/${graphqlEndpoint}`, {
37
+ method: "POST",
38
+ headers: {
39
+ "Content-Type": "application/json",
40
+ Cookie: encodeCookie(session_cookie_name, JSON.stringify(session ?? {}), {
41
+ httpOnly: true
42
+ })
43
+ },
44
+ body: JSON.stringify({
45
+ query,
46
+ variables
47
+ })
48
+ })
49
+ );
50
+ return await response.json();
36
51
  });
37
52
  }
38
53
  return async (request) => {
@@ -43,8 +58,8 @@ function _serverHandler({
43
58
  );
44
59
  }
45
60
  const url = new URL(request.url).pathname;
46
- if (yoga && url === localApiEndpoint(config_file)) {
47
- return yoga(request);
61
+ if (requestHandler && url === graphqlEndpoint) {
62
+ return requestHandler(request);
48
63
  }
49
64
  const authResponse = await handle_request({
50
65
  request,
@@ -69,7 +84,7 @@ function _serverHandler({
69
84
  };
70
85
  }
71
86
  const serverAdapterFactory = (args) => {
72
- return createAdapter(_serverHandler(args));
87
+ return createServerAdapter(_serverHandler(args));
73
88
  };
74
89
  export {
75
90
  _serverHandler,
@@ -17,5 +17,6 @@ export type ServerResponse = {
17
17
  redirect(url: string, status?: number): void;
18
18
  set_header(name: string, value: string): void;
19
19
  };
20
+ export declare const session_cookie_name = "__houdini__";
20
21
  export declare function get_session(req: Headers, secrets: string[]): Promise<App.Session>;
21
22
  export {};
@@ -52,6 +52,9 @@ async function get_session(req, secrets) {
52
52
  if (!cookie) {
53
53
  return {};
54
54
  }
55
+ if (cookie === "{}") {
56
+ return {};
57
+ }
55
58
  for (const secret of secrets) {
56
59
  if (!await verify(cookie, secret)) {
57
60
  continue;
@@ -66,5 +69,6 @@ async function get_session(req, secrets) {
66
69
  }
67
70
  export {
68
71
  get_session,
69
- handle_request
72
+ handle_request,
73
+ session_cookie_name
70
74
  };
@@ -0,0 +1,17 @@
1
+ import type { ServerAdapterRequestHandler } from '@whatwg-node/server';
2
+ import { YogaServer } from 'graphql-yoga';
3
+ import type { YogaSchemaDefinition } from 'graphql-yoga/typings/plugins/use-schema';
4
+ type YogaParams = Required<ConstructorParameters<typeof YogaServer>>[0];
5
+ type ConstructorParams = Omit<YogaParams, 'schema' | 'graphqlEndpoint'>;
6
+ export declare class Server<ServerContext extends Record<string, any>, UserContext extends Record<string, any>> {
7
+ opts: ConstructorParams | null;
8
+ _yoga: YogaServer<any, any> | null;
9
+ constructor(opts?: ConstructorParams);
10
+ init({ endpoint, schema, getSession, }: {
11
+ schema: YogaSchemaDefinition<any, any>;
12
+ endpoint: string;
13
+ getSession: (request: Request) => Promise<UserContext>;
14
+ }): import("@whatwg-node/server").ServerAdapter<ServerContext, Server<ServerContext, UserContext>>;
15
+ handle: ServerAdapterRequestHandler<ServerContext>;
16
+ }
17
+ export {};
@@ -0,0 +1,38 @@
1
+ import { createServerAdapter } from "@whatwg-node/server";
2
+ import { YogaServer } from "graphql-yoga";
3
+ class Server {
4
+ opts;
5
+ _yoga = null;
6
+ constructor(opts) {
7
+ this.opts = opts ?? null;
8
+ }
9
+ init({
10
+ endpoint,
11
+ schema,
12
+ getSession
13
+ }) {
14
+ this._yoga = new YogaServer({
15
+ ...this.opts,
16
+ schema,
17
+ graphqlEndpoint: endpoint,
18
+ context: async (ctx) => {
19
+ const userContext = !this.opts ? {} : typeof this.opts.context === "function" ? await this.opts.context(ctx) : this.opts.context || {};
20
+ const sessionContext = await getSession(ctx.request) || {};
21
+ return {
22
+ ...userContext,
23
+ session: sessionContext
24
+ };
25
+ }
26
+ });
27
+ return createServerAdapter(this, {
28
+ fetchAPI: this._yoga.fetchAPI,
29
+ plugins: this._yoga["plugins"]
30
+ });
31
+ }
32
+ handle = (request, serverContext) => {
33
+ return this._yoga.handle(request, serverContext);
34
+ };
35
+ }
36
+ export {
37
+ Server
38
+ };