@suss/packs 0.35.1 → 0.37.0

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.
@@ -4,11 +4,11 @@ import { z } from "zod";
4
4
  import { SCALAR_SHAPES } from "@suss/contract-graphql";
5
5
  var optionsSchema = z.object({
6
6
  /**
7
- * The directory the pack looks under for the class a `mutation:` or
8
- * `resolver:` field references, for example
9
- * `path.join(repoRoot, "app/graphql")`. A relative path resolves
10
- * against `configDirectory`, or the working directory when that is
11
- * unset.
7
+ * The directory the pack looks under for a class a `mutation:` or
8
+ * `resolver:` field references when no file in the run declares it,
9
+ * for example `path.join(repoRoot, "app/graphql")`. A relative path
10
+ * resolves against `configDirectory`, or the working directory when
11
+ * that is unset.
12
12
  */
13
13
  root: z.string(),
14
14
  /**
@@ -29,6 +29,7 @@ var optionsSchema = z.object({
29
29
  var GRAPHQL_RUBY_ROOT_CLASS_NAMES = [
30
30
  "GraphQL::Schema::Object",
31
31
  "GraphQL::Schema::Mutation",
32
+ "GraphQL::Schema::RelayClassicMutation",
32
33
  "GraphQL::Schema::Resolver",
33
34
  "GraphQL::Schema::Interface",
34
35
  "GraphQL::Schema::InputObject",
@@ -44,6 +45,56 @@ var DEFAULT_BASE_CLASS_NAMES = [
44
45
  "Types::BaseUnion",
45
46
  "Types::BaseScalar"
46
47
  ];
48
+ function orNull(shape) {
49
+ return { type: "union", variants: [shape, { type: "null" }] };
50
+ }
51
+ var PAGE_INFO_FIELDS = {
52
+ hasNextPage: { type: "boolean" },
53
+ hasPreviousPage: { type: "boolean" },
54
+ startCursor: orNull({ type: "text" }),
55
+ endCursor: orNull({ type: "text" })
56
+ };
57
+ var CONNECTION_TYPE = {
58
+ name: "{type}Connection",
59
+ types: {
60
+ "{type}Connection": {
61
+ edges: orNull({
62
+ type: "array",
63
+ items: orNull({ type: "ref", name: "{type}Edge" })
64
+ }),
65
+ nodes: orNull({
66
+ type: "array",
67
+ items: orNull({ type: "ref", name: "{type}" })
68
+ }),
69
+ pageInfo: { type: "ref", name: "PageInfo" }
70
+ },
71
+ "{type}Edge": {
72
+ cursor: { type: "text" },
73
+ node: orNull({ type: "ref", name: "{type}" })
74
+ }
75
+ }
76
+ };
77
+ var COLLECTION_METADATA_FIELDS = {
78
+ currentPage: { type: "number" },
79
+ limitValue: { type: "number" },
80
+ totalCount: { type: "number" },
81
+ totalPages: { type: "number" }
82
+ };
83
+ var COLLECTION_TYPE = {
84
+ name: "{type}Collection",
85
+ types: {
86
+ "{type}Collection": {
87
+ collection: { type: "array", items: { type: "ref", name: "{type}" } },
88
+ metadata: { type: "ref", name: "{metadata_type}" }
89
+ }
90
+ },
91
+ typeArguments: {
92
+ "{metadata_type}": {
93
+ keyword: "metadata_type",
94
+ fallback: "CollectionMetadata"
95
+ }
96
+ }
97
+ };
47
98
  function rootDirectory(options) {
48
99
  if (options.configDirectory === void 0 || path.isAbsolute(options.root)) {
49
100
  return options.root;
@@ -69,6 +120,38 @@ function graphqlRubyFramework(options) {
69
120
  argumentCallName: "argument",
70
121
  wiringKeywords: ["mutation", "resolver"],
71
122
  resolverMethodName: "resolve",
123
+ resolverMethodKeyword: "resolver_method",
124
+ // A Mutation or Resolver runs ready?, then authorized?, then resolve.
125
+ // A hook that returns false, or [false, payload], stops the field,
126
+ // and the payload comes back in its place.
127
+ resolverHooks: {
128
+ methods: ["ready?", "authorized?"],
129
+ answerIsListHead: true,
130
+ // A bare false from `ready?` resolves the field to null. One from
131
+ // `authorized?` raises, and the schema decides what the client sees.
132
+ refusalRaises: { "authorized?": "GraphQL::UnauthorizedFieldError" }
133
+ },
134
+ typeKeyword: "type",
135
+ typeNameCallName: "graphql_name",
136
+ // A field, and a mutation's or resolver's own type, can be null unless
137
+ // it says `null: false`. The items of a list cannot unless the list
138
+ // type says `[Type, null: true]`.
139
+ nullability: {
140
+ keyword: "null",
141
+ callName: "null",
142
+ nullableByDefault: true,
143
+ listItemsNullableByDefault: false
144
+ },
145
+ typeWrappers: {
146
+ connection_type: CONNECTION_TYPE,
147
+ collection_type: COLLECTION_TYPE
148
+ },
149
+ libraryTypes: {
150
+ PageInfo: PAGE_INFO_FIELDS,
151
+ CollectionMetadata: COLLECTION_METADATA_FIELDS
152
+ },
153
+ // Returning one of these puts it in `errors[]` in place of the value.
154
+ returnedErrorClassNames: ["GraphQL::ExecutionError"],
72
155
  ancestryRootClassNames: [...GRAPHQL_RUBY_ROOT_CLASS_NAMES],
73
156
  requiredKeyword: "required",
74
157
  // graphql-ruby registers an argument as required unless the call
@@ -124,13 +207,14 @@ var declares = {
124
207
  kind: "framework",
125
208
  package: "@suss/framework-graphql-ruby",
126
209
  dependencies: [{ ecosystem: "rubygems", name: "graphql" }],
127
- reads: "graphql-ruby class-based field DSL (Ruby). The pack follows `mutation:` and `resolver:` wiring one hop out to what the referenced class declares. It also records the model a resolver reads through `dataloader`, when a storage pack in the run recognizes that model.",
210
+ reads: "graphql-ruby class-based field DSL (Ruby). The pack follows `mutation:` and `resolver:` wiring to the referenced class, wherever the run declares it, and reads its arguments, its payload, its `resolve` method and the `ready?` and `authorized?` hooks that run first. It follows `resolver_method:` to the type's own method. Each path through that method records what the field returns, from its declared type with null where the schema allows it and the object type's fields, and the errors it raises or returns. It also records the model a resolver reads through `dataloader`, when a storage pack in the run recognizes that model.",
128
211
  configuration: {
129
212
  file: "suss.graphql-ruby.json",
130
213
  example: { root: "app/graphql" },
131
214
  required: true,
132
- why: "the directory a field's wired class is looked up under, read relative to this file. A Rails app generated by the library keeps its types and mutations under app/graphql.",
133
- defaults: { root: "app/graphql" }
215
+ why: "the directory a field's wired class is looked up under when no file in the run declares it, read relative to this file. A Rails app generated by the library keeps its types and mutations under app/graphql.",
216
+ defaults: { root: "app/graphql" },
217
+ paths: ["root"]
134
218
  }
135
219
  };
136
220
  var index_default = graphqlRubyFramework;
package/dist/node.js CHANGED
@@ -6,9 +6,11 @@ import {
6
6
  } from "ts-morph";
7
7
  import {
8
8
  declarationsBehind,
9
- findEnclosingFunction,
9
+ dottedPathOf,
10
+ fallbackOf,
10
11
  functionTargetOf,
11
12
  isDefaultedAt,
13
+ scalarValueOf,
12
14
  stringValueOf,
13
15
  symbolBehind,
14
16
  toFunctionRoot
@@ -36,6 +38,7 @@ import { functionCallBinding } from "@suss/behavioral-ir";
36
38
  import { Node as Node4 } from "ts-morph";
37
39
  import { writtenPayloadOf } from "@suss/adapter-typescript";
38
40
  import { ioBinding } from "@suss/behavioral-ir";
41
+ import { callSiteKey } from "@suss/extractor";
39
42
  var RECOGNITION = "@suss/runtime-node";
40
43
  function configBinding(where) {
41
44
  return runtimeConfigBinding({ recognition: RECOGNITION, ...where });
@@ -295,98 +298,46 @@ function schemaEnvReadsInside(callee, resolution) {
295
298
  SCHEMA_READS_INSIDE.set(callee, found);
296
299
  return found;
297
300
  }
298
- var readName = (name) => `process.env.${name}`;
299
- function isProcessEnv(node) {
301
+ var ENVIRONMENT_OBJECTS = [
302
+ "process.env",
303
+ "import.meta.env"
304
+ ];
305
+ var PROCESS_ENV = "process.env";
306
+ var IMPORT_META_ENV = "import.meta.env";
307
+ var VITE_BUILD_KEYS = /* @__PURE__ */ new Set(["MODE", "BASE_URL", "PROD", "DEV", "SSR"]);
308
+ var readName = (read) => read.name === null ? read.node.getText() : `${read.object}.${read.name}`;
309
+ function environmentSpelling(node) {
300
310
  if (!N2.isPropertyAccessExpression(node) || node.getName() !== "env") {
301
- return false;
311
+ return null;
302
312
  }
303
- const root = node.getExpression();
304
- return N2.isIdentifier(root) && root.getText() === "process";
313
+ const path = dottedPathOf(node);
314
+ return path !== null && ENVIRONMENT_OBJECTS.includes(path) ? path : null;
305
315
  }
306
316
  function dottedRead(node) {
307
- if (!isProcessEnv(node.getExpression())) {
317
+ const object = environmentSpelling(node.getExpression());
318
+ if (object === null) {
308
319
  return [];
309
320
  }
310
- return [{ name: node.getName(), defaulted: isDefaultedAt(node), node }];
321
+ return [
322
+ { name: node.getName(), defaulted: isDefaultedAt(node), node, object }
323
+ ];
311
324
  }
312
- function bracketRead(access, resolution) {
325
+ function bracketRead(access, object) {
313
326
  const argument = access.getArgumentExpression();
314
327
  if (argument === void 0) {
315
328
  return [];
316
329
  }
317
- if (N2.isStringLiteral(argument) || N2.isNoSubstitutionTemplateLiteral(argument)) {
318
- const name = argument.getLiteralValue();
319
- if (name.length === 0) {
320
- return [];
321
- }
322
- return [{ name, defaulted: isDefaultedAt(access), node: access }];
323
- }
324
- if (N2.isIdentifier(argument)) {
325
- return readsThroughParameter(access, argument, resolution);
326
- }
327
- return [];
328
- }
329
- var CALLER_LOOKUPS = /* @__PURE__ */ new WeakMap();
330
- function readsThroughParameter(access, index, resolution) {
331
- const remembered = CALLER_LOOKUPS.get(access);
332
- if (remembered !== void 0) {
333
- return remembered;
334
- }
335
- const found = callerLiteralReads(access, index, resolution);
336
- CALLER_LOOKUPS.set(access, found);
337
- return found;
338
- }
339
- function callerLiteralReads(access, index, resolution) {
340
- if (resolution === void 0) {
341
- return [];
342
- }
343
- const enclosing = findEnclosingFunction(access);
344
- if (enclosing === null) {
345
- return [];
346
- }
347
- const start = enclosing.getParameters().find((parameter) => parameter.getName() === index.getText());
348
- if (start === void 0) {
349
- return [];
350
- }
351
330
  const defaulted = isDefaultedAt(access);
352
- const reads = [];
353
- const pending = [start];
354
- const taken = /* @__PURE__ */ new Set();
355
- while (pending.length > 0) {
356
- const wanted = pending.pop();
357
- if (taken.has(wanted)) {
358
- continue;
359
- }
360
- taken.add(wanted);
361
- for (const passed of resolution.argumentsPassedTo(wanted)) {
362
- const literal = stringValueOf(passed.argument, resolution);
363
- if (literal !== null && literal.length > 0) {
364
- reads.push({ name: literal, defaulted, node: passed.call });
365
- continue;
366
- }
367
- const forwarded = forwardedParameter(passed.argument, passed.call);
368
- if (forwarded !== null) {
369
- pending.push(forwarded);
370
- }
371
- }
372
- }
373
- return reads;
374
- }
375
- function forwardedParameter(passed, call) {
376
- if (!N2.isIdentifier(passed)) {
377
- return null;
331
+ if (!N2.isStringLiteral(argument) && !N2.isNoSubstitutionTemplateLiteral(argument)) {
332
+ return [{ name: null, defaulted, node: access, object }];
378
333
  }
379
- const caller = findEnclosingFunction(call);
380
- if (caller === null) {
381
- return null;
382
- }
383
- const behind = symbolBehind(passed)?.getValueDeclaration();
384
- if (behind === void 0 || !N2.isParameterDeclaration(behind)) {
385
- return null;
334
+ const name = argument.getLiteralValue();
335
+ if (name.length === 0) {
336
+ return [];
386
337
  }
387
- return behind.getParent() === caller ? behind : null;
338
+ return [{ name, defaulted, node: access, object }];
388
339
  }
389
- function bindingRead(element) {
340
+ function bindingRead(element, object) {
390
341
  if (element.getDotDotDotToken() !== void 0) {
391
342
  return [];
392
343
  }
@@ -404,24 +355,25 @@ function bindingRead(element) {
404
355
  // A binding default covers a missing variable the same way `??`
405
356
  // does after a dotted read.
406
357
  defaulted: element.getInitializer() !== void 0 || isDefaultedAt(element),
407
- node: element
358
+ node: element,
359
+ object
408
360
  }
409
361
  ];
410
362
  }
411
- function destructuredReads(declaration) {
363
+ function destructuredReads(declaration, object) {
412
364
  const pattern = declaration.getNameNode();
413
365
  if (!N2.isObjectBindingPattern(pattern)) {
414
366
  return [];
415
367
  }
416
- return pattern.getElements().flatMap(bindingRead);
368
+ return pattern.getElements().flatMap((element) => bindingRead(element, object));
417
369
  }
418
- function readsThroughEnvObject(envNode, resolution) {
370
+ function readsThroughEnvObject(envNode, object) {
419
371
  const parent = envNode.getParent();
420
372
  if (N2.isElementAccessExpression(parent)) {
421
- return bracketRead(parent, resolution);
373
+ return bracketRead(parent, object);
422
374
  }
423
375
  if (N2.isVariableDeclaration(parent)) {
424
- return destructuredReads(parent);
376
+ return destructuredReads(parent, object);
425
377
  }
426
378
  return [];
427
379
  }
@@ -433,7 +385,8 @@ function envReadsAt(node, resolution) {
433
385
  if (!N2.isPropertyAccessExpression(node)) {
434
386
  return [];
435
387
  }
436
- return isProcessEnv(node) ? readsThroughEnvObject(node, resolution) : dottedRead(node);
388
+ const object = environmentSpelling(node);
389
+ return object === null ? dottedRead(node) : readsThroughEnvObject(node, object);
437
390
  }
438
391
  function readsThroughHelperCall(call, resolution) {
439
392
  const callee = functionBehindCallee(call.getExpression(), resolution);
@@ -442,14 +395,15 @@ function readsThroughHelperCall(call, resolution) {
442
395
  }
443
396
  const sitesNaming = namesReadAtSites(callee, resolution);
444
397
  const parameters = callee.getParameters();
445
- const defaultedByName = /* @__PURE__ */ new Map();
398
+ const byName = /* @__PURE__ */ new Map();
446
399
  call.getArguments().forEach((passed, at) => {
447
400
  const parameter = parameters[at];
448
401
  if (parameter === void 0) {
449
402
  return;
450
403
  }
451
404
  const sites = sitesNaming(parameter) ?? directEnvReads(callee, parameter);
452
- if (sites.length === 0) {
405
+ const [first] = sites;
406
+ if (first === void 0 || handsOnParameter(passed)) {
453
407
  return;
454
408
  }
455
409
  const literal = stringValueOf(passed, resolution);
@@ -457,25 +411,40 @@ function readsThroughHelperCall(call, resolution) {
457
411
  return;
458
412
  }
459
413
  const everywhere = sites.every(isDefaultedAt);
460
- defaultedByName.set(
461
- literal,
462
- (defaultedByName.get(literal) ?? true) && everywhere
463
- );
414
+ const known = byName.get(literal);
415
+ byName.set(literal, {
416
+ defaulted: (known?.defaulted ?? true) && everywhere,
417
+ object: known?.object ?? objectReadAt(first)
418
+ });
464
419
  });
465
420
  const wrapped = isDefaultedAt(call);
466
421
  return [
467
- ...[...defaultedByName].map(([name, atSites]) => ({
422
+ ...[...byName].map(([name, read]) => ({
468
423
  name,
469
- defaulted: atSites || wrapped,
470
- node: call
424
+ defaulted: read.defaulted || wrapped,
425
+ node: call,
426
+ object: read.object
471
427
  })),
472
428
  // A config module often parses its schema inside a function that
473
429
  // every handler calls, so each call reports the keys that parse reads.
474
430
  ...anchoredAt(schemaEnvReadsInside(callee, resolution), call)
475
431
  ];
476
432
  }
433
+ function handsOnParameter(passed) {
434
+ if (!N2.isIdentifier(passed)) {
435
+ return false;
436
+ }
437
+ const declared = symbolBehind(passed)?.getValueDeclaration();
438
+ return declared !== void 0 && N2.isParameterDeclaration(declared);
439
+ }
440
+ function objectReadAt(site) {
441
+ if (!N2.isElementAccessExpression(site)) {
442
+ return PROCESS_ENV;
443
+ }
444
+ return environmentSpelling(site.getExpression()) ?? PROCESS_ENV;
445
+ }
477
446
  function anchoredAt(reads, node) {
478
- return reads.map((read) => ({ ...read, node }));
447
+ return reads.map((read) => ({ ...read, node, object: PROCESS_ENV }));
479
448
  }
480
449
  function functionBehindCallee(callee, resolution) {
481
450
  const nameNode = N2.isPropertyAccessExpression(callee) ? callee.getNameNode() : callee;
@@ -524,7 +493,7 @@ function directEnvRead(fn, parameter) {
524
493
  for (const access of fn.getDescendantsOfKind(
525
494
  SyntaxKind2.ElementAccessExpression
526
495
  )) {
527
- if (!isProcessEnv(access.getExpression())) {
496
+ if (environmentSpelling(access.getExpression()) === null) {
528
497
  continue;
529
498
  }
530
499
  const argument = access.getArgumentExpression();
@@ -534,24 +503,36 @@ function directEnvRead(fn, parameter) {
534
503
  }
535
504
  return null;
536
505
  }
537
- function configReadEffect(read, where) {
506
+ function readsBuildKey(read) {
507
+ return read.object === IMPORT_META_ENV && read.name !== null && VITE_BUILD_KEYS.has(read.name);
508
+ }
509
+ function configReadEffect(read, where, resolution) {
510
+ if (readsBuildKey(read)) {
511
+ return opaqueRuntimeRead(readName(read));
512
+ }
513
+ const fallback = read.defaulted ? defaultValueAt(read.node, resolution) : null;
538
514
  return {
539
515
  type: "interaction",
540
516
  binding: configBinding(where),
541
- callee: readName(read.name),
517
+ callee: readName(read),
542
518
  interaction: {
543
519
  class: "config-read",
544
520
  name: read.name,
545
- defaulted: read.defaulted
521
+ defaulted: read.defaulted,
522
+ ...fallback === null ? {} : { default: fallback }
546
523
  }
547
524
  };
548
525
  }
526
+ function defaultValueAt(read, resolution) {
527
+ const fallback = fallbackOf(read);
528
+ return fallback === null ? null : scalarValueOf(fallback, resolution);
529
+ }
549
530
  function recognizeProcessEnvRead(access, where, resolution) {
550
531
  const reads = envReadsAt(access, resolution);
551
532
  if (reads.length === 0) {
552
533
  return null;
553
534
  }
554
- return reads.map((read) => configReadEffect(read, where));
535
+ return reads.map((read) => configReadEffect(read, where, resolution));
555
536
  }
556
537
  function envVarRecognizer(opts = {}) {
557
538
  return (access, ctx) => recognizeProcessEnvRead(
@@ -561,6 +542,7 @@ function envVarRecognizer(opts = {}) {
561
542
  );
562
543
  }
563
544
  var FILE_LOCATION_GLOBALS = /* @__PURE__ */ new Set(["__dirname", "__filename"]);
545
+ var ENVIRONMENT_PROPERTY = "env";
564
546
  var importMetaRecognizer = (access, _ctx) => {
565
547
  const node = access;
566
548
  if (!Node.isPropertyAccessExpression(node)) {
@@ -574,6 +556,9 @@ var importMetaRecognizer = (access, _ctx) => {
574
556
  if (keyword === void 0 || inner.getNameNode().getText() !== "meta") {
575
557
  return null;
576
558
  }
559
+ if (node.getName() === ENVIRONMENT_PROPERTY) {
560
+ return null;
561
+ }
577
562
  return [opaqueRuntimeRead(node.getText())];
578
563
  };
579
564
  var fileLocationRecognizer = (access, _ctx) => {
@@ -868,14 +853,13 @@ var streamWriteRecognizer = (call, ctx) => {
868
853
  type: "interaction",
869
854
  binding: ioBinding({ recognition: RECOGNITION2, target }),
870
855
  callee: callee.getText(),
871
- groupId: callSiteId(written),
872
856
  interaction: {
873
857
  class: "stream-write",
874
858
  payload: payload.shape,
875
859
  serialized: payload.serialized
876
860
  }
877
861
  };
878
- return [effect];
862
+ return [{ ...effect, groupId: callSiteKey(effect) }];
879
863
  };
880
864
  function targetOf(receiver, method, resolution) {
881
865
  const consoleStream = Object.hasOwn(CONSOLE_STREAMS, method) ? CONSOLE_STREAMS[method] : void 0;
@@ -904,11 +888,7 @@ function viaParameter(receiver, annotations, resolution) {
904
888
  function streamName(path) {
905
889
  return path.slice(path.lastIndexOf(".") + 1);
906
890
  }
907
- function callSiteId(call) {
908
- const { line, column } = call.getSourceFile().getLineAndColumnAtPos(call.getStart());
909
- return `${line}:${column}`;
910
- }
911
- var PACK_VERSION = "0.3.0";
891
+ var PACK_VERSION = "0.4.0";
912
892
  var optionsSchema = z.object({
913
893
  /**
914
894
  * The kind of deployment that runtime-config reads such as
@@ -955,7 +935,7 @@ function nodeRuntimePack(options = {}) {
955
935
  argumentParsers: PARSE_ARGS,
956
936
  inputMapping: { type: "positionalParams", params: [] },
957
937
  invocationRecognizers: [schedulingRecognizer, streamWriteRecognizer],
958
- environmentObjects: ["process.env"],
938
+ environmentObjects: [...ENVIRONMENT_OBJECTS],
959
939
  streamObjects: PROCESS_STREAMS,
960
940
  accessRecognizers: [
961
941
  // envRecognizer handles `process.env.X` and processRecognizer skips
@@ -973,7 +953,7 @@ var declares = {
973
953
  package: "@suss/runtime-node",
974
954
  dependencies: [],
975
955
  shippedWith: "typescript",
976
- reads: "Node.js runtime primitives, scheduling and the `process` surface, each recorded as an interaction effect. A `process.env.X` read, or a key of a schema parsed against `process.env`, becomes a config-read interaction. A module-loading global becomes a metadata-read interaction. A `console` call or a write to `process.stdout` or `process.stderr` becomes a stream-write interaction on the stream it goes to."
956
+ reads: "Node.js runtime primitives, scheduling and the `process` surface, each recorded as an interaction effect. A `process.env.X` or `import.meta.env.X` read, or a key of a schema parsed against either, becomes a config-read interaction. A module-loading global becomes a metadata-read interaction. A `console` call or a write to `process.stdout` or `process.stderr` becomes a stream-write interaction on the stream it goes to."
977
957
  };
978
958
  var index_default = nodeRuntimePack;
979
959
  export {
package/dist/prisma.js CHANGED
@@ -150,6 +150,55 @@ function textOf(file) {
150
150
  return "";
151
151
  }
152
152
  }
153
+ function generatedClientInputs(walked) {
154
+ const roots = /* @__PURE__ */ new Set();
155
+ for (const dir of new Set(walked.map((file) => path3.dirname(file)))) {
156
+ const root = projectRootOf(dir);
157
+ if (root !== null) {
158
+ roots.add(root);
159
+ }
160
+ }
161
+ const inputs = /* @__PURE__ */ new Set();
162
+ for (const root of roots) {
163
+ const project = readProjectAt(root);
164
+ for (const file of project?.readFrom.keys() ?? []) {
165
+ inputs.add(file);
166
+ }
167
+ for (const dir of [...project?.dirs ?? [], ...defaultClientDirs(root)]) {
168
+ for (const file of clientTypeFiles(dir)) {
169
+ inputs.add(file);
170
+ }
171
+ }
172
+ }
173
+ return [...inputs].sort();
174
+ }
175
+ function defaultClientDirs(root) {
176
+ for (let dir = root; ; dir = path3.dirname(dir)) {
177
+ const client = path3.join(dir, "node_modules", ".prisma", "client");
178
+ if (fs3.existsSync(client)) {
179
+ return [client];
180
+ }
181
+ if (path3.dirname(dir) === dir) {
182
+ return [];
183
+ }
184
+ }
185
+ }
186
+ var CLIENT_TYPE_FILE = /(\.d\.[cm]?ts|\.[cm]?ts|\.prisma|^package\.json)$/;
187
+ function clientTypeFiles(dir) {
188
+ let entries;
189
+ try {
190
+ entries = fs3.readdirSync(dir, { withFileTypes: true });
191
+ } catch {
192
+ return [];
193
+ }
194
+ return entries.flatMap((entry) => {
195
+ const file = path3.join(dir, entry.name);
196
+ if (entry.isDirectory()) {
197
+ return entry.name === "runtime" || entry.name === "node_modules" ? [] : clientTypeFiles(file);
198
+ }
199
+ return CLIENT_TYPE_FILE.test(entry.name) ? [file] : [];
200
+ });
201
+ }
153
202
  function isInGeneratedClient(filePath) {
154
203
  return generatedClientDirs(path3.dirname(filePath)).some(
155
204
  (dir) => filePath.startsWith(`${dir}${path3.sep}`)
@@ -774,6 +823,7 @@ function prismaFramework(options = {}) {
774
823
  // `prisma-client` generator writes no schema beside it.
775
824
  generatedModuleMarkers: [GENERATED_CLIENT_MARKER],
776
825
  generatedModuleDirs: generatedClientDirs,
826
+ discoveryInputs: generatedClientInputs,
777
827
  invocationRecognizers: [makeRecognizer(options)],
778
828
  // A tagged template is not an invocation, so the raw chain runs on
779
829
  // the access walk, which visits calls as well.