@gaganref/confect-cli 10.3.1-fork.17 → 10.3.1-fork.19

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.
@@ -52,6 +52,10 @@ var ImplMissingMiddlewareError = class extends Schema.TaggedError()("ImplMissing
52
52
  groupPath: Schema.String,
53
53
  missingMiddlewareKeys: Schema.Array(Schema.String)
54
54
  }) {};
55
+ var RequiredMiddlewareError = class extends Schema.TaggedError()("RequiredMiddlewareError", { missing: Schema.Array(Schema.Struct({
56
+ functionName: Schema.String,
57
+ middlewareKey: Schema.String
58
+ })) }) {};
55
59
  var ParentChildNameCollisionError = class extends Schema.TaggedError()("ParentChildNameCollisionError", {
56
60
  parentSpecPath: Schema.String,
57
61
  childSpecPath: Schema.String,
@@ -84,6 +88,7 @@ var HandWrittenConvexFileError = class extends Schema.TaggedError()("HandWritten
84
88
  convexPath: Schema.String,
85
89
  declarationPath: Schema.String
86
90
  }) {};
91
+ var UnownedConvexEntrypointError = class extends Schema.TaggedError()("UnownedConvexEntrypointError", { filePaths: Schema.Array(Schema.String) }) {};
87
92
  var DeclarationKindMismatchError = class extends Schema.TaggedError()("DeclarationKindMismatchError", {
88
93
  declarationPath: Schema.String,
89
94
  declaredKind: Schema.Literals(["app", "component"]),
@@ -109,6 +114,7 @@ const CodegenError = Schema.Union([
109
114
  ImplNotFinalizedError,
110
115
  ImplMissingFunctionsError,
111
116
  ImplMissingMiddlewareError,
117
+ RequiredMiddlewareError,
112
118
  ParentChildNameCollisionError,
113
119
  InvalidTableDefaultExportError,
114
120
  InvalidTableFilenameError,
@@ -118,6 +124,7 @@ const CodegenError = Schema.Union([
118
124
  InvalidConvexConfigError,
119
125
  InvalidDeclarationError,
120
126
  HandWrittenConvexFileError,
127
+ UnownedConvexEntrypointError,
121
128
  DeclarationKindMismatchError,
122
129
  CallbackPrefixError
123
130
  ]);
@@ -175,11 +182,13 @@ const renderParentChildNameCollisionError = (error) => singleLine("Spec ", forma
175
182
  const renderCodegenError = (error) => {
176
183
  if (isBuildError(error)) return renderBuildError(error);
177
184
  if (error._tag === "ComponentNodeGroupError") return singleLine(`Group "${error.groupPath}" in ${error.specPath} uses the Node runtime. Convex components do not support Node.js functions.`);
185
+ if (error._tag === "RequiredMiddlewareError") return singleLine("Required middleware is missing:\n", error.missing.map(({ functionName, middlewareKey }) => `${functionName} requires middleware "${middlewareKey}"`).join("\n"));
178
186
  if (error._tag === "RemoveBusyError") return singleLine("Could not remove ", formatPath(error.path), ` after ${error.attempts} attempts because it is busy. Close other tools using it and try again.`);
179
187
  if (error._tag === "InvalidDeclarationError") return singleLine("Declaration ", formatPath(error.declarationPath), ` is invalid: ${error.reason}`);
180
188
  if (error._tag === "DeclarationKindMismatchError") return singleLine("Declaration ", formatPath(error.declarationPath), ` declares kind "${error.declaredKind}", but the target directory is kind "${error.targetKind}".`);
181
189
  if (error._tag === "CallbackPrefixError") return singleLine("Callback contract ", `"${error.contractId}" in `, formatPath(error.declarationPath), ` must start with "${error.componentName}/" for component "${error.componentName}".`);
182
190
  if (error._tag === "HandWrittenConvexFileError") return singleLine("Found a hand-written ", formatPath(error.convexPath), ". `confect codegen` writes it from ", formatPath(error.declarationPath), " now; move its contents there and delete the file.");
191
+ if (error._tag === "UnownedConvexEntrypointError") return singleLine(error.filePaths.map((file) => formatPath(file)).join(", "), error.filePaths.length === 1 ? " was" : " were", " not written by confect codegen. Generated files only re-export the registry; put authored code outside convex/. If a file is stale generated output, delete it and run codegen again.");
183
192
  return Match.value(error).pipe(Match.tag("SnapshotError", ({ reason, relativePath, pathSegments }) => singleLine(`Invalid generation metadata (${reason})`, relativePath === "" ? "" : ` for ${relativePath}`, pathSegments.length === 0 ? "." : ` at ${pathSegments.join("/")}.`)), Match.tag("MissingImplFileError", renderMissingImplFileError), Match.tag("MissingSpecFileError", renderMissingSpecFileError), Match.tag("SpecMissingDefaultGroupSpecError", renderSpecMissingDefaultGroupSpecError), Match.tag("SpecImportsServerError", renderSpecImportsServerError), Match.tag("InvalidMiddlewareAttachmentError", (attachmentError) => singleLine("Spec ", formatPath(attachmentError.specPath), `: ${attachmentError.message}`)), Match.tag("ImplMissingSpecImportError", renderImplMissingSpecImportError), Match.tag("ImplMissingDefaultLayerError", renderImplMissingDefaultLayerError), Match.tag("ImplNotFinalizedError", renderImplNotFinalizedError), Match.tag("ImplMissingFunctionsError", renderImplMissingFunctionsError), Match.tag("ImplMissingMiddlewareError", renderImplMissingMiddlewareError), Match.tag("ParentChildNameCollisionError", renderParentChildNameCollisionError), Match.tag("InvalidTableDefaultExportError", renderInvalidTableDefaultExportError), Match.tag("InvalidTableFilenameError", renderInvalidTableFilenameError), Match.tag("DuplicateTableNameError", renderDuplicateTableNameError), Match.tag("LegacySchemaFileError", renderLegacySchemaFileError), Match.tag("ConflictingDocNameError", renderConflictingDocNameError), Match.tag("InvalidConvexConfigError", renderInvalidConvexConfigError), Match.exhaustive);
184
193
  };
185
194
  const logCodegenError = (error) => Console.error(renderCodegenError(error));
@@ -189,6 +198,6 @@ const logCodegenError = (error) => Console.error(renderCodegenError(error));
189
198
  */
190
199
  const tapAndLog = (effect) => effect.pipe(Effect.tapError((error) => isCodegenError(error) ? logCodegenError(error) : Effect.void));
191
200
  //#endregion
192
- export { CallbackPrefixError, CodegenError, ComponentNodeGroupError, ConflictingDocNameError, DeclarationKindMismatchError, DuplicateTableNameError, HandWrittenConvexFileError, ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingMiddlewareError, ImplMissingSpecImportError, ImplNotFinalizedError, InvalidConvexConfigError, InvalidDeclarationError, InvalidMiddlewareAttachmentError, InvalidTableDefaultExportError, InvalidTableFilenameError, LegacySchemaFileError, MissingImplFileError, MissingSpecFileError, ParentChildNameCollisionError, RemoveBusyError, SpecImportsServerError, SpecMissingDefaultGroupSpecError, isCodegenError, logCodegenError, renderCodegenError, tapAndLog };
201
+ export { CallbackPrefixError, CodegenError, ComponentNodeGroupError, ConflictingDocNameError, DeclarationKindMismatchError, DuplicateTableNameError, HandWrittenConvexFileError, ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingMiddlewareError, ImplMissingSpecImportError, ImplNotFinalizedError, InvalidConvexConfigError, InvalidDeclarationError, InvalidMiddlewareAttachmentError, InvalidTableDefaultExportError, InvalidTableFilenameError, LegacySchemaFileError, MissingImplFileError, MissingSpecFileError, ParentChildNameCollisionError, RemoveBusyError, RequiredMiddlewareError, SpecImportsServerError, SpecMissingDefaultGroupSpecError, UnownedConvexEntrypointError, isCodegenError, logCodegenError, renderCodegenError, tapAndLog };
193
202
 
194
203
  //# sourceMappingURL=CodegenError.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodegenError.mjs","names":["Ansi.red"],"sources":["../src/CodegenError.ts"],"sourcesContent":["import * as Array from \"effect/Array\";\nimport * as Console from \"effect/Console\";\nimport { pipe } from \"effect/Function\";\nimport * as Effect from \"effect/Effect\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport { BuildError, isBuildError } from \"./BuildError.js\";\nimport { SnapshotError } from \"./SnapshotError.js\";\nimport * as Ansi from \"./Ansi.js\";\nimport { formatPath, renderBuildError } from \"./log.js\";\n\n// --- Variants ---\n\nexport class MissingImplFileError extends Schema.TaggedError<MissingImplFileError>()(\n \"MissingImplFileError\",\n {\n specPath: Schema.String,\n expectedImplPath: Schema.String,\n },\n) {}\n\nexport class MissingSpecFileError extends Schema.TaggedError<MissingSpecFileError>()(\n \"MissingSpecFileError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class SpecMissingDefaultGroupSpecError extends Schema.TaggedError<SpecMissingDefaultGroupSpecError>()(\n \"SpecMissingDefaultGroupSpecError\",\n {\n specPath: Schema.String,\n },\n) {}\n\nexport class RemoveBusyError extends Schema.TaggedError<RemoveBusyError>()(\n \"RemoveBusyError\",\n { path: Schema.String, attempts: Schema.Finite, cause: Schema.Unknown },\n) {}\n\nexport class ComponentNodeGroupError extends Schema.TaggedError<ComponentNodeGroupError>()(\n \"ComponentNodeGroupError\",\n {\n specPath: Schema.String,\n groupPath: Schema.String,\n },\n) {}\n\nexport class SpecImportsServerError extends Schema.TaggedError<SpecImportsServerError>()(\n \"SpecImportsServerError\",\n {\n specPath: Schema.String,\n importerPaths: Schema.Array(Schema.String),\n },\n) {}\n\nexport class InvalidMiddlewareAttachmentError extends Schema.TaggedError<InvalidMiddlewareAttachmentError>()(\n \"InvalidMiddlewareAttachmentError\",\n { specPath: Schema.String, message: Schema.String },\n) {}\n\nexport class ImplMissingSpecImportError extends Schema.TaggedError<ImplMissingSpecImportError>()(\n \"ImplMissingSpecImportError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingDefaultLayerError extends Schema.TaggedError<ImplMissingDefaultLayerError>()(\n \"ImplMissingDefaultLayerError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplNotFinalizedError extends Schema.TaggedError<ImplNotFinalizedError>()(\n \"ImplNotFinalizedError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingFunctionsError extends Schema.TaggedError<ImplMissingFunctionsError>()(\n \"ImplMissingFunctionsError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingFunctionNames: Schema.Array(Schema.String),\n },\n) {}\n\nexport class ImplMissingMiddlewareError extends Schema.TaggedError<ImplMissingMiddlewareError>()(\n \"ImplMissingMiddlewareError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingMiddlewareKeys: Schema.Array(Schema.String),\n },\n) {}\n\nexport class ParentChildNameCollisionError extends Schema.TaggedError<ParentChildNameCollisionError>()(\n \"ParentChildNameCollisionError\",\n {\n parentSpecPath: Schema.String,\n childSpecPath: Schema.String,\n collisionName: Schema.String,\n collisionKind: Schema.Literals([\"function\", \"group\"]),\n },\n) {}\n\nexport class InvalidTableDefaultExportError extends Schema.TaggedError<InvalidTableDefaultExportError>()(\n \"InvalidTableDefaultExportError\",\n {\n tablePath: Schema.String,\n },\n) {}\n\nexport class InvalidTableFilenameError extends Schema.TaggedError<InvalidTableFilenameError>()(\n \"InvalidTableFilenameError\",\n {\n tablePath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class DuplicateTableNameError extends Schema.TaggedError<DuplicateTableNameError>()(\n \"DuplicateTableNameError\",\n {\n // Every table name that more than one file resolves to, each paired with\n // the colliding file paths. All collisions are captured in a single pass\n // so the user can fix them together rather than re-running codegen once\n // per conflict.\n collisions: Schema.Array(\n Schema.Struct({\n tableName: Schema.String,\n tablePaths: Schema.Array(Schema.String),\n }),\n ),\n },\n) {}\n\nexport class LegacySchemaFileError extends Schema.TaggedError<LegacySchemaFileError>()(\n \"LegacySchemaFileError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport class ConflictingDocNameError extends Schema.TaggedError<ConflictingDocNameError>()(\n \"ConflictingDocNameError\",\n {\n collisions: Schema.Array(\n Schema.Struct({\n docName: Schema.String,\n tableNames: Schema.Array(Schema.String),\n }),\n ),\n },\n) {}\n\nexport class InvalidConvexConfigError extends Schema.TaggedError<InvalidConvexConfigError>()(\n \"InvalidConvexConfigError\",\n {\n configPath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class InvalidDeclarationError extends Schema.TaggedError<InvalidDeclarationError>()(\n \"InvalidDeclarationError\",\n {\n declarationPath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class HandWrittenConvexFileError extends Schema.TaggedError<HandWrittenConvexFileError>()(\n \"HandWrittenConvexFileError\",\n {\n convexPath: Schema.String,\n declarationPath: Schema.String,\n },\n) {}\n\nexport class DeclarationKindMismatchError extends Schema.TaggedError<DeclarationKindMismatchError>()(\n \"DeclarationKindMismatchError\",\n {\n declarationPath: Schema.String,\n declaredKind: Schema.Literals([\"app\", \"component\"]),\n targetKind: Schema.Literals([\"app\", \"component\"]),\n },\n) {}\n\nexport class CallbackPrefixError extends Schema.TaggedError<CallbackPrefixError>()(\n \"CallbackPrefixError\",\n {\n declarationPath: Schema.String,\n contractId: Schema.String,\n componentName: Schema.String,\n },\n) {}\n\nexport const CodegenError = Schema.Union([\n SnapshotError,\n BuildError,\n MissingImplFileError,\n MissingSpecFileError,\n SpecMissingDefaultGroupSpecError,\n ComponentNodeGroupError,\n RemoveBusyError,\n SpecImportsServerError,\n InvalidMiddlewareAttachmentError,\n ImplMissingSpecImportError,\n ImplMissingDefaultLayerError,\n ImplNotFinalizedError,\n ImplMissingFunctionsError,\n ImplMissingMiddlewareError,\n ParentChildNameCollisionError,\n InvalidTableDefaultExportError,\n InvalidTableFilenameError,\n DuplicateTableNameError,\n LegacySchemaFileError,\n ConflictingDocNameError,\n InvalidConvexConfigError,\n InvalidDeclarationError,\n HandWrittenConvexFileError,\n DeclarationKindMismatchError,\n CallbackPrefixError,\n]);\nexport type CodegenError = typeof CodegenError.Type;\n\nexport const isCodegenError = (error: unknown): error is CodegenError => {\n if (isBuildError(error)) return true;\n return Schema.is(CodegenError)(error);\n};\n\n// --- Per-variant rendering ---\n\nconst cross = Ansi.red(\"✘\");\n\nconst stemFromSpecPath = (specPath: string): string => {\n const lastSep = Math.max(\n specPath.lastIndexOf(\"/\"),\n specPath.lastIndexOf(\"\\\\\"),\n );\n const basename = lastSep < 0 ? specPath : specPath.slice(lastSep + 1);\n return basename.endsWith(\".spec.ts\")\n ? basename.slice(0, -\".spec.ts\".length)\n : basename;\n};\n\nconst singleLine = (...parts: ReadonlyArray<string>): string =>\n `${cross} ${parts.join(\"\")}`;\n\nconst renderMissingImplFileError = (error: MissingImplFileError): string =>\n singleLine(\n \"Spec \",\n formatPath(error.specPath),\n \" has no sibling impl; create \",\n formatPath(error.expectedImplPath),\n \" and default-export a GroupImpl layer from it.\",\n );\n\nconst renderMissingSpecFileError = (error: MissingSpecFileError): string =>\n singleLine(\n \"Impl \",\n formatPath(error.implPath),\n \" has no sibling spec; create \",\n formatPath(error.expectedSpecPath),\n \" and default-export a GroupSpec from it, or remove the impl.\",\n );\n\nconst renderSpecMissingDefaultGroupSpecError = (\n error: SpecMissingDefaultGroupSpecError,\n): string =>\n singleLine(\n \"Spec \",\n formatPath(error.specPath),\n \" must default-export a GroupSpec; build it with GroupSpec.make() or GroupSpec.makeNode().\",\n );\n\nconst renderSpecImportsServerError = (\n error: SpecImportsServerError,\n): string => {\n const importers = error.importerPaths.join(\", \");\n return singleLine(\n \"Spec \",\n formatPath(error.specPath),\n ` reaches a module that imports \\`@confect/server\\`: ${importers}. Spec modules are bundled into your client, so anything they import ships to the browser—move the server logic into a \\`*.impl.ts\\` module, or use \\`import type\\` if you only need the types.`,\n );\n};\n\nconst renderImplMissingSpecImportError = (\n error: ImplMissingSpecImportError,\n): string => {\n const stem = stemFromSpecPath(error.expectedSpecPath);\n return singleLine(\n \"Impl \",\n formatPath(error.implPath),\n ` does not import its sibling spec; add \\`import ${stem} from \"./${stem}.spec.js\"\\` and pass it to FunctionImpl.make/GroupImpl.make.`,\n );\n};\n\nconst renderImplMissingDefaultLayerError = (\n error: ImplMissingDefaultLayerError,\n): string =>\n singleLine(\n \"Impl \",\n formatPath(error.implPath),\n \" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(databaseSchema, groupSpec).pipe(Layer.provide(...))` and `export default` it.\",\n );\n\nconst renderImplNotFinalizedError = (error: ImplNotFinalizedError): string =>\n singleLine(\n \"Impl \",\n formatPath(error.implPath),\n \" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(databaseSchema, group).pipe(Layer.provide(...), GroupImpl.finalize)`).\",\n );\n\nconst renderImplMissingFunctionsError = (\n error: ImplMissingFunctionsError,\n): string => {\n const names = error.missingFunctionNames.join(\", \");\n return singleLine(\n \"Impl \",\n formatPath(error.implPath),\n ` does not implement every function declared by group \\`${error.groupPath}\\`; missing: ${names}. Add a \\`FunctionImpl.make\\` for each missing function and provide it to the group layer.`,\n );\n};\n\nconst renderImplMissingMiddlewareError = (\n error: ImplMissingMiddlewareError,\n): string => {\n const keys = error.missingMiddlewareKeys.join(\", \");\n return singleLine(\n \"Impl \",\n formatPath(error.implPath),\n ` does not implement every middleware attached to group \\`${error.groupPath}\\`; missing: ${keys}. Provide a \\`MiddlewareImpl.make\\` (or \\`makeByFunctionType\\`/\\`provides\\`) layer for each missing middleware to the group layer.`,\n );\n};\n\nconst renderInvalidTableDefaultExportError = (\n error: InvalidTableDefaultExportError,\n): string =>\n singleLine(\n \"Table \",\n formatPath(error.tablePath),\n \" must default-export a Table (e.g. `export default Table.make({ ... })`); convert any named export to a default export.\",\n );\n\nconst renderInvalidTableFilenameError = (\n error: InvalidTableFilenameError,\n): string =>\n singleLine(\n \"Table \",\n formatPath(error.tablePath),\n ` has an invalid filename: ${error.reason} Convex table names must start with a letter and contain only letters, numbers, and underscores; leading underscores are reserved for system tables.`,\n );\n\nconst renderDuplicateTableNameError = (\n error: DuplicateTableNameError,\n): string => {\n const conflicts = error.collisions\n .map(\n ({ tableName, tablePaths }) =>\n `\\`${tableName}\\` (${tablePaths.join(\", \")})`,\n )\n .join(\"; \");\n return singleLine(\n `Multiple files under \\`confect/tables/\\` resolve to the same table name. Table names are derived from filenames, so each must be unique across the directory (including subdirectories); rename or remove all but one. Conflicts: ${conflicts}.`,\n );\n};\n\nconst renderConflictingDocNameError = (\n error: ConflictingDocNameError,\n): string => {\n const conflicts = pipe(\n error.collisions,\n Array.map(\n ({ docName, tableNames }) =>\n `\\`${docName}\\` (${Array.join(tableNames, \", \")})`,\n ),\n Array.join(\"; \"),\n );\n return singleLine(\n `Multiple tables fold to the same generated document type name. Table names are converted to PascalCase (so \\`user_profiles\\` and \\`userProfiles\\` both become \\`UserProfilesDoc\\`); rename all but one of each colliding group. Conflicts: ${conflicts}.`,\n );\n};\n\nconst renderInvalidConvexConfigError = (\n error: InvalidConvexConfigError,\n): string =>\n singleLine(\n \"Convex config \",\n formatPath(error.configPath),\n ` could not be evaluated: ${error.reason}`,\n );\n\nconst renderLegacySchemaFileError = (error: LegacySchemaFileError): string =>\n singleLine(\n \"Found a legacy \",\n formatPath(error.schemaPath),\n \". Delete it: tables in `confect/tables/*.ts` are now the single source of truth, and the runtime schema is generated as `confect/_generated/schema.ts`.\",\n );\n\nconst renderParentChildNameCollisionError = (\n error: ParentChildNameCollisionError,\n): string =>\n singleLine(\n \"Spec \",\n formatPath(error.parentSpecPath),\n ` declares a ${error.collisionKind} \\`${error.collisionName}\\` whose name collides with the sibling subdirectory spec `,\n formatPath(error.childSpecPath),\n `. Rename one of them so the assembled spec has a unique key at this path.`,\n );\n\n/**\n * Render any {@link CodegenError} into a styled, ready-to-print string.\n * Single-error variants render to a one-line `✘`-prefixed message;\n * `BundleFailedError` (the only multi-error variant) renders to a header plus\n * an esbuild diagnostic block.\n */\nexport const renderCodegenError = (error: CodegenError): string => {\n if (isBuildError(error)) return renderBuildError(error);\n // The renderer pipeline below is at Effect's pipe arity limit, so the\n // fork's errors render here.\n if (error._tag === \"ComponentNodeGroupError\") {\n return singleLine(\n `Group \"${error.groupPath}\" in ${error.specPath} uses the Node runtime. Convex components do not support Node.js functions.`,\n );\n }\n if (error._tag === \"RemoveBusyError\") {\n return singleLine(\n \"Could not remove \",\n formatPath(error.path),\n ` after ${error.attempts} attempts because it is busy. Close other tools using it and try again.`,\n );\n }\n if (error._tag === \"InvalidDeclarationError\") {\n return singleLine(\n \"Declaration \",\n formatPath(error.declarationPath),\n ` is invalid: ${error.reason}`,\n );\n }\n if (error._tag === \"DeclarationKindMismatchError\") {\n return singleLine(\n \"Declaration \",\n formatPath(error.declarationPath),\n ` declares kind \"${error.declaredKind}\", but the target directory is kind \"${error.targetKind}\".`,\n );\n }\n if (error._tag === \"CallbackPrefixError\") {\n return singleLine(\n \"Callback contract \",\n `\"${error.contractId}\" in `,\n formatPath(error.declarationPath),\n ` must start with \"${error.componentName}/\" for component \"${error.componentName}\".`,\n );\n }\n if (error._tag === \"HandWrittenConvexFileError\") {\n return singleLine(\n \"Found a hand-written \",\n formatPath(error.convexPath),\n \". `confect codegen` writes it from \",\n formatPath(error.declarationPath),\n \" now; move its contents there and delete the file.\",\n );\n }\n return Match.value(error).pipe(\n Match.tag(\"SnapshotError\", ({ reason, relativePath, pathSegments }) =>\n singleLine(\n `Invalid generation metadata (${reason})`,\n relativePath === \"\" ? \"\" : ` for ${relativePath}`,\n pathSegments.length === 0 ? \".\" : ` at ${pathSegments.join(\"/\")}.`,\n ),\n ),\n Match.tag(\"MissingImplFileError\", renderMissingImplFileError),\n Match.tag(\"MissingSpecFileError\", renderMissingSpecFileError),\n Match.tag(\n \"SpecMissingDefaultGroupSpecError\",\n renderSpecMissingDefaultGroupSpecError,\n ),\n Match.tag(\"SpecImportsServerError\", renderSpecImportsServerError),\n Match.tag(\"InvalidMiddlewareAttachmentError\", (attachmentError) =>\n singleLine(\n \"Spec \",\n formatPath(attachmentError.specPath),\n `: ${attachmentError.message}`,\n ),\n ),\n Match.tag(\"ImplMissingSpecImportError\", renderImplMissingSpecImportError),\n Match.tag(\n \"ImplMissingDefaultLayerError\",\n renderImplMissingDefaultLayerError,\n ),\n Match.tag(\"ImplNotFinalizedError\", renderImplNotFinalizedError),\n Match.tag(\"ImplMissingFunctionsError\", renderImplMissingFunctionsError),\n Match.tag(\"ImplMissingMiddlewareError\", renderImplMissingMiddlewareError),\n Match.tag(\n \"ParentChildNameCollisionError\",\n renderParentChildNameCollisionError,\n ),\n Match.tag(\n \"InvalidTableDefaultExportError\",\n renderInvalidTableDefaultExportError,\n ),\n Match.tag(\"InvalidTableFilenameError\", renderInvalidTableFilenameError),\n Match.tag(\"DuplicateTableNameError\", renderDuplicateTableNameError),\n Match.tag(\"LegacySchemaFileError\", renderLegacySchemaFileError),\n Match.tag(\"ConflictingDocNameError\", renderConflictingDocNameError),\n Match.tag(\"InvalidConvexConfigError\", renderInvalidConvexConfigError),\n Match.exhaustive,\n );\n};\n\nexport const logCodegenError = (error: CodegenError) =>\n Console.error(renderCodegenError(error));\n\n// --- Effect combinators ---\n\n/**\n * Log any {@link CodegenError} thrown by `effect` and propagate the failure\n * unchanged so the caller's error channel is preserved.\n */\nexport const tapAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, E, R> =>\n effect.pipe(\n Effect.tapError((error) =>\n isCodegenError(error) ? logCodegenError(error) : Effect.void,\n ),\n );\n\n/**\n * Catch any {@link CodegenError} thrown by `effect`, log it, and resolve to\n * `Option.none()`. Success resolves to `Option.some(value)`.\n */\n// oxlint-disable effecttsgo/unsafe-effect-type-assertion -- catchIf removes the error variant selected by this refinement.\nexport const catchAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R> =>\n Effect.catchIf(Effect.map(effect, Option.some<A>), isCodegenError, (error) =>\n logCodegenError(error).pipe(Effect.as(Option.none<A>())),\n ) as Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R>;\n// oxlint-enable effecttsgo/unsafe-effect-type-assertion\n"],"mappings":"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"}
1
+ {"version":3,"file":"CodegenError.mjs","names":["Ansi.red"],"sources":["../src/CodegenError.ts"],"sourcesContent":["import * as Array from \"effect/Array\";\nimport * as Console from \"effect/Console\";\nimport { pipe } from \"effect/Function\";\nimport * as Effect from \"effect/Effect\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport { BuildError, isBuildError } from \"./BuildError.js\";\nimport { SnapshotError } from \"./SnapshotError.js\";\nimport * as Ansi from \"./Ansi.js\";\nimport { formatPath, renderBuildError } from \"./log.js\";\n\n// --- Variants ---\n\nexport class MissingImplFileError extends Schema.TaggedError<MissingImplFileError>()(\n \"MissingImplFileError\",\n {\n specPath: Schema.String,\n expectedImplPath: Schema.String,\n },\n) {}\n\nexport class MissingSpecFileError extends Schema.TaggedError<MissingSpecFileError>()(\n \"MissingSpecFileError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class SpecMissingDefaultGroupSpecError extends Schema.TaggedError<SpecMissingDefaultGroupSpecError>()(\n \"SpecMissingDefaultGroupSpecError\",\n {\n specPath: Schema.String,\n },\n) {}\n\nexport class RemoveBusyError extends Schema.TaggedError<RemoveBusyError>()(\n \"RemoveBusyError\",\n { path: Schema.String, attempts: Schema.Finite, cause: Schema.Unknown },\n) {}\n\nexport class ComponentNodeGroupError extends Schema.TaggedError<ComponentNodeGroupError>()(\n \"ComponentNodeGroupError\",\n {\n specPath: Schema.String,\n groupPath: Schema.String,\n },\n) {}\n\nexport class SpecImportsServerError extends Schema.TaggedError<SpecImportsServerError>()(\n \"SpecImportsServerError\",\n {\n specPath: Schema.String,\n importerPaths: Schema.Array(Schema.String),\n },\n) {}\n\nexport class InvalidMiddlewareAttachmentError extends Schema.TaggedError<InvalidMiddlewareAttachmentError>()(\n \"InvalidMiddlewareAttachmentError\",\n { specPath: Schema.String, message: Schema.String },\n) {}\n\nexport class ImplMissingSpecImportError extends Schema.TaggedError<ImplMissingSpecImportError>()(\n \"ImplMissingSpecImportError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingDefaultLayerError extends Schema.TaggedError<ImplMissingDefaultLayerError>()(\n \"ImplMissingDefaultLayerError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplNotFinalizedError extends Schema.TaggedError<ImplNotFinalizedError>()(\n \"ImplNotFinalizedError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingFunctionsError extends Schema.TaggedError<ImplMissingFunctionsError>()(\n \"ImplMissingFunctionsError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingFunctionNames: Schema.Array(Schema.String),\n },\n) {}\n\nexport class ImplMissingMiddlewareError extends Schema.TaggedError<ImplMissingMiddlewareError>()(\n \"ImplMissingMiddlewareError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingMiddlewareKeys: Schema.Array(Schema.String),\n },\n) {}\n\nexport class RequiredMiddlewareError extends Schema.TaggedError<RequiredMiddlewareError>()(\n \"RequiredMiddlewareError\",\n {\n missing: Schema.Array(\n Schema.Struct({\n functionName: Schema.String,\n middlewareKey: Schema.String,\n }),\n ),\n },\n) {}\n\nexport class ParentChildNameCollisionError extends Schema.TaggedError<ParentChildNameCollisionError>()(\n \"ParentChildNameCollisionError\",\n {\n parentSpecPath: Schema.String,\n childSpecPath: Schema.String,\n collisionName: Schema.String,\n collisionKind: Schema.Literals([\"function\", \"group\"]),\n },\n) {}\n\nexport class InvalidTableDefaultExportError extends Schema.TaggedError<InvalidTableDefaultExportError>()(\n \"InvalidTableDefaultExportError\",\n {\n tablePath: Schema.String,\n },\n) {}\n\nexport class InvalidTableFilenameError extends Schema.TaggedError<InvalidTableFilenameError>()(\n \"InvalidTableFilenameError\",\n {\n tablePath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class DuplicateTableNameError extends Schema.TaggedError<DuplicateTableNameError>()(\n \"DuplicateTableNameError\",\n {\n // Every table name that more than one file resolves to, each paired with\n // the colliding file paths. All collisions are captured in a single pass\n // so the user can fix them together rather than re-running codegen once\n // per conflict.\n collisions: Schema.Array(\n Schema.Struct({\n tableName: Schema.String,\n tablePaths: Schema.Array(Schema.String),\n }),\n ),\n },\n) {}\n\nexport class LegacySchemaFileError extends Schema.TaggedError<LegacySchemaFileError>()(\n \"LegacySchemaFileError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport class ConflictingDocNameError extends Schema.TaggedError<ConflictingDocNameError>()(\n \"ConflictingDocNameError\",\n {\n collisions: Schema.Array(\n Schema.Struct({\n docName: Schema.String,\n tableNames: Schema.Array(Schema.String),\n }),\n ),\n },\n) {}\n\nexport class InvalidConvexConfigError extends Schema.TaggedError<InvalidConvexConfigError>()(\n \"InvalidConvexConfigError\",\n {\n configPath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class InvalidDeclarationError extends Schema.TaggedError<InvalidDeclarationError>()(\n \"InvalidDeclarationError\",\n {\n declarationPath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class HandWrittenConvexFileError extends Schema.TaggedError<HandWrittenConvexFileError>()(\n \"HandWrittenConvexFileError\",\n {\n convexPath: Schema.String,\n declarationPath: Schema.String,\n },\n) {}\n\nexport class UnownedConvexEntrypointError extends Schema.TaggedError<UnownedConvexEntrypointError>()(\n \"UnownedConvexEntrypointError\",\n { filePaths: Schema.Array(Schema.String) },\n) {}\n\nexport class DeclarationKindMismatchError extends Schema.TaggedError<DeclarationKindMismatchError>()(\n \"DeclarationKindMismatchError\",\n {\n declarationPath: Schema.String,\n declaredKind: Schema.Literals([\"app\", \"component\"]),\n targetKind: Schema.Literals([\"app\", \"component\"]),\n },\n) {}\n\nexport class CallbackPrefixError extends Schema.TaggedError<CallbackPrefixError>()(\n \"CallbackPrefixError\",\n {\n declarationPath: Schema.String,\n contractId: Schema.String,\n componentName: Schema.String,\n },\n) {}\n\nexport const CodegenError = Schema.Union([\n SnapshotError,\n BuildError,\n MissingImplFileError,\n MissingSpecFileError,\n SpecMissingDefaultGroupSpecError,\n ComponentNodeGroupError,\n RemoveBusyError,\n SpecImportsServerError,\n InvalidMiddlewareAttachmentError,\n ImplMissingSpecImportError,\n ImplMissingDefaultLayerError,\n ImplNotFinalizedError,\n ImplMissingFunctionsError,\n ImplMissingMiddlewareError,\n RequiredMiddlewareError,\n ParentChildNameCollisionError,\n InvalidTableDefaultExportError,\n InvalidTableFilenameError,\n DuplicateTableNameError,\n LegacySchemaFileError,\n ConflictingDocNameError,\n InvalidConvexConfigError,\n InvalidDeclarationError,\n HandWrittenConvexFileError,\n UnownedConvexEntrypointError,\n DeclarationKindMismatchError,\n CallbackPrefixError,\n]);\nexport type CodegenError = typeof CodegenError.Type;\n\nexport const isCodegenError = (error: unknown): error is CodegenError => {\n if (isBuildError(error)) return true;\n return Schema.is(CodegenError)(error);\n};\n\n// --- Per-variant rendering ---\n\nconst cross = Ansi.red(\"✘\");\n\nconst stemFromSpecPath = (specPath: string): string => {\n const lastSep = Math.max(\n specPath.lastIndexOf(\"/\"),\n specPath.lastIndexOf(\"\\\\\"),\n );\n const basename = lastSep < 0 ? specPath : specPath.slice(lastSep + 1);\n return basename.endsWith(\".spec.ts\")\n ? basename.slice(0, -\".spec.ts\".length)\n : basename;\n};\n\nconst singleLine = (...parts: ReadonlyArray<string>): string =>\n `${cross} ${parts.join(\"\")}`;\n\nconst renderMissingImplFileError = (error: MissingImplFileError): string =>\n singleLine(\n \"Spec \",\n formatPath(error.specPath),\n \" has no sibling impl; create \",\n formatPath(error.expectedImplPath),\n \" and default-export a GroupImpl layer from it.\",\n );\n\nconst renderMissingSpecFileError = (error: MissingSpecFileError): string =>\n singleLine(\n \"Impl \",\n formatPath(error.implPath),\n \" has no sibling spec; create \",\n formatPath(error.expectedSpecPath),\n \" and default-export a GroupSpec from it, or remove the impl.\",\n );\n\nconst renderSpecMissingDefaultGroupSpecError = (\n error: SpecMissingDefaultGroupSpecError,\n): string =>\n singleLine(\n \"Spec \",\n formatPath(error.specPath),\n \" must default-export a GroupSpec; build it with GroupSpec.make() or GroupSpec.makeNode().\",\n );\n\nconst renderSpecImportsServerError = (\n error: SpecImportsServerError,\n): string => {\n const importers = error.importerPaths.join(\", \");\n return singleLine(\n \"Spec \",\n formatPath(error.specPath),\n ` reaches a module that imports \\`@confect/server\\`: ${importers}. Spec modules are bundled into your client, so anything they import ships to the browser—move the server logic into a \\`*.impl.ts\\` module, or use \\`import type\\` if you only need the types.`,\n );\n};\n\nconst renderImplMissingSpecImportError = (\n error: ImplMissingSpecImportError,\n): string => {\n const stem = stemFromSpecPath(error.expectedSpecPath);\n return singleLine(\n \"Impl \",\n formatPath(error.implPath),\n ` does not import its sibling spec; add \\`import ${stem} from \"./${stem}.spec.js\"\\` and pass it to FunctionImpl.make/GroupImpl.make.`,\n );\n};\n\nconst renderImplMissingDefaultLayerError = (\n error: ImplMissingDefaultLayerError,\n): string =>\n singleLine(\n \"Impl \",\n formatPath(error.implPath),\n \" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(databaseSchema, groupSpec).pipe(Layer.provide(...))` and `export default` it.\",\n );\n\nconst renderImplNotFinalizedError = (error: ImplNotFinalizedError): string =>\n singleLine(\n \"Impl \",\n formatPath(error.implPath),\n \" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(databaseSchema, group).pipe(Layer.provide(...), GroupImpl.finalize)`).\",\n );\n\nconst renderImplMissingFunctionsError = (\n error: ImplMissingFunctionsError,\n): string => {\n const names = error.missingFunctionNames.join(\", \");\n return singleLine(\n \"Impl \",\n formatPath(error.implPath),\n ` does not implement every function declared by group \\`${error.groupPath}\\`; missing: ${names}. Add a \\`FunctionImpl.make\\` for each missing function and provide it to the group layer.`,\n );\n};\n\nconst renderImplMissingMiddlewareError = (\n error: ImplMissingMiddlewareError,\n): string => {\n const keys = error.missingMiddlewareKeys.join(\", \");\n return singleLine(\n \"Impl \",\n formatPath(error.implPath),\n ` does not implement every middleware attached to group \\`${error.groupPath}\\`; missing: ${keys}. Provide a \\`MiddlewareImpl.make\\` (or \\`makeByFunctionType\\`/\\`provides\\`) layer for each missing middleware to the group layer.`,\n );\n};\n\nconst renderInvalidTableDefaultExportError = (\n error: InvalidTableDefaultExportError,\n): string =>\n singleLine(\n \"Table \",\n formatPath(error.tablePath),\n \" must default-export a Table (e.g. `export default Table.make({ ... })`); convert any named export to a default export.\",\n );\n\nconst renderInvalidTableFilenameError = (\n error: InvalidTableFilenameError,\n): string =>\n singleLine(\n \"Table \",\n formatPath(error.tablePath),\n ` has an invalid filename: ${error.reason} Convex table names must start with a letter and contain only letters, numbers, and underscores; leading underscores are reserved for system tables.`,\n );\n\nconst renderDuplicateTableNameError = (\n error: DuplicateTableNameError,\n): string => {\n const conflicts = error.collisions\n .map(\n ({ tableName, tablePaths }) =>\n `\\`${tableName}\\` (${tablePaths.join(\", \")})`,\n )\n .join(\"; \");\n return singleLine(\n `Multiple files under \\`confect/tables/\\` resolve to the same table name. Table names are derived from filenames, so each must be unique across the directory (including subdirectories); rename or remove all but one. Conflicts: ${conflicts}.`,\n );\n};\n\nconst renderConflictingDocNameError = (\n error: ConflictingDocNameError,\n): string => {\n const conflicts = pipe(\n error.collisions,\n Array.map(\n ({ docName, tableNames }) =>\n `\\`${docName}\\` (${Array.join(tableNames, \", \")})`,\n ),\n Array.join(\"; \"),\n );\n return singleLine(\n `Multiple tables fold to the same generated document type name. Table names are converted to PascalCase (so \\`user_profiles\\` and \\`userProfiles\\` both become \\`UserProfilesDoc\\`); rename all but one of each colliding group. Conflicts: ${conflicts}.`,\n );\n};\n\nconst renderInvalidConvexConfigError = (\n error: InvalidConvexConfigError,\n): string =>\n singleLine(\n \"Convex config \",\n formatPath(error.configPath),\n ` could not be evaluated: ${error.reason}`,\n );\n\nconst renderLegacySchemaFileError = (error: LegacySchemaFileError): string =>\n singleLine(\n \"Found a legacy \",\n formatPath(error.schemaPath),\n \". Delete it: tables in `confect/tables/*.ts` are now the single source of truth, and the runtime schema is generated as `confect/_generated/schema.ts`.\",\n );\n\nconst renderParentChildNameCollisionError = (\n error: ParentChildNameCollisionError,\n): string =>\n singleLine(\n \"Spec \",\n formatPath(error.parentSpecPath),\n ` declares a ${error.collisionKind} \\`${error.collisionName}\\` whose name collides with the sibling subdirectory spec `,\n formatPath(error.childSpecPath),\n `. Rename one of them so the assembled spec has a unique key at this path.`,\n );\n\n/**\n * Render any {@link CodegenError} into a styled, ready-to-print string.\n * Single-error variants render to a one-line `✘`-prefixed message;\n * `BundleFailedError` (the only multi-error variant) renders to a header plus\n * an esbuild diagnostic block.\n */\nexport const renderCodegenError = (error: CodegenError): string => {\n if (isBuildError(error)) return renderBuildError(error);\n // The renderer pipeline below is at Effect's pipe arity limit, so the\n // fork's errors render here.\n if (error._tag === \"ComponentNodeGroupError\") {\n return singleLine(\n `Group \"${error.groupPath}\" in ${error.specPath} uses the Node runtime. Convex components do not support Node.js functions.`,\n );\n }\n if (error._tag === \"RequiredMiddlewareError\") {\n return singleLine(\n \"Required middleware is missing:\\n\",\n error.missing\n .map(\n ({ functionName, middlewareKey }) =>\n `${functionName} requires middleware \"${middlewareKey}\"`,\n )\n .join(\"\\n\"),\n );\n }\n if (error._tag === \"RemoveBusyError\") {\n return singleLine(\n \"Could not remove \",\n formatPath(error.path),\n ` after ${error.attempts} attempts because it is busy. Close other tools using it and try again.`,\n );\n }\n if (error._tag === \"InvalidDeclarationError\") {\n return singleLine(\n \"Declaration \",\n formatPath(error.declarationPath),\n ` is invalid: ${error.reason}`,\n );\n }\n if (error._tag === \"DeclarationKindMismatchError\") {\n return singleLine(\n \"Declaration \",\n formatPath(error.declarationPath),\n ` declares kind \"${error.declaredKind}\", but the target directory is kind \"${error.targetKind}\".`,\n );\n }\n if (error._tag === \"CallbackPrefixError\") {\n return singleLine(\n \"Callback contract \",\n `\"${error.contractId}\" in `,\n formatPath(error.declarationPath),\n ` must start with \"${error.componentName}/\" for component \"${error.componentName}\".`,\n );\n }\n if (error._tag === \"HandWrittenConvexFileError\") {\n return singleLine(\n \"Found a hand-written \",\n formatPath(error.convexPath),\n \". `confect codegen` writes it from \",\n formatPath(error.declarationPath),\n \" now; move its contents there and delete the file.\",\n );\n }\n if (error._tag === \"UnownedConvexEntrypointError\") {\n return singleLine(\n error.filePaths.map((file) => formatPath(file)).join(\", \"),\n error.filePaths.length === 1 ? \" was\" : \" were\",\n \" not written by confect codegen. Generated files only re-export the registry; put authored code outside convex/. If a file is stale generated output, delete it and run codegen again.\",\n );\n }\n return Match.value(error).pipe(\n Match.tag(\"SnapshotError\", ({ reason, relativePath, pathSegments }) =>\n singleLine(\n `Invalid generation metadata (${reason})`,\n relativePath === \"\" ? \"\" : ` for ${relativePath}`,\n pathSegments.length === 0 ? \".\" : ` at ${pathSegments.join(\"/\")}.`,\n ),\n ),\n Match.tag(\"MissingImplFileError\", renderMissingImplFileError),\n Match.tag(\"MissingSpecFileError\", renderMissingSpecFileError),\n Match.tag(\n \"SpecMissingDefaultGroupSpecError\",\n renderSpecMissingDefaultGroupSpecError,\n ),\n Match.tag(\"SpecImportsServerError\", renderSpecImportsServerError),\n Match.tag(\"InvalidMiddlewareAttachmentError\", (attachmentError) =>\n singleLine(\n \"Spec \",\n formatPath(attachmentError.specPath),\n `: ${attachmentError.message}`,\n ),\n ),\n Match.tag(\"ImplMissingSpecImportError\", renderImplMissingSpecImportError),\n Match.tag(\n \"ImplMissingDefaultLayerError\",\n renderImplMissingDefaultLayerError,\n ),\n Match.tag(\"ImplNotFinalizedError\", renderImplNotFinalizedError),\n Match.tag(\"ImplMissingFunctionsError\", renderImplMissingFunctionsError),\n Match.tag(\"ImplMissingMiddlewareError\", renderImplMissingMiddlewareError),\n Match.tag(\n \"ParentChildNameCollisionError\",\n renderParentChildNameCollisionError,\n ),\n Match.tag(\n \"InvalidTableDefaultExportError\",\n renderInvalidTableDefaultExportError,\n ),\n Match.tag(\"InvalidTableFilenameError\", renderInvalidTableFilenameError),\n Match.tag(\"DuplicateTableNameError\", renderDuplicateTableNameError),\n Match.tag(\"LegacySchemaFileError\", renderLegacySchemaFileError),\n Match.tag(\"ConflictingDocNameError\", renderConflictingDocNameError),\n Match.tag(\"InvalidConvexConfigError\", renderInvalidConvexConfigError),\n Match.exhaustive,\n );\n};\n\nexport const logCodegenError = (error: CodegenError) =>\n Console.error(renderCodegenError(error));\n\n// --- Effect combinators ---\n\n/**\n * Log any {@link CodegenError} thrown by `effect` and propagate the failure\n * unchanged so the caller's error channel is preserved.\n */\nexport const tapAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, E, R> =>\n effect.pipe(\n Effect.tapError((error) =>\n isCodegenError(error) ? logCodegenError(error) : Effect.void,\n ),\n );\n\n/**\n * Catch any {@link CodegenError} thrown by `effect`, log it, and resolve to\n * `Option.none()`. Success resolves to `Option.some(value)`.\n */\n// oxlint-disable effecttsgo/unsafe-effect-type-assertion -- catchIf removes the error variant selected by this refinement.\nexport const catchAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R> =>\n Effect.catchIf(Effect.map(effect, Option.some<A>), isCodegenError, (error) =>\n logCodegenError(error).pipe(Effect.as(Option.none<A>())),\n ) as Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R>;\n// oxlint-enable effecttsgo/unsafe-effect-type-assertion\n"],"mappings":"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"}
@@ -1,9 +1,12 @@
1
1
  import { fromGroupModulePath, modulePath } from "./GroupPath.mjs";
2
+ import { ProjectRoot } from "./ProjectRoot.mjs";
2
3
  import { logFileAdded, logFileModified, logFileRemoved } from "./log.mjs";
4
+ import { UnownedConvexEntrypointError } from "./CodegenError.mjs";
3
5
  import { ConvexDirectory } from "./ConvexDirectory.mjs";
4
6
  import { ConfectDirectory } from "./ConfectDirectory.mjs";
5
7
  import { CodeBlockWriter } from "./CodeBlockWriter.mjs";
6
- import { removePathIfExists, toModuleImportPath } from "./utils.mjs";
8
+ import { crons, declaredHttp, http } from "./templates.mjs";
9
+ import { removePathIfExists, toModuleImportPath, toPosixPath } from "./utils.mjs";
7
10
  import { GroupPaths } from "./GroupPaths.mjs";
8
11
  import { functionPaths, plan } from "./GenerationSnapshot.mjs";
9
12
  import * as Effect from "effect/Effect";
@@ -14,6 +17,80 @@ import { pipe } from "effect/Function";
14
17
  import * as HashSet from "effect/HashSet";
15
18
  import * as Match from "effect/Match";
16
19
  //#region src/FunctionModule.ts
20
+ const RESERVED_CONVEX_TS_FILE_NAMES = /* @__PURE__ */ new Set([
21
+ "schema.ts",
22
+ "http.ts",
23
+ "crons.ts",
24
+ "auth.config.ts",
25
+ "convex.config.ts"
26
+ ]);
27
+ const getEntrypoints = Effect.gen(function* () {
28
+ const fs = yield* FileSystem.FileSystem;
29
+ const path = yield* Path.Path;
30
+ const convex = yield* ConvexDirectory.get;
31
+ const files = yield* fs.readDirectory(convex, { recursive: true });
32
+ const components = files.filter((file) => path.basename(file) === "convex.config.ts" && path.dirname(file) !== ".").map((file) => path.dirname(file) + path.sep);
33
+ return files.filter((file) => {
34
+ const base = path.basename(file);
35
+ return !file.startsWith("_generated" + path.sep) && !components.some((component) => file.startsWith(component)) && /\.(?:js|mjs|cjs|ts|tsx|mts|cts|jsx)$/.test(base) && !base.startsWith(".") && !base.startsWith("#") && (base.match(/\./g)?.length ?? 0) === 1 && base !== "schema.ts" && base !== "schema.js" && !file.includes(" ");
36
+ });
37
+ });
38
+ const tokenize = (source, modulePath, path) => {
39
+ const token = /\s+|\/\/[^\r\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\\r\n])*"|'(?:\\.|[^'\\\r\n])*'|[$A-Z_a-z][$\w]*|[{}()[\].,:;=]/y;
40
+ const tokens = [];
41
+ while (token.lastIndex < source.length) {
42
+ const match = token.exec(source);
43
+ if (match === null) return void 0;
44
+ const value = match[0];
45
+ if (/^\s|^\//.test(value)) continue;
46
+ if (value.startsWith("\"") || value.startsWith("'")) {
47
+ const literal = value.slice(1, -1);
48
+ tokens.push(JSON.stringify(literal.startsWith(".") ? path.resolve(path.dirname(modulePath), literal.replace(/\.js$/, "")) : literal));
49
+ } else tokens.push(value);
50
+ }
51
+ return tokens;
52
+ };
53
+ const matchesShape = (actual, expected) => {
54
+ let index = 0;
55
+ for (const token of expected) {
56
+ if (token === ";" && actual[index] !== ";") continue;
57
+ if (actual[index] === "," && (token === "}" || token === ")")) index++;
58
+ if (actual[index++] !== token) return false;
59
+ }
60
+ return index === actual.length;
61
+ };
62
+ const assertOwnedEntrypoints = Effect.gen(function* () {
63
+ const fs = yield* FileSystem.FileSystem;
64
+ const path = yield* Path.Path;
65
+ const convex = yield* ConvexDirectory.get;
66
+ const confect = yield* ConfectDirectory.get;
67
+ const projectRoot = yield* ProjectRoot.get;
68
+ const importFromConvex = (file) => toModuleImportPath(path.relative(convex, path.join(confect, file)));
69
+ const optional = /* @__PURE__ */ new Map([["http.ts", [yield* http({ httpImportPath: yield* importFromConvex("http.ts") }), yield* declaredHttp({
70
+ schemaImportPath: yield* importFromConvex("_generated/schema.ts"),
71
+ httpImportPath: yield* importFromConvex("http.ts")
72
+ })]], ["crons.ts", [yield* crons({ cronsImportPath: yield* importFromConvex("crons.ts") })]]]);
73
+ const refused = [];
74
+ for (const relative of yield* getEntrypoints) {
75
+ const absolute = path.join(convex, relative);
76
+ const tokens = tokenize(yield* fs.readFileString(absolute), absolute, path);
77
+ if (tokens !== void 0) {
78
+ if (optional.get(relative)?.some((template) => matchesShape(tokens, tokenize(template, absolute, path)))) continue;
79
+ if (path.extname(relative) === ".ts") {
80
+ const names = tokens.flatMap((token, index) => token === "export" && tokens[index + 1] === "const" ? [tokens[index + 2]] : []);
81
+ const group = yield* fromGroupModulePath(relative);
82
+ const template = yield* render({
83
+ functionNames: names,
84
+ registeredFunctionsImportPath: yield* registeredFunctionsImportPathForGroup(group, absolute),
85
+ useNode: tokens[0] === "\"use node\""
86
+ });
87
+ if (names.length > 0 && new Set(names).size === names.length && matchesShape(tokens, tokenize(template, absolute, path))) continue;
88
+ }
89
+ }
90
+ refused.push(toPosixPath(path, path.relative(projectRoot, absolute)));
91
+ }
92
+ if (refused.length > 0) return yield* new UnownedConvexEntrypointError({ filePaths: refused.sort() });
93
+ });
17
94
  const render = ({ functionNames, registeredFunctionsImportPath, useNode = false }) => renderEffect({
18
95
  functionNames,
19
96
  registeredFunctionsImportPath,
@@ -92,18 +169,9 @@ const applyFunctionPlan = Effect.fnUntraced(function* (plan) {
92
169
  yield* writeGroups(plan.changed);
93
170
  });
94
171
  const getGroupPathsFromFs = Effect.gen(function* () {
95
- const fs = yield* FileSystem.FileSystem;
96
172
  const path = yield* Path.Path;
97
- const convexDirectory = yield* ConvexDirectory.get;
98
- const RESERVED_CONVEX_TS_FILE_NAMES = /* @__PURE__ */ new Set([
99
- "schema.ts",
100
- "http.ts",
101
- "crons.ts",
102
- "auth.config.ts",
103
- "convex.config.ts"
104
- ]);
105
- const allConvexPaths = yield* fs.readDirectory(convexDirectory, { recursive: true });
106
- const groupPathArray = yield* pipe(allConvexPaths, Array.filter((convexPath) => path.extname(convexPath) === ".ts" && !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) && path.basename(path.dirname(convexPath)) !== "_generated"), Effect.forEach((groupModulePath) => fromGroupModulePath(groupModulePath)));
173
+ const allConvexPaths = yield* getEntrypoints;
174
+ const groupPathArray = yield* pipe(allConvexPaths, Array.filter((convexPath) => path.extname(convexPath) === ".ts" && !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath))), Effect.forEach((groupModulePath) => fromGroupModulePath(groupModulePath)));
107
175
  return GroupPaths.make(HashSet.fromIterable(groupPathArray));
108
176
  });
109
177
  const removeGroups = Effect.fnUntraced(function* (groupPaths) {
@@ -132,6 +200,6 @@ const writeGroups = (groups) => Effect.forEach(groups, Effect.fnUntraced(functio
132
200
  yield* Match.value(change).pipe(Match.when("Added", () => logFileAdded(modulePath$1)), Match.when("Modified", () => logFileModified(modulePath$1)), Match.when("Unchanged", () => Effect.void), Match.exhaustive);
133
201
  }));
134
202
  //#endregion
135
- export { applyFunctionPlan, generateFunctions, generateGroupModule, registeredFunctionsImportPathForGroup, removeGroups, render, writeGroups };
203
+ export { applyFunctionPlan, assertOwnedEntrypoints, generateFunctions, generateGroupModule, registeredFunctionsImportPathForGroup, removeGroups, render, writeGroups };
136
204
 
137
205
  //# sourceMappingURL=FunctionModule.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionModule.mjs","names":["GroupPath.modulePath","modulePath","GenerationSnapshot.plan","GenerationSnapshot.functionPaths","GroupPath.fromGroupModulePath"],"sources":["../src/FunctionModule.ts"],"sourcesContent":["import * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as GenerationSnapshot from \"./GenerationSnapshot.js\";\nimport * as GroupPath from \"./GroupPath.js\";\nimport * as GroupPaths from \"./GroupPaths.js\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter.js\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ConvexDirectory } from \"./ConvexDirectory.js\";\nimport { removePathIfExists, toModuleImportPath } from \"./utils.js\";\n\nexport const render = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof renderEffect>[0]) =>\n renderEffect({ functionNames, registeredFunctionsImportPath, useNode });\n\nconst renderEffect = Effect.fnUntraced(function* ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (name) =>\n cbw.writeLine(`export const ${name} = registeredFunctions.${name};`),\n );\n\n return yield* cbw.toString();\n});\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof generateGroupModuleEffect>[0]) =>\n generateGroupModuleEffect({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\nconst generateGroupModuleEffect = Effect.fnUntraced(function* ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const functionsContentsString = yield* render({\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n});\n\n/**\n * Compute the module import specifier (relative to `modulePath`) for a group's\n * registry file under `confect/_generated/registeredFunctions/`. The registry\n * path mirrors the group's path one-to-one (see\n * `registeredFunctionsRelativePath` in `LeafModule.ts`) for both Convex and\n * Node groups.\n */\nexport const registeredFunctionsImportPathForGroup = Effect.fnUntraced(\n function* (groupPath: GroupPath.GroupPath, modulePath: string) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const registeredFunctionsPath =\n path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n ...groupPath.pathSegments,\n ) + \".ts\";\n\n return yield* toModuleImportPath(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n },\n);\n\nconst logGroupPaths = Effect.fnUntraced(function* <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n): Effect.fn.Return<void, never, R | Path.Path | ConvexDirectory> {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(\n groupPaths,\n Effect.fnUntraced(function* (gp: GroupPath.GroupPath) {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n});\n\nexport const generateFunctions = Effect.fnUntraced(function* (\n snapshot: GenerationSnapshot.GenerationSnapshot,\n) {\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n yield* applyFunctionPlan(GenerationSnapshot.plan(snapshot, groupPathsFromFs));\n return GenerationSnapshot.functionPaths(snapshot);\n});\n\nexport const applyFunctionPlan = Effect.fnUntraced(function* (\n plan: GenerationSnapshot.ModulePlan,\n) {\n const removed = GroupPaths.GroupPaths.make(\n HashSet.fromIterable(plan.removed),\n );\n yield* removeGroups(removed);\n yield* logGroupPaths(removed, logFileRemoved);\n yield* writeGroups(plan.changed);\n});\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n ]);\n\n const allConvexPaths = yield* fs.readDirectory(convexDirectory, {\n recursive: true,\n });\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) &&\n path.basename(path.dirname(convexPath)) !== \"_generated\",\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return GroupPaths.GroupPaths.make(HashSet.fromIterable(groupPathArray));\n});\n\nexport const removeGroups = Effect.fnUntraced(function* (\n groupPaths: GroupPaths.GroupPaths,\n) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* removePathIfExists(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n});\n\nexport const writeGroups = (\n groups: ReadonlyArray<GenerationSnapshot.GroupSummary>,\n) =>\n Effect.forEach(\n groups,\n Effect.fnUntraced(function* (group: GenerationSnapshot.GroupSummary) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const relativeModulePath = yield* GroupPath.modulePath(group.path);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n const registeredFunctionsImportPath =\n yield* registeredFunctionsImportPathForGroup(group.path, modulePath);\n const change = yield* generateGroupModule({\n groupPath: group.path,\n functionNames: group.functionNames,\n registeredFunctionsImportPath,\n useNode: group.runtime === \"Node\",\n });\n yield* Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(modulePath)),\n Match.when(\"Modified\", () => logFileModified(modulePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n );\n }),\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"FunctionModule.mjs","names":["templates.http","templates.declaredHttp","templates.crons","GroupPath.fromGroupModulePath","GroupPath.modulePath","modulePath","GenerationSnapshot.plan","GenerationSnapshot.functionPaths"],"sources":["../src/FunctionModule.ts"],"sourcesContent":["import * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport { UnownedConvexEntrypointError } from \"./CodegenError.js\";\nimport * as templates from \"./templates.js\";\nimport * as GenerationSnapshot from \"./GenerationSnapshot.js\";\nimport * as GroupPath from \"./GroupPath.js\";\nimport * as GroupPaths from \"./GroupPaths.js\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter.js\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ConvexDirectory } from \"./ConvexDirectory.js\";\nimport {\n removePathIfExists,\n toModuleImportPath,\n toPosixPath,\n} from \"./utils.js\";\nimport { ProjectRoot } from \"./ProjectRoot.js\";\n\nconst RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n]);\n\n// Keep ownership and removal aligned with Convex's bundler entryPoints filter.\nconst getEntrypoints = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convex = yield* ConvexDirectory.get;\n const files = yield* fs.readDirectory(convex, { recursive: true });\n const components = files\n .filter(\n (file) =>\n path.basename(file) === \"convex.config.ts\" &&\n path.dirname(file) !== \".\",\n )\n .map((file) => path.dirname(file) + path.sep);\n return files.filter((file) => {\n const base = path.basename(file);\n return (\n !file.startsWith(\"_generated\" + path.sep) &&\n !components.some((component) => file.startsWith(component)) &&\n /\\.(?:js|mjs|cjs|ts|tsx|mts|cts|jsx)$/.test(base) &&\n !base.startsWith(\".\") &&\n !base.startsWith(\"#\") &&\n (base.match(/\\./g)?.length ?? 0) === 1 &&\n base !== \"schema.ts\" &&\n base !== \"schema.js\" &&\n !file.includes(\" \")\n );\n });\n});\n\nconst tokenize = (\n source: string,\n modulePath: string,\n path: Path.Path,\n): string[] | undefined => {\n const token =\n /\\s+|\\/\\/[^\\r\\n]*|\\/\\*[\\s\\S]*?\\*\\/|\"(?:\\\\.|[^\"\\\\\\r\\n])*\"|'(?:\\\\.|[^'\\\\\\r\\n])*'|[$A-Z_a-z][$\\w]*|[{}()[\\].,:;=]/y;\n const tokens: string[] = [];\n while (token.lastIndex < source.length) {\n const match = token.exec(source);\n if (match === null) return undefined;\n const value = match[0];\n if (/^\\s|^\\//.test(value)) continue;\n if (value.startsWith('\"') || value.startsWith(\"'\")) {\n const literal = value.slice(1, -1);\n tokens.push(\n JSON.stringify(\n literal.startsWith(\".\")\n ? path.resolve(\n path.dirname(modulePath),\n literal.replace(/\\.js$/, \"\"),\n )\n : literal,\n ),\n );\n } else tokens.push(value);\n }\n return tokens;\n};\n\nconst matchesShape = (\n actual: readonly string[],\n expected: readonly string[],\n) => {\n let index = 0;\n for (const token of expected) {\n if (token === \";\" && actual[index] !== \";\") continue;\n if (actual[index] === \",\" && (token === \"}\" || token === \")\")) index++;\n if (actual[index++] !== token) return false;\n }\n return index === actual.length;\n};\n\nexport const assertOwnedEntrypoints = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convex = yield* ConvexDirectory.get;\n const confect = yield* ConfectDirectory.get;\n const projectRoot = yield* ProjectRoot.get;\n const importFromConvex = (file: string) =>\n toModuleImportPath(path.relative(convex, path.join(confect, file)));\n const optional = new Map([\n [\n \"http.ts\",\n [\n yield* templates.http({\n httpImportPath: yield* importFromConvex(\"http.ts\"),\n }),\n yield* templates.declaredHttp({\n schemaImportPath: yield* importFromConvex(\"_generated/schema.ts\"),\n httpImportPath: yield* importFromConvex(\"http.ts\"),\n }),\n ],\n ],\n [\n \"crons.ts\",\n [\n yield* templates.crons({\n cronsImportPath: yield* importFromConvex(\"crons.ts\"),\n }),\n ],\n ],\n ]);\n const refused: string[] = [];\n for (const relative of yield* getEntrypoints) {\n const absolute = path.join(convex, relative);\n const tokens = tokenize(yield* fs.readFileString(absolute), absolute, path);\n if (tokens !== undefined) {\n if (\n optional\n .get(relative)\n ?.some((template) =>\n matchesShape(tokens, tokenize(template, absolute, path)!),\n )\n )\n continue;\n if (path.extname(relative) === \".ts\") {\n const names = tokens.flatMap((token, index) =>\n token === \"export\" && tokens[index + 1] === \"const\"\n ? [tokens[index + 2]!]\n : [],\n );\n const group = yield* GroupPath.fromGroupModulePath(relative);\n const template = yield* render({\n functionNames: names,\n registeredFunctionsImportPath:\n yield* registeredFunctionsImportPathForGroup(group, absolute),\n useNode: tokens[0] === '\"use node\"',\n });\n if (\n names.length > 0 &&\n new Set(names).size === names.length &&\n matchesShape(tokens, tokenize(template, absolute, path)!)\n )\n continue;\n }\n }\n refused.push(toPosixPath(path, path.relative(projectRoot, absolute)));\n }\n if (refused.length > 0)\n return yield* new UnownedConvexEntrypointError({\n filePaths: refused.sort(),\n });\n});\n\nexport const render = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof renderEffect>[0]) =>\n renderEffect({ functionNames, registeredFunctionsImportPath, useNode });\n\nconst renderEffect = Effect.fnUntraced(function* ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (name) =>\n cbw.writeLine(`export const ${name} = registeredFunctions.${name};`),\n );\n\n return yield* cbw.toString();\n});\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof generateGroupModuleEffect>[0]) =>\n generateGroupModuleEffect({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\nconst generateGroupModuleEffect = Effect.fnUntraced(function* ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const functionsContentsString = yield* render({\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n});\n\n/**\n * Compute the module import specifier (relative to `modulePath`) for a group's\n * registry file under `confect/_generated/registeredFunctions/`. The registry\n * path mirrors the group's path one-to-one (see\n * `registeredFunctionsRelativePath` in `LeafModule.ts`) for both Convex and\n * Node groups.\n */\nexport const registeredFunctionsImportPathForGroup = Effect.fnUntraced(\n function* (groupPath: GroupPath.GroupPath, modulePath: string) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const registeredFunctionsPath =\n path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n ...groupPath.pathSegments,\n ) + \".ts\";\n\n return yield* toModuleImportPath(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n },\n);\n\nconst logGroupPaths = Effect.fnUntraced(function* <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n): Effect.fn.Return<void, never, R | Path.Path | ConvexDirectory> {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(\n groupPaths,\n Effect.fnUntraced(function* (gp: GroupPath.GroupPath) {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n});\n\nexport const generateFunctions = Effect.fnUntraced(function* (\n snapshot: GenerationSnapshot.GenerationSnapshot,\n) {\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n yield* applyFunctionPlan(GenerationSnapshot.plan(snapshot, groupPathsFromFs));\n return GenerationSnapshot.functionPaths(snapshot);\n});\n\nexport const applyFunctionPlan = Effect.fnUntraced(function* (\n plan: GenerationSnapshot.ModulePlan,\n) {\n const removed = GroupPaths.GroupPaths.make(\n HashSet.fromIterable(plan.removed),\n );\n yield* removeGroups(removed);\n yield* logGroupPaths(removed, logFileRemoved);\n yield* writeGroups(plan.changed);\n});\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const path = yield* Path.Path;\n const allConvexPaths = yield* getEntrypoints;\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)),\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return GroupPaths.GroupPaths.make(HashSet.fromIterable(groupPathArray));\n});\n\nexport const removeGroups = Effect.fnUntraced(function* (\n groupPaths: GroupPaths.GroupPaths,\n) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* removePathIfExists(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n});\n\nexport const writeGroups = (\n groups: ReadonlyArray<GenerationSnapshot.GroupSummary>,\n) =>\n Effect.forEach(\n groups,\n Effect.fnUntraced(function* (group: GenerationSnapshot.GroupSummary) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const relativeModulePath = yield* GroupPath.modulePath(group.path);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n const registeredFunctionsImportPath =\n yield* registeredFunctionsImportPathForGroup(group.path, modulePath);\n const change = yield* generateGroupModule({\n groupPath: group.path,\n functionNames: group.functionNames,\n registeredFunctionsImportPath,\n useNode: group.runtime === \"Node\",\n });\n yield* Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(modulePath)),\n Match.when(\"Modified\", () => logFileModified(modulePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n );\n }),\n );\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { fromBundlerError } from "./BuildError.mjs";
2
2
  import { bundle, directlyImports, importersOfPackage, withBatch } from "./Bundler.mjs";
3
- import { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingMiddlewareError, ImplMissingSpecImportError, ImplNotFinalizedError, InvalidMiddlewareAttachmentError, MissingImplFileError, MissingSpecFileError, SpecImportsServerError, SpecMissingDefaultGroupSpecError } from "./CodegenError.mjs";
3
+ import { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingMiddlewareError, ImplMissingSpecImportError, ImplNotFinalizedError, InvalidMiddlewareAttachmentError, MissingImplFileError, MissingSpecFileError, RequiredMiddlewareError, SpecImportsServerError, SpecMissingDefaultGroupSpecError } from "./CodegenError.mjs";
4
4
  import { ConfectDirectory } from "./ConfectDirectory.mjs";
5
5
  import { removePathExtension, toPosixPath } from "./utils.mjs";
6
6
  import { ImplModulePath } from "./ImplModulePath.mjs";
@@ -16,7 +16,7 @@ import * as Schema from "effect/Schema";
16
16
  import * as String from "effect/String";
17
17
  import * as Layer from "effect/Layer";
18
18
  import * as Brand from "effect/Brand";
19
- import { Registry } from "@confect/server";
19
+ import { Registry, RegistryItems } from "@confect/server";
20
20
  import * as GroupImpl from "@confect/server/GroupImpl";
21
21
  //#region src/LeafModule.ts
22
22
  const LoadedLeafModule = Brand.nominal();
@@ -156,22 +156,23 @@ const loadSpec = Effect.fn("LeafModule.loadSpec")(function* (leaf) {
156
156
  const findFinalizedGroupImpl = (context) => Array.findFirst(context.mapUnsafe.values(), GroupImpl.isFinalizedGroupImpl);
157
157
  /**
158
158
  * Build the impl layer with a fresh `Registry` so each validation is isolated
159
- * from prior validations' `FunctionImpl.make` writes. The CLI no longer reads
160
- * the registry directly—`GroupImpl.finalize` snapshots the registered function
161
- * names onto the produced `Finalized` `GroupImpl` service value—but a fresh
162
- * `Ref` is still required because the default `Context.Reference` is cached
163
- * globally and would otherwise accumulate items across impls.
159
+ * from prior validations' `FunctionImpl.make` writes. Retain its items to check
160
+ * required middleware against actual function attachments.
164
161
  */
165
162
  const buildImplLayer = Effect.fnUntraced(function* (implLayer) {
166
163
  const registry = Ref.makeUnsafe({});
167
- return yield* Layer.build(implLayer).pipe(Effect.provideService(Registry.Registry, registry));
164
+ return {
165
+ context: yield* Layer.build(implLayer).pipe(Effect.provideService(Registry.Registry, registry)),
166
+ items: yield* Ref.get(registry)
167
+ };
168
168
  }, Effect.scoped);
169
169
  /**
170
170
  * Validate that the leaf's sibling impl file imports the spec, default-exports
171
171
  * a finalized `GroupImpl` layer, and provides a `FunctionImpl` for every
172
- * function declared by the spec.
172
+ * function declared by the spec. Return uncovered middleware requirements for
173
+ * the caller to report across groups.
173
174
  */
174
- const validateImpl = Effect.fn("LeafModule.validateImpl")(function* (leaf) {
175
+ const validateImpl = Effect.fn("LeafModule.validateImpl")(function* (leaf, required = []) {
175
176
  const implRelativePath = yield* implPathForSpec(leaf.relativePath);
176
177
  const implAbsolutePath = yield* absoluteModulePath(implRelativePath);
177
178
  const specAbsolutePath = yield* absoluteModulePath(leaf.relativePath);
@@ -183,7 +184,7 @@ const validateImpl = Effect.fn("LeafModule.validateImpl")(function* (leaf) {
183
184
  if (!Layer.isLayer(bundled.module.default)) return yield* new ImplMissingDefaultLayerError({ implPath: implRelativePath });
184
185
  const groupSpec = leaf.spec;
185
186
  const expectedFunctionNames = Object.keys(groupSpec.functions);
186
- const context = yield* buildImplLayer(bundled.module.default);
187
+ const { context, items } = yield* buildImplLayer(bundled.module.default);
187
188
  const finalizedGroupImpl = yield* Option.match(findFinalizedGroupImpl(context), {
188
189
  onNone: () => new ImplNotFinalizedError({ implPath: implRelativePath }),
189
190
  onSome: Effect.succeed
@@ -203,6 +204,7 @@ const validateImpl = Effect.fn("LeafModule.validateImpl")(function* (leaf) {
203
204
  groupPath: leaf.groupPathDot,
204
205
  missingMiddlewareKeys: missingMiddleware
205
206
  });
207
+ return RegistryItems.missingRequired(items, required, leaf.groupPathDot);
206
208
  });
207
209
  const withImplFiles = Effect.fnUntraced(function* (relativePaths, use) {
208
210
  const fs = yield* FileSystem.FileSystem;
@@ -227,14 +229,12 @@ const withImplFiles = Effect.fnUntraced(function* (relativePaths, use) {
227
229
  }));
228
230
  });
229
231
  const validateImplFiles = Effect.fn("LeafModule.validateImplFiles")((relativePaths) => withImplFiles(relativePaths, validateAllImpls));
230
- const validateAllImpls = Effect.fnUntraced(function* (leaves) {
232
+ const validateAllImpls = Effect.fnUntraced(function* (leaves, required = []) {
231
233
  const path = yield* Path.Path;
232
234
  const confectDirectory = yield* ConfectDirectory.get;
233
235
  const implementationPaths = yield* Effect.forEach(leaves, ({ relativePath }) => implPathForSpec(relativePath).pipe(Effect.map((implPath) => path.resolve(confectDirectory, implPath))));
234
- yield* withBatch(implementationPaths, Effect.forEach(leaves, validateImpl, {
235
- concurrency: VALIDATION_CONCURRENCY,
236
- discard: true
237
- }));
236
+ const missing = (yield* withBatch(implementationPaths, Effect.forEach(leaves, (leaf) => validateImpl(leaf, required), { concurrency: VALIDATION_CONCURRENCY }))).flat().sort((left, right) => left.functionName.localeCompare(right.functionName));
237
+ if (missing.length > 0) return yield* new RequiredMiddlewareError({ missing });
238
238
  });
239
239
  const loadAll = Effect.gen(function* () {
240
240
  const fs = yield* FileSystem.FileSystem;
@@ -1 +1 @@
1
- {"version":3,"file":"LeafModule.mjs","names":["Bundler.importersOfPackage","Bundler.bundle","Bundler.directlyImports","Bundler.withBatch"],"sources":["../src/LeafModule.ts"],"sourcesContent":["import { GroupSpec, MiddlewareAttachment } from \"@confect/core\";\nimport { Registry, type RegistryItems } from \"@confect/server\";\nimport * as GroupImpl from \"@confect/server/GroupImpl\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport type { Context } from \"effect\";\nimport * as Array from \"effect/Array\";\nimport * as Brand from \"effect/Brand\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\nimport * as String from \"effect/String\";\nimport { fromBundlerError } from \"./BuildError.js\";\nimport * as Bundler from \"./Bundler.js\";\nimport {\n MissingImplFileError,\n MissingSpecFileError,\n ImplMissingDefaultLayerError,\n ImplMissingFunctionsError,\n ImplMissingMiddlewareError,\n ImplMissingSpecImportError,\n ImplNotFinalizedError,\n InvalidMiddlewareAttachmentError,\n SpecImportsServerError,\n SpecMissingDefaultGroupSpecError,\n} from \"./CodegenError.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ImplModulePath } from \"./ImplModulePath.js\";\nimport { removePathExtension, toPosixPath } from \"./utils.js\";\n\nexport interface LeafModule {\n readonly relativePath: string;\n readonly pathSegments: readonly [string, ...string[]];\n readonly groupPathDot: string;\n readonly exportName: string;\n readonly specImportPath: string;\n}\n\nexport type LoadedLeafModule = LeafModule & {\n readonly spec: GroupSpec.AnyWithProps;\n} & Brand.Brand<\"@confect/cli/LoadedLeafModule\">;\n\nconst LoadedLeafModule = Brand.nominal<LoadedLeafModule>();\n\nconst VALIDATION_CONCURRENCY = 4;\n\nexport const SPEC_SUFFIX = \".spec.ts\";\nexport const IMPL_SUFFIX = \".impl.ts\";\n\nconst swapModuleSuffix = Effect.fnUntraced(function* (\n relativePath: string,\n fromSuffix: string,\n toSuffix: string,\n) {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n if (ext !== \".ts\" || !name.endsWith(fromSuffix.slice(0, -\".ts\".length))) {\n return relativePath;\n }\n\n const stem = name.slice(0, -fromSuffix.slice(0, -\".ts\".length).length);\n const nextName = `${stem}${toSuffix.slice(0, -\".ts\".length)}`;\n return dir.length > 0\n ? path.join(dir, `${nextName}${ext}`)\n : `${nextName}${ext}`;\n});\n\nexport const isLeafSpecPath = (relativePath: string) =>\n relativePath.endsWith(SPEC_SUFFIX);\n\nexport const exportNameFromModulePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { name, ext } = path.parse(relativePath);\n if (ext !== \".ts\") {\n return name;\n }\n return name.endsWith(\".spec\") ? name.slice(0, -\".spec\".length) : name;\n});\n\nexport const groupPathFromRelativeModulePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n const stem =\n ext === \".ts\" && name.endsWith(\".spec\")\n ? name.slice(0, -\".spec\".length)\n : name;\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n const pathSegments = Array.append(dirSegments, stem) as [string, ...string[]];\n return {\n pathSegments,\n groupPathDot: Array.join(pathSegments, \".\"),\n };\n});\n\nexport const specImportPathFromGenerated = Effect.fnUntraced(function* (\n specRelativePath: string,\n) {\n const path = yield* Path.Path;\n const withoutExt = toPosixPath(\n path,\n yield* removePathExtension(specRelativePath),\n );\n return `../${withoutExt}.js`;\n});\n\nexport const specPathForImpl = (implRelativePath: string) =>\n swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);\n\nexport const implPathForSpec = (specRelativePath: string) =>\n swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);\n\nexport const registeredFunctionsRelativePath = Effect.fnUntraced(function* (\n leaf: LeafModule,\n) {\n const path = yield* Path.Path;\n return path.join(\"registeredFunctions\", ...leaf.pathSegments) + \".ts\";\n});\n\nexport const discoverLeafSpecFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = HashSet.make(\"_generated\", \"tables\", \"middleware\");\n const excludedFiles = HashSet.make(\"nodeSpec.ts\", \"spec.ts\");\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafSpecPath(relativePath)) {\n return false;\n }\n\n if (HashSet.has(excludedFiles, relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) =>\n HashSet.has(excludedDirs, segment),\n );\n });\n});\n\nexport const discoverLeafImplFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = HashSet.make(\"_generated\", \"tables\", \"middleware\");\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(\n Array.filterMap(allPaths, (relativePath) =>\n Schema.decodeResult(ImplModulePath)(relativePath),\n ),\n (relativePath) => {\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) =>\n HashSet.has(excludedDirs, segment),\n );\n },\n );\n});\n\nexport const toLeafModule = Effect.fnUntraced(function* (\n specRelativePath: string,\n) {\n const exportName = yield* exportNameFromModulePath(specRelativePath);\n const { pathSegments, groupPathDot } =\n yield* groupPathFromRelativeModulePath(specRelativePath);\n const specImportPath = yield* specImportPathFromGenerated(specRelativePath);\n\n return {\n relativePath: specRelativePath,\n pathSegments,\n groupPathDot,\n exportName,\n specImportPath,\n } satisfies LeafModule;\n});\n\nconst absoluteModulePath = Effect.fnUntraced(function* (relativePath: string) {\n const confectDirectory = yield* ConfectDirectory.get;\n const path = yield* Path.Path;\n return path.resolve(confectDirectory, relativePath);\n});\n\n/**\n * Every `*.spec.ts` is reachable from `_generated/spec.ts`, which the client\n * imports through `_generated/refs.ts`—so a spec's whole import graph is\n * bundled into the browser whether or not the client calls those functions.\n * Server logic co-located with a declaration therefore ships to users,\n * silently.\n *\n * `@confect/server` is a sound proxy for \"server logic lives here\": an\n * implementation can't be written without `FunctionImpl`/`MiddlewareImpl`, both\n * of which live there. Table `Doc`/`Fields` schemas live in `@confect/core`, so\n * the documented `notes.Doc` pattern in a spec must not reach `@confect/server`\n * even through `tables/` or `_generated/`. The check runs over the spec\n * bundle's transitive inputs rather than the spec module alone, so it also\n * covers middleware declarations under `confect/middleware/` (which codegen\n * otherwise never visits) and any shared helper a spec pulls in—while only ever\n * flagging modules that genuinely reach the client.\n */\nconst validateClientSafety = Effect.fnUntraced(function* (\n leaf: LeafModule,\n bundled: Bundler.Bundled,\n) {\n const path = yield* Path.Path;\n const confectDirectory = path.resolve(yield* ConfectDirectory.get);\n\n const isCheckedUserModule = (absolutePath: string) => {\n const relative = path.relative(confectDirectory, absolutePath);\n return !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n };\n\n const importers = Bundler.importersOfPackage(\n bundled,\n \"@confect/server\",\n isCheckedUserModule,\n );\n\n if (importers.length > 0) {\n return yield* new SpecImportsServerError({\n specPath: leaf.relativePath,\n importerPaths: Array.map(importers, (absolutePath) =>\n toPosixPath(path, path.relative(confectDirectory, absolutePath)),\n ),\n });\n }\n});\n\n/**\n * Validate that the leaf's spec file default-exports a `GroupSpec`, and that\n * nothing it reaches drags server code into the client (see\n * {@link validateClientSafety}). Returns the leaf paired with its validated\n * spec, so subsequent operations reuse that association without re-bundling.\n * The runtime is declared by the spec, not its file location.\n */\nexport const loadSpec = Effect.fn(\"LeafModule.loadSpec\")(function* (\n leaf: LeafModule,\n) {\n const absolutePath = yield* absoluteModulePath(leaf.relativePath);\n const bundled = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n\n const groupSpec = bundled.module.default;\n\n if (!GroupSpec.isGroupSpec(groupSpec)) {\n return yield* new SpecMissingDefaultGroupSpecError({\n specPath: leaf.relativePath,\n });\n }\n\n yield* validateClientSafety(leaf, bundled);\n\n yield* Effect.fromResult(GroupSpec.validateMiddleware(groupSpec)).pipe(\n Effect.mapError(\n (error) =>\n new InvalidMiddlewareAttachmentError({\n specPath: leaf.relativePath,\n message: MiddlewareAttachment.formatValidationError(error),\n }),\n ),\n );\n\n return LoadedLeafModule({\n ...leaf,\n spec: groupSpec,\n });\n});\n\n/**\n * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The\n * lookup is value-shaped (via `GroupImpl.isFinalizedGroupImpl`) so we don't\n * need to know the group's path up front to construct a typed tag for it.\n */\nconst findFinalizedGroupImpl = <S>(\n context: Context.Context<S>,\n): Option.Option<GroupImpl.AnyFinalized> =>\n Array.findFirst(context.mapUnsafe.values(), GroupImpl.isFinalizedGroupImpl);\n\n/**\n * Build the impl layer with a fresh `Registry` so each validation is isolated\n * from prior validations' `FunctionImpl.make` writes. The CLI no longer reads\n * the registry directly—`GroupImpl.finalize` snapshots the registered function\n * names onto the produced `Finalized` `GroupImpl` service value—but a fresh\n * `Ref` is still required because the default `Context.Reference` is cached\n * globally and would otherwise accumulate items across impls.\n */\nconst buildImplLayer = Effect.fnUntraced(function* (\n implLayer: Layer.Layer<unknown>,\n) {\n const registry = Ref.makeUnsafe<RegistryItems.RegistryItems>({});\n return yield* Layer.build(\n implLayer as Layer.Layer<unknown, never, never>,\n ).pipe(Effect.provideService(Registry.Registry, registry));\n}, Effect.scoped);\n\n/**\n * Validate that the leaf's sibling impl file imports the spec, default-exports\n * a finalized `GroupImpl` layer, and provides a `FunctionImpl` for every\n * function declared by the spec.\n */\nexport const validateImpl = Effect.fn(\"LeafModule.validateImpl\")(function* (\n leaf: LoadedLeafModule,\n) {\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const implAbsolutePath = yield* absoluteModulePath(implRelativePath);\n const specAbsolutePath = yield* absoluteModulePath(leaf.relativePath);\n\n const bundled = yield* Bundler.bundle(implAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(implRelativePath, error)),\n );\n\n if (\n !(yield* Bundler.directlyImports(\n bundled,\n implAbsolutePath,\n specAbsolutePath,\n ))\n ) {\n return yield* new ImplMissingSpecImportError({\n implPath: implRelativePath,\n expectedSpecPath: leaf.relativePath,\n });\n }\n\n if (!Layer.isLayer(bundled.module.default)) {\n return yield* new ImplMissingDefaultLayerError({\n implPath: implRelativePath,\n });\n }\n\n const groupSpec = leaf.spec;\n const expectedFunctionNames = Object.keys(groupSpec.functions);\n\n const context = yield* buildImplLayer(\n bundled.module.default as Layer.Layer<unknown>,\n );\n const finalizedGroupImpl = yield* Option.match(\n findFinalizedGroupImpl(context),\n {\n onNone: () => new ImplNotFinalizedError({ implPath: implRelativePath }),\n onSome: Effect.succeed,\n },\n );\n\n const registeredSet = HashSet.fromIterable(\n finalizedGroupImpl.registeredFunctionNames,\n );\n const missing = expectedFunctionNames.filter(\n (name) => !HashSet.has(registeredSet, name),\n );\n\n if (missing.length > 0) {\n return yield* new ImplMissingFunctionsError({\n implPath: implRelativePath,\n groupPath: leaf.groupPathDot,\n missingFunctionNames: missing,\n });\n }\n\n const expectedMiddlewareKeys = Array.dedupe([\n ...(groupSpec.middlewareSpecs ?? []).map(\n (middlewareSpec) => middlewareSpec.key,\n ),\n ...Object.values(groupSpec.functions).flatMap((function_) =>\n (function_.middlewareSpecs ?? []).map(\n (middlewareSpec) => middlewareSpec.key,\n ),\n ),\n ]);\n const registeredMiddlewareKeys = HashSet.fromIterable(\n finalizedGroupImpl.registeredMiddlewareKeys ?? [],\n );\n const missingMiddleware = Array.filter(\n expectedMiddlewareKeys,\n (key) => !HashSet.has(registeredMiddlewareKeys, key),\n );\n\n if (missingMiddleware.length > 0) {\n return yield* new ImplMissingMiddlewareError({\n implPath: implRelativePath,\n groupPath: leaf.groupPathDot,\n missingMiddlewareKeys: missingMiddleware,\n });\n }\n});\n\nexport const withImplFiles = Effect.fnUntraced(function* <A, E, R>(\n relativePaths: ReadonlyArray<ImplModulePath>,\n use: (leaves: ReadonlyArray<LoadedLeafModule>) => Effect.Effect<A, E, R>,\n) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const pairs = yield* Effect.forEach(relativePaths, (implRelativePath) =>\n specPathForImpl(implRelativePath).pipe(\n Effect.map((specRelativePath) => ({\n implRelativePath,\n specRelativePath,\n })),\n ),\n );\n\n return yield* Bundler.withBatch(\n pairs.flatMap(({ implRelativePath, specRelativePath }) => [\n path.resolve(confectDirectory, implRelativePath),\n path.resolve(confectDirectory, specRelativePath),\n ]),\n Effect.gen(function* () {\n const leaves = yield* Effect.forEach(\n pairs,\n Effect.fnUntraced(function* ({ implRelativePath, specRelativePath }) {\n if (\n !(yield* fs.exists(path.join(confectDirectory, specRelativePath)))\n ) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n if (\n !(yield* fs.exists(path.join(confectDirectory, implRelativePath)))\n ) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n const leaf = yield* loadSpec(yield* toLeafModule(specRelativePath));\n return leaf;\n }),\n { concurrency: VALIDATION_CONCURRENCY },\n );\n return yield* use(leaves);\n }),\n );\n});\n\nexport const validateImplFiles = Effect.fn(\"LeafModule.validateImplFiles\")(\n (relativePaths: ReadonlyArray<ImplModulePath>) =>\n withImplFiles(relativePaths, validateAllImpls),\n);\n\nexport const validateAllImpls = Effect.fnUntraced(function* (\n leaves: ReadonlyArray<LoadedLeafModule>,\n) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implementationPaths = yield* Effect.forEach(\n leaves,\n ({ relativePath }) =>\n implPathForSpec(relativePath).pipe(\n Effect.map((implPath) => path.resolve(confectDirectory, implPath)),\n ),\n );\n yield* Bundler.withBatch(\n implementationPaths,\n Effect.forEach(leaves, validateImpl, {\n concurrency: VALIDATION_CONCURRENCY,\n discard: true,\n }),\n );\n});\n\nexport const loadAll = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const results = yield* Bundler.withBatch(\n specFiles.map((relativePath) =>\n path.resolve(confectDirectory, relativePath),\n ),\n Effect.forEach(\n specFiles,\n Effect.fnUntraced(function* (specRelativePath: string) {\n const discovered = yield* toLeafModule(specRelativePath);\n const leaf = yield* loadSpec(discovered);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return leaf;\n }),\n { concurrency: VALIDATION_CONCURRENCY },\n ),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n return results;\n});\n\n/**\n * Walk leaf ancestors and fail with a {@link ParentChildNameCollisionError} when\n * a parent leaf declares a function or subgroup whose name matches a sibling\n * subdirectory spec's segment. Without this check the colliding descendant\n * would overwrite the parent's entry in the assembled `GroupSpec.groups` map at\n * runtime, surfacing as a confusing `Refs.make` error rather than a\n * codegen-time diagnostic.\n */\nconst validateOrphanImpls = Effect.fnUntraced(function* (\n specFiles: ReadonlyArray<string>,\n) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = HashSet.fromIterable(specFiles);\n\n yield* Effect.forEach(\n implFiles,\n Effect.fnUntraced(function* (implRelativePath: string) {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (HashSet.has(specPaths, specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"LeafModule.mjs","names":["Bundler.importersOfPackage","Bundler.bundle","Bundler.directlyImports","Bundler.withBatch"],"sources":["../src/LeafModule.ts"],"sourcesContent":["import { GroupSpec, MiddlewareAttachment } from \"@confect/core\";\nimport { Registry, RegistryItems } from \"@confect/server\";\nimport * as GroupImpl from \"@confect/server/GroupImpl\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport type { Context } from \"effect\";\nimport * as Array from \"effect/Array\";\nimport * as Brand from \"effect/Brand\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\nimport * as String from \"effect/String\";\nimport { fromBundlerError } from \"./BuildError.js\";\nimport * as Bundler from \"./Bundler.js\";\nimport {\n MissingImplFileError,\n MissingSpecFileError,\n ImplMissingDefaultLayerError,\n ImplMissingFunctionsError,\n ImplMissingMiddlewareError,\n RequiredMiddlewareError,\n ImplMissingSpecImportError,\n ImplNotFinalizedError,\n InvalidMiddlewareAttachmentError,\n SpecImportsServerError,\n SpecMissingDefaultGroupSpecError,\n} from \"./CodegenError.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ImplModulePath } from \"./ImplModulePath.js\";\nimport { removePathExtension, toPosixPath } from \"./utils.js\";\n\nexport interface LeafModule {\n readonly relativePath: string;\n readonly pathSegments: readonly [string, ...string[]];\n readonly groupPathDot: string;\n readonly exportName: string;\n readonly specImportPath: string;\n}\n\nexport type LoadedLeafModule = LeafModule & {\n readonly spec: GroupSpec.AnyWithProps;\n} & Brand.Brand<\"@confect/cli/LoadedLeafModule\">;\n\nconst LoadedLeafModule = Brand.nominal<LoadedLeafModule>();\n\nconst VALIDATION_CONCURRENCY = 4;\n\nexport const SPEC_SUFFIX = \".spec.ts\";\nexport const IMPL_SUFFIX = \".impl.ts\";\n\nconst swapModuleSuffix = Effect.fnUntraced(function* (\n relativePath: string,\n fromSuffix: string,\n toSuffix: string,\n) {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n if (ext !== \".ts\" || !name.endsWith(fromSuffix.slice(0, -\".ts\".length))) {\n return relativePath;\n }\n\n const stem = name.slice(0, -fromSuffix.slice(0, -\".ts\".length).length);\n const nextName = `${stem}${toSuffix.slice(0, -\".ts\".length)}`;\n return dir.length > 0\n ? path.join(dir, `${nextName}${ext}`)\n : `${nextName}${ext}`;\n});\n\nexport const isLeafSpecPath = (relativePath: string) =>\n relativePath.endsWith(SPEC_SUFFIX);\n\nexport const exportNameFromModulePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { name, ext } = path.parse(relativePath);\n if (ext !== \".ts\") {\n return name;\n }\n return name.endsWith(\".spec\") ? name.slice(0, -\".spec\".length) : name;\n});\n\nexport const groupPathFromRelativeModulePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n const stem =\n ext === \".ts\" && name.endsWith(\".spec\")\n ? name.slice(0, -\".spec\".length)\n : name;\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n const pathSegments = Array.append(dirSegments, stem) as [string, ...string[]];\n return {\n pathSegments,\n groupPathDot: Array.join(pathSegments, \".\"),\n };\n});\n\nexport const specImportPathFromGenerated = Effect.fnUntraced(function* (\n specRelativePath: string,\n) {\n const path = yield* Path.Path;\n const withoutExt = toPosixPath(\n path,\n yield* removePathExtension(specRelativePath),\n );\n return `../${withoutExt}.js`;\n});\n\nexport const specPathForImpl = (implRelativePath: string) =>\n swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);\n\nexport const implPathForSpec = (specRelativePath: string) =>\n swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);\n\nexport const registeredFunctionsRelativePath = Effect.fnUntraced(function* (\n leaf: LeafModule,\n) {\n const path = yield* Path.Path;\n return path.join(\"registeredFunctions\", ...leaf.pathSegments) + \".ts\";\n});\n\nexport const discoverLeafSpecFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = HashSet.make(\"_generated\", \"tables\", \"middleware\");\n const excludedFiles = HashSet.make(\"nodeSpec.ts\", \"spec.ts\");\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafSpecPath(relativePath)) {\n return false;\n }\n\n if (HashSet.has(excludedFiles, relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) =>\n HashSet.has(excludedDirs, segment),\n );\n });\n});\n\nexport const discoverLeafImplFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = HashSet.make(\"_generated\", \"tables\", \"middleware\");\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(\n Array.filterMap(allPaths, (relativePath) =>\n Schema.decodeResult(ImplModulePath)(relativePath),\n ),\n (relativePath) => {\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) =>\n HashSet.has(excludedDirs, segment),\n );\n },\n );\n});\n\nexport const toLeafModule = Effect.fnUntraced(function* (\n specRelativePath: string,\n) {\n const exportName = yield* exportNameFromModulePath(specRelativePath);\n const { pathSegments, groupPathDot } =\n yield* groupPathFromRelativeModulePath(specRelativePath);\n const specImportPath = yield* specImportPathFromGenerated(specRelativePath);\n\n return {\n relativePath: specRelativePath,\n pathSegments,\n groupPathDot,\n exportName,\n specImportPath,\n } satisfies LeafModule;\n});\n\nconst absoluteModulePath = Effect.fnUntraced(function* (relativePath: string) {\n const confectDirectory = yield* ConfectDirectory.get;\n const path = yield* Path.Path;\n return path.resolve(confectDirectory, relativePath);\n});\n\n/**\n * Every `*.spec.ts` is reachable from `_generated/spec.ts`, which the client\n * imports through `_generated/refs.ts`—so a spec's whole import graph is\n * bundled into the browser whether or not the client calls those functions.\n * Server logic co-located with a declaration therefore ships to users,\n * silently.\n *\n * `@confect/server` is a sound proxy for \"server logic lives here\": an\n * implementation can't be written without `FunctionImpl`/`MiddlewareImpl`, both\n * of which live there. Table `Doc`/`Fields` schemas live in `@confect/core`, so\n * the documented `notes.Doc` pattern in a spec must not reach `@confect/server`\n * even through `tables/` or `_generated/`. The check runs over the spec\n * bundle's transitive inputs rather than the spec module alone, so it also\n * covers middleware declarations under `confect/middleware/` (which codegen\n * otherwise never visits) and any shared helper a spec pulls in—while only ever\n * flagging modules that genuinely reach the client.\n */\nconst validateClientSafety = Effect.fnUntraced(function* (\n leaf: LeafModule,\n bundled: Bundler.Bundled,\n) {\n const path = yield* Path.Path;\n const confectDirectory = path.resolve(yield* ConfectDirectory.get);\n\n const isCheckedUserModule = (absolutePath: string) => {\n const relative = path.relative(confectDirectory, absolutePath);\n return !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n };\n\n const importers = Bundler.importersOfPackage(\n bundled,\n \"@confect/server\",\n isCheckedUserModule,\n );\n\n if (importers.length > 0) {\n return yield* new SpecImportsServerError({\n specPath: leaf.relativePath,\n importerPaths: Array.map(importers, (absolutePath) =>\n toPosixPath(path, path.relative(confectDirectory, absolutePath)),\n ),\n });\n }\n});\n\n/**\n * Validate that the leaf's spec file default-exports a `GroupSpec`, and that\n * nothing it reaches drags server code into the client (see\n * {@link validateClientSafety}). Returns the leaf paired with its validated\n * spec, so subsequent operations reuse that association without re-bundling.\n * The runtime is declared by the spec, not its file location.\n */\nexport const loadSpec = Effect.fn(\"LeafModule.loadSpec\")(function* (\n leaf: LeafModule,\n) {\n const absolutePath = yield* absoluteModulePath(leaf.relativePath);\n const bundled = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n\n const groupSpec = bundled.module.default;\n\n if (!GroupSpec.isGroupSpec(groupSpec)) {\n return yield* new SpecMissingDefaultGroupSpecError({\n specPath: leaf.relativePath,\n });\n }\n\n yield* validateClientSafety(leaf, bundled);\n\n yield* Effect.fromResult(GroupSpec.validateMiddleware(groupSpec)).pipe(\n Effect.mapError(\n (error) =>\n new InvalidMiddlewareAttachmentError({\n specPath: leaf.relativePath,\n message: MiddlewareAttachment.formatValidationError(error),\n }),\n ),\n );\n\n return LoadedLeafModule({\n ...leaf,\n spec: groupSpec,\n });\n});\n\n/**\n * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The\n * lookup is value-shaped (via `GroupImpl.isFinalizedGroupImpl`) so we don't\n * need to know the group's path up front to construct a typed tag for it.\n */\nconst findFinalizedGroupImpl = <S>(\n context: Context.Context<S>,\n): Option.Option<GroupImpl.AnyFinalized> =>\n Array.findFirst(context.mapUnsafe.values(), GroupImpl.isFinalizedGroupImpl);\n\n/**\n * Build the impl layer with a fresh `Registry` so each validation is isolated\n * from prior validations' `FunctionImpl.make` writes. Retain its items to check\n * required middleware against actual function attachments.\n */\nconst buildImplLayer = Effect.fnUntraced(function* (\n implLayer: Layer.Layer<unknown>,\n) {\n const registry = Ref.makeUnsafe<RegistryItems.RegistryItems>({});\n const context = yield* Layer.build(\n implLayer as Layer.Layer<unknown, never, never>,\n ).pipe(Effect.provideService(Registry.Registry, registry));\n return { context, items: yield* Ref.get(registry) };\n}, Effect.scoped);\n\n/**\n * Validate that the leaf's sibling impl file imports the spec, default-exports\n * a finalized `GroupImpl` layer, and provides a `FunctionImpl` for every\n * function declared by the spec. Return uncovered middleware requirements for\n * the caller to report across groups.\n */\nexport const validateImpl = Effect.fn(\"LeafModule.validateImpl\")(function* (\n leaf: LoadedLeafModule,\n required: ReadonlyArray<{ readonly key: string }> = [],\n) {\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const implAbsolutePath = yield* absoluteModulePath(implRelativePath);\n const specAbsolutePath = yield* absoluteModulePath(leaf.relativePath);\n\n const bundled = yield* Bundler.bundle(implAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(implRelativePath, error)),\n );\n\n if (\n !(yield* Bundler.directlyImports(\n bundled,\n implAbsolutePath,\n specAbsolutePath,\n ))\n ) {\n return yield* new ImplMissingSpecImportError({\n implPath: implRelativePath,\n expectedSpecPath: leaf.relativePath,\n });\n }\n\n if (!Layer.isLayer(bundled.module.default)) {\n return yield* new ImplMissingDefaultLayerError({\n implPath: implRelativePath,\n });\n }\n\n const groupSpec = leaf.spec;\n const expectedFunctionNames = Object.keys(groupSpec.functions);\n\n const { context, items } = yield* buildImplLayer(\n bundled.module.default as Layer.Layer<unknown>,\n );\n const finalizedGroupImpl = yield* Option.match(\n findFinalizedGroupImpl(context),\n {\n onNone: () => new ImplNotFinalizedError({ implPath: implRelativePath }),\n onSome: Effect.succeed,\n },\n );\n\n const registeredSet = HashSet.fromIterable(\n finalizedGroupImpl.registeredFunctionNames,\n );\n const missing = expectedFunctionNames.filter(\n (name) => !HashSet.has(registeredSet, name),\n );\n\n if (missing.length > 0) {\n return yield* new ImplMissingFunctionsError({\n implPath: implRelativePath,\n groupPath: leaf.groupPathDot,\n missingFunctionNames: missing,\n });\n }\n\n const expectedMiddlewareKeys = Array.dedupe([\n ...(groupSpec.middlewareSpecs ?? []).map(\n (middlewareSpec) => middlewareSpec.key,\n ),\n ...Object.values(groupSpec.functions).flatMap((function_) =>\n (function_.middlewareSpecs ?? []).map(\n (middlewareSpec) => middlewareSpec.key,\n ),\n ),\n ]);\n const registeredMiddlewareKeys = HashSet.fromIterable(\n finalizedGroupImpl.registeredMiddlewareKeys ?? [],\n );\n const missingMiddleware = Array.filter(\n expectedMiddlewareKeys,\n (key) => !HashSet.has(registeredMiddlewareKeys, key),\n );\n\n if (missingMiddleware.length > 0) {\n return yield* new ImplMissingMiddlewareError({\n implPath: implRelativePath,\n groupPath: leaf.groupPathDot,\n missingMiddlewareKeys: missingMiddleware,\n });\n }\n\n return RegistryItems.missingRequired(items, required, leaf.groupPathDot);\n});\n\nexport const withImplFiles = Effect.fnUntraced(function* <A, E, R>(\n relativePaths: ReadonlyArray<ImplModulePath>,\n use: (leaves: ReadonlyArray<LoadedLeafModule>) => Effect.Effect<A, E, R>,\n) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const pairs = yield* Effect.forEach(relativePaths, (implRelativePath) =>\n specPathForImpl(implRelativePath).pipe(\n Effect.map((specRelativePath) => ({\n implRelativePath,\n specRelativePath,\n })),\n ),\n );\n\n return yield* Bundler.withBatch(\n pairs.flatMap(({ implRelativePath, specRelativePath }) => [\n path.resolve(confectDirectory, implRelativePath),\n path.resolve(confectDirectory, specRelativePath),\n ]),\n Effect.gen(function* () {\n const leaves = yield* Effect.forEach(\n pairs,\n Effect.fnUntraced(function* ({ implRelativePath, specRelativePath }) {\n if (\n !(yield* fs.exists(path.join(confectDirectory, specRelativePath)))\n ) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n if (\n !(yield* fs.exists(path.join(confectDirectory, implRelativePath)))\n ) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n const leaf = yield* loadSpec(yield* toLeafModule(specRelativePath));\n return leaf;\n }),\n { concurrency: VALIDATION_CONCURRENCY },\n );\n return yield* use(leaves);\n }),\n );\n});\n\nexport const validateImplFiles = Effect.fn(\"LeafModule.validateImplFiles\")(\n (relativePaths: ReadonlyArray<ImplModulePath>) =>\n withImplFiles(relativePaths, validateAllImpls),\n);\n\nexport const validateAllImpls = Effect.fnUntraced(function* (\n leaves: ReadonlyArray<LoadedLeafModule>,\n required: ReadonlyArray<{ readonly key: string }> = [],\n) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implementationPaths = yield* Effect.forEach(\n leaves,\n ({ relativePath }) =>\n implPathForSpec(relativePath).pipe(\n Effect.map((implPath) => path.resolve(confectDirectory, implPath)),\n ),\n );\n const missing = (yield* Bundler.withBatch(\n implementationPaths,\n Effect.forEach(leaves, (leaf) => validateImpl(leaf, required), {\n concurrency: VALIDATION_CONCURRENCY,\n }),\n ))\n .flat()\n .sort((left, right) => left.functionName.localeCompare(right.functionName));\n if (missing.length > 0) {\n return yield* new RequiredMiddlewareError({ missing });\n }\n});\n\nexport const loadAll = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const results = yield* Bundler.withBatch(\n specFiles.map((relativePath) =>\n path.resolve(confectDirectory, relativePath),\n ),\n Effect.forEach(\n specFiles,\n Effect.fnUntraced(function* (specRelativePath: string) {\n const discovered = yield* toLeafModule(specRelativePath);\n const leaf = yield* loadSpec(discovered);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return leaf;\n }),\n { concurrency: VALIDATION_CONCURRENCY },\n ),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n return results;\n});\n\n/**\n * Walk leaf ancestors and fail with a {@link ParentChildNameCollisionError} when\n * a parent leaf declares a function or subgroup whose name matches a sibling\n * subdirectory spec's segment. Without this check the colliding descendant\n * would overwrite the parent's entry in the assembled `GroupSpec.groups` map at\n * runtime, surfacing as a confusing `Refs.make` error rather than a\n * codegen-time diagnostic.\n */\nconst validateOrphanImpls = Effect.fnUntraced(function* (\n specFiles: ReadonlyArray<string>,\n) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = HashSet.fromIterable(specFiles);\n\n yield* Effect.forEach(\n implFiles,\n Effect.fnUntraced(function* (implRelativePath: string) {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (HashSet.has(specPaths, specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n});\n"],"mappings":"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"}