@gaganref/confect-cli 10.3.1-fork.2 → 10.3.1-fork.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/Bundler.mjs +22 -1
  2. package/dist/Bundler.mjs.map +1 -1
  3. package/dist/CodegenError.mjs +11 -2
  4. package/dist/CodegenError.mjs.map +1 -1
  5. package/dist/ConfectDirectory.mjs.map +1 -1
  6. package/dist/ConvexConfig.mjs.map +1 -1
  7. package/dist/ConvexDirectory.mjs.map +1 -1
  8. package/dist/DirectoryOptions.mjs.map +1 -1
  9. package/dist/EntryPoint.mjs.map +1 -1
  10. package/dist/Evaluation.mjs +39 -13
  11. package/dist/Evaluation.mjs.map +1 -1
  12. package/dist/EvaluationWorker.mjs +13 -1
  13. package/dist/EvaluationWorker.mjs.map +1 -1
  14. package/dist/FunctionModule.mjs +81 -13
  15. package/dist/FunctionModule.mjs.map +1 -1
  16. package/dist/FunctionPath.mjs.map +1 -1
  17. package/dist/FunctionPaths.mjs.map +1 -1
  18. package/dist/GenerationSnapshot.mjs.map +1 -1
  19. package/dist/GroupPaths.mjs.map +1 -1
  20. package/dist/ImplModulePath.mjs.map +1 -1
  21. package/dist/LeafModule.mjs +17 -17
  22. package/dist/LeafModule.mjs.map +1 -1
  23. package/dist/Remove.mjs.map +1 -1
  24. package/dist/Rollback.mjs.map +1 -1
  25. package/dist/SpecAssemblyNode.mjs.map +1 -1
  26. package/dist/SpecModulePath.mjs.map +1 -1
  27. package/dist/SyncState.mjs.map +1 -1
  28. package/dist/TableModule.mjs.map +1 -1
  29. package/dist/TableModulePath.mjs.map +1 -1
  30. package/dist/WatchBuild.mjs.map +1 -1
  31. package/dist/WatchTopology.mjs.map +1 -1
  32. package/dist/Watcher.mjs +57 -55
  33. package/dist/Watcher.mjs.map +1 -1
  34. package/dist/cliApp.mjs.map +1 -1
  35. package/dist/confect/codegen.mjs +75 -23
  36. package/dist/confect/codegen.mjs.map +1 -1
  37. package/dist/confect/declaration.mjs +4 -3
  38. package/dist/confect/declaration.mjs.map +1 -1
  39. package/dist/confect/dev.mjs +9 -4
  40. package/dist/confect/dev.mjs.map +1 -1
  41. package/dist/confect.mjs.map +1 -1
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/log.mjs.map +1 -1
  44. package/dist/templates.mjs +16 -12
  45. package/dist/templates.mjs.map +1 -1
  46. package/dist/utils.mjs +1 -1
  47. package/dist/utils.mjs.map +1 -1
  48. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"GenerationSnapshot.mjs","names":["GroupPath.GroupPath","GroupPath.make","GroupPath.append"],"sources":["../src/GenerationSnapshot.ts"],"sourcesContent":["import { type GroupSpec, Identifier } from \"@confect/core\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashMap from \"effect/HashMap\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaGetter from \"effect/SchemaGetter\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\nimport * as String from \"effect/String\";\nimport { ParentChildNameCollisionError } from \"./CodegenError\";\nimport * as FunctionPath from \"./FunctionPath\";\nimport * as FunctionPaths from \"./FunctionPaths\";\nimport * as GroupPath from \"./GroupPath\";\nimport type { LoadedLeafModule } from \"./LeafModule\";\nimport * as SpecModulePath from \"./SpecModulePath\";\nimport { SnapshotError } from \"./SnapshotError\";\n\nexport { SnapshotError } from \"./SnapshotError\";\n\nexport const GroupSummary = Schema.Struct({\n path: GroupPath.GroupPath,\n runtime: Schema.Literals([\"Convex\", \"Node\"]),\n functionNames: Schema.Array(Schema.NonEmptyString),\n});\nexport interface GroupSummary extends Schema.Schema.Type<typeof GroupSummary> {}\n\nexport interface GroupTree {\n readonly runtime: \"Convex\" | \"Node\";\n readonly functionNames: ReadonlyArray<string>;\n readonly groups: { readonly [name: string]: GroupTree };\n}\n\nexport const GroupTree: Schema.Codec<GroupTree> = Schema.Struct({\n runtime: GroupSummary.fields.runtime,\n functionNames: GroupSummary.fields.functionNames,\n groups: Schema.Record(\n Schema.String,\n Schema.suspend(() => GroupTree),\n ),\n});\n\nclass Snapshot {\n readonly #leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>;\n\n private constructor(\n leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n ) {\n this.#leaves = leaves;\n }\n\n static parseLeaves(\n leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n ): Result.Result<GenerationSnapshot, ParentChildNameCollisionError> {\n return Result.map(\n parseNoParentChildNameCollisions(leaves),\n (parsed) => new Snapshot(parsed),\n );\n }\n\n get leaves(): HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree> {\n return this.#leaves;\n }\n}\n\nexport interface GenerationSnapshot extends Snapshot {}\n\nconst Entries = Schema.Array(Schema.Tuple([Schema.String, GroupTree]));\nconst CanonicalSpecPath = SpecModulePath.SpecModulePath.check(\n Schema.makeFilter((path) => !path.includes(\"\\\\\")),\n);\nconst rootPath = (path: SpecModulePath.SpecModulePath) =>\n GroupPath.make(String.split(path.slice(0, -\".spec.ts\".length), \"/\"));\n\nconst parseTree = (\n relativePath: SpecModulePath.SpecModulePath,\n path: GroupPath.GroupPath,\n tree: GroupTree,\n): Result.Result<GroupTree, SnapshotError> =>\n Result.gen(function* () {\n yield* Result.try({\n try: () => {\n for (const name of tree.functionNames)\n Identifier.validateConfectFunctionIdentifier(name);\n },\n catch: () =>\n new SnapshotError({\n reason: \"NoncanonicalFunctionNames\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n });\n if (\n HashSet.size(HashSet.fromIterable(tree.functionNames)) !==\n tree.functionNames.length\n ) {\n return yield* Result.fail(\n new SnapshotError({\n reason: \"NoncanonicalFunctionNames\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n );\n }\n for (const [name, child] of Object.entries(tree.groups)) {\n yield* Result.try({\n try: () => Identifier.validateConfectFunctionIdentifier(name),\n catch: () =>\n new SnapshotError({\n reason: \"NoncanonicalPath\",\n relativePath,\n pathSegments: [...path.pathSegments, name],\n }),\n });\n yield* parseTree(relativePath, GroupPath.append(path, name), child);\n }\n return tree;\n });\n\nconst fromEntries = (\n entries: ReadonlyArray<readonly [string, GroupTree]>,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n Result.gen(function* () {\n let leaves = HashMap.empty<SpecModulePath.SpecModulePath, GroupTree>();\n for (const [key, tree] of entries) {\n const relativePath = yield* Schema.decodeResult(CanonicalSpecPath)(\n key,\n ).pipe(\n Result.mapError(\n (cause) =>\n new SnapshotError({\n reason: \"NoncanonicalPath\",\n relativePath: key,\n pathSegments: [],\n cause,\n }),\n ),\n );\n const path = rootPath(relativePath);\n yield* Result.try({\n try: () => {\n for (const segment of path.pathSegments)\n Identifier.validateConfectFunctionIdentifier(segment);\n },\n catch: () =>\n new SnapshotError({\n reason: \"NoncanonicalPath\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n });\n if (HashMap.has(leaves, relativePath)) {\n return yield* Result.fail(\n new SnapshotError({\n reason: \"DuplicateLeaf\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n );\n }\n const parsed = yield* parseTree(relativePath, path, tree);\n leaves = HashMap.set(leaves, relativePath, parsed);\n }\n return yield* Snapshot.parseLeaves(leaves);\n });\n\nexport const parse = (\n input: unknown,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n Schema.decodeUnknownResult(Entries)(input).pipe(\n Result.mapError(\n (cause) =>\n new SnapshotError({\n reason: \"InvalidShape\",\n relativePath: \"\",\n pathSegments: [],\n cause,\n }),\n ),\n Result.flatMap(fromEntries),\n );\n\nexport const GenerationSnapshot = Entries.pipe(\n Schema.decodeTo(\n Schema.declare<GenerationSnapshot>((input) => input instanceof Snapshot),\n {\n decode: SchemaGetter.transformEffect((entries, options) =>\n Effect.fromResult(fromEntries(entries)).pipe(\n Effect.mapError(\n (error) =>\n new SchemaIssue.InvalidValue(\n {\n message: Match.value(error).pipe(\n Match.tagsExhaustive({\n SnapshotError: (failure) => failure.message,\n ParentChildNameCollisionError: (failure) =>\n `${failure.parentSpecPath} declares a ${failure.collisionKind} named ${failure.collisionName} that collides with ${failure.childSpecPath}`,\n }),\n ),\n },\n entries,\n options,\n ),\n ),\n ),\n ),\n encode: SchemaGetter.transform((snapshot) =>\n HashMap.toEntries(snapshot.leaves),\n ),\n },\n ),\n);\n\nconst summarize = (group: GroupSpec.AnyWithProps): GroupTree => ({\n runtime: group.runtime,\n functionNames: Record.keys(group.functions),\n groups: Record.map(group.groups, summarize),\n});\n\nexport const update = (\n snapshot: GenerationSnapshot,\n leaves: ReadonlyArray<LoadedLeafModule>,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n Result.gen(function* () {\n if (leaves.length === 0) return snapshot;\n const replacement = yield* fromLoadedLeaves(leaves);\n return yield* Snapshot.parseLeaves(\n HashMap.union(snapshot.leaves, replacement.leaves),\n );\n });\n\nexport const fromLoadedLeaves = (\n leaves: ReadonlyArray<LoadedLeafModule>,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n parse(\n leaves.map(\n (leaf) =>\n [\n leaf.relativePath.replaceAll(\"\\\\\", \"/\"),\n summarize(leaf.spec),\n ] as const,\n ),\n );\n\nconst groups = (snapshot: GenerationSnapshot): ReadonlyArray<GroupSummary> => {\n const visit = (\n path: GroupPath.GroupPath,\n tree: GroupTree,\n ): ReadonlyArray<GroupSummary> => [\n {\n path,\n runtime: tree.runtime,\n functionNames: Array.sort(tree.functionNames, String.Order),\n },\n ...Array.flatMap(\n Array.sort(Object.keys(tree.groups), String.Order),\n (name: string) => visit(GroupPath.append(path, name), tree.groups[name]!),\n ),\n ];\n return Array.flatMap(Array.fromIterable(snapshot.leaves), ([path, tree]) =>\n visit(rootPath(path), tree),\n );\n};\n\nexport const functionPaths = (\n snapshot: GenerationSnapshot,\n): FunctionPaths.FunctionPaths =>\n FunctionPaths.FunctionPaths.make(\n HashSet.fromIterable(\n Array.flatMap(groups(snapshot), (group) =>\n group.functionNames.map((name) =>\n FunctionPath.FunctionPath.make({ groupPath: group.path, name }),\n ),\n ),\n ),\n );\n\nconst generatedGroups = (snapshot: GenerationSnapshot) =>\n HashMap.fromIterable(\n Array.filterMap(groups(snapshot), (group) =>\n group.functionNames.length === 0\n ? Result.fail(undefined)\n : Result.succeed([group.path, group] as const),\n ),\n );\n\nexport interface ModulePlan {\n readonly removed: ReadonlyArray<GroupPath.GroupPath>;\n readonly changed: ReadonlyArray<GroupSummary>;\n}\n\nexport const plan = (\n snapshot: GenerationSnapshot,\n existing: Iterable<GroupPath.GroupPath>,\n): ModulePlan => {\n const current = generatedGroups(snapshot);\n return {\n removed: Array.fromIterable(existing).filter(\n (path) => !HashMap.has(current, path),\n ),\n changed: Array.fromIterable(HashMap.values(current)),\n };\n};\n\nconst equivalentGroup = Schema.toEquivalence(GroupSummary);\n\nexport const diff = (\n before: GenerationSnapshot,\n after: GenerationSnapshot,\n): ModulePlan => {\n const previous = generatedGroups(before);\n const current = generatedGroups(after);\n return {\n removed: Array.filter(\n HashMap.keys(previous),\n (path) => !HashMap.has(current, path),\n ),\n changed: Array.filter(HashMap.values(current), (group) => {\n const old = HashMap.get(previous, group.path);\n return Option.isNone(old) || !equivalentGroup(old.value, group);\n }),\n };\n};\n\nconst parseNoParentChildNameCollisions = (\n leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n): Result.Result<\n HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n ParentChildNameCollisionError\n> => {\n for (const childPath of HashMap.keys(leaves)) {\n const segments = rootPath(childPath).pathSegments;\n for (let depth = 1; depth < segments.length; depth++) {\n const parentPath = SpecModulePath.SpecModulePath.make(\n `${segments.slice(0, depth).join(\"/\")}.spec.ts`,\n );\n const parent = HashMap.get(leaves, parentPath);\n if (Option.isNone(parent)) continue;\n const collisionName = segments[depth]!;\n const collisionKind = parent.value.functionNames.includes(collisionName)\n ? \"function\"\n : Object.hasOwn(parent.value.groups, collisionName)\n ? \"group\"\n : undefined;\n if (collisionKind !== undefined) {\n return Result.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentPath,\n childSpecPath: childPath,\n collisionName,\n collisionKind,\n }),\n );\n }\n }\n }\n return Result.succeed(leaves);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"GenerationSnapshot.mjs","names":["GroupPath.GroupPath","GroupPath.make","GroupPath.append"],"sources":["../src/GenerationSnapshot.ts"],"sourcesContent":["import { type GroupSpec, Identifier } from \"@confect/core\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashMap from \"effect/HashMap\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaGetter from \"effect/SchemaGetter\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\nimport * as String from \"effect/String\";\nimport { ParentChildNameCollisionError } from \"./CodegenError.js\";\nimport * as FunctionPath from \"./FunctionPath.js\";\nimport * as FunctionPaths from \"./FunctionPaths.js\";\nimport * as GroupPath from \"./GroupPath.js\";\nimport type { LoadedLeafModule } from \"./LeafModule.js\";\nimport * as SpecModulePath from \"./SpecModulePath.js\";\nimport { SnapshotError } from \"./SnapshotError.js\";\n\nexport { SnapshotError } from \"./SnapshotError.js\";\n\nexport const GroupSummary = Schema.Struct({\n path: GroupPath.GroupPath,\n runtime: Schema.Literals([\"Convex\", \"Node\"]),\n functionNames: Schema.Array(Schema.NonEmptyString),\n});\nexport interface GroupSummary extends Schema.Schema.Type<typeof GroupSummary> {}\n\nexport interface GroupTree {\n readonly runtime: \"Convex\" | \"Node\";\n readonly functionNames: ReadonlyArray<string>;\n readonly groups: { readonly [name: string]: GroupTree };\n}\n\nexport const GroupTree: Schema.Codec<GroupTree> = Schema.Struct({\n runtime: GroupSummary.fields.runtime,\n functionNames: GroupSummary.fields.functionNames,\n groups: Schema.Record(\n Schema.String,\n Schema.suspend(() => GroupTree),\n ),\n});\n\nclass Snapshot {\n readonly #leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>;\n\n private constructor(\n leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n ) {\n this.#leaves = leaves;\n }\n\n static parseLeaves(\n leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n ): Result.Result<GenerationSnapshot, ParentChildNameCollisionError> {\n return Result.map(\n parseNoParentChildNameCollisions(leaves),\n (parsed) => new Snapshot(parsed),\n );\n }\n\n get leaves(): HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree> {\n return this.#leaves;\n }\n}\n\nexport interface GenerationSnapshot extends Snapshot {}\n\nconst Entries = Schema.Array(Schema.Tuple([Schema.String, GroupTree]));\nconst CanonicalSpecPath = SpecModulePath.SpecModulePath.check(\n Schema.makeFilter((path) => !path.includes(\"\\\\\")),\n);\nconst rootPath = (path: SpecModulePath.SpecModulePath) =>\n GroupPath.make(String.split(path.slice(0, -\".spec.ts\".length), \"/\"));\n\nconst parseTree = (\n relativePath: SpecModulePath.SpecModulePath,\n path: GroupPath.GroupPath,\n tree: GroupTree,\n): Result.Result<GroupTree, SnapshotError> =>\n Result.gen(function* () {\n yield* Result.try({\n try: () => {\n for (const name of tree.functionNames)\n Identifier.validateConfectFunctionIdentifier(name);\n },\n catch: () =>\n new SnapshotError({\n reason: \"NoncanonicalFunctionNames\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n });\n if (\n HashSet.size(HashSet.fromIterable(tree.functionNames)) !==\n tree.functionNames.length\n ) {\n return yield* Result.fail(\n new SnapshotError({\n reason: \"NoncanonicalFunctionNames\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n );\n }\n for (const [name, child] of Object.entries(tree.groups)) {\n yield* Result.try({\n try: () => Identifier.validateConfectFunctionIdentifier(name),\n catch: () =>\n new SnapshotError({\n reason: \"NoncanonicalPath\",\n relativePath,\n pathSegments: [...path.pathSegments, name],\n }),\n });\n yield* parseTree(relativePath, GroupPath.append(path, name), child);\n }\n return tree;\n });\n\nconst fromEntries = (\n entries: ReadonlyArray<readonly [string, GroupTree]>,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n Result.gen(function* () {\n let leaves = HashMap.empty<SpecModulePath.SpecModulePath, GroupTree>();\n for (const [key, tree] of entries) {\n const relativePath = yield* Schema.decodeResult(CanonicalSpecPath)(\n key,\n ).pipe(\n Result.mapError(\n (cause) =>\n new SnapshotError({\n reason: \"NoncanonicalPath\",\n relativePath: key,\n pathSegments: [],\n cause,\n }),\n ),\n );\n const path = rootPath(relativePath);\n yield* Result.try({\n try: () => {\n for (const segment of path.pathSegments)\n Identifier.validateConfectFunctionIdentifier(segment);\n },\n catch: () =>\n new SnapshotError({\n reason: \"NoncanonicalPath\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n });\n if (HashMap.has(leaves, relativePath)) {\n return yield* Result.fail(\n new SnapshotError({\n reason: \"DuplicateLeaf\",\n relativePath,\n pathSegments: path.pathSegments,\n }),\n );\n }\n const parsed = yield* parseTree(relativePath, path, tree);\n leaves = HashMap.set(leaves, relativePath, parsed);\n }\n return yield* Snapshot.parseLeaves(leaves);\n });\n\nexport const parse = (\n input: unknown,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n Schema.decodeUnknownResult(Entries)(input).pipe(\n Result.mapError(\n (cause) =>\n new SnapshotError({\n reason: \"InvalidShape\",\n relativePath: \"\",\n pathSegments: [],\n cause,\n }),\n ),\n Result.flatMap(fromEntries),\n );\n\nexport const GenerationSnapshot = Entries.pipe(\n Schema.decodeTo(\n Schema.declare<GenerationSnapshot>((input) => input instanceof Snapshot),\n {\n decode: SchemaGetter.transformEffect((entries, options) =>\n Effect.fromResult(fromEntries(entries)).pipe(\n Effect.mapError(\n (error) =>\n new SchemaIssue.InvalidValue(\n {\n message: Match.value(error).pipe(\n Match.tagsExhaustive({\n SnapshotError: (failure) => failure.message,\n ParentChildNameCollisionError: (failure) =>\n `${failure.parentSpecPath} declares a ${failure.collisionKind} named ${failure.collisionName} that collides with ${failure.childSpecPath}`,\n }),\n ),\n },\n entries,\n options,\n ),\n ),\n ),\n ),\n encode: SchemaGetter.transform((snapshot) =>\n HashMap.toEntries(snapshot.leaves),\n ),\n },\n ),\n);\n\nconst summarize = (group: GroupSpec.AnyWithProps): GroupTree => ({\n runtime: group.runtime,\n functionNames: Record.keys(group.functions),\n groups: Record.map(group.groups, summarize),\n});\n\nexport const update = (\n snapshot: GenerationSnapshot,\n leaves: ReadonlyArray<LoadedLeafModule>,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n Result.gen(function* () {\n if (leaves.length === 0) return snapshot;\n const replacement = yield* fromLoadedLeaves(leaves);\n return yield* Snapshot.parseLeaves(\n HashMap.union(snapshot.leaves, replacement.leaves),\n );\n });\n\nexport const fromLoadedLeaves = (\n leaves: ReadonlyArray<LoadedLeafModule>,\n): Result.Result<\n GenerationSnapshot,\n SnapshotError | ParentChildNameCollisionError\n> =>\n parse(\n leaves.map(\n (leaf) =>\n [\n leaf.relativePath.replaceAll(\"\\\\\", \"/\"),\n summarize(leaf.spec),\n ] as const,\n ),\n );\n\nconst groups = (snapshot: GenerationSnapshot): ReadonlyArray<GroupSummary> => {\n const visit = (\n path: GroupPath.GroupPath,\n tree: GroupTree,\n ): ReadonlyArray<GroupSummary> => [\n {\n path,\n runtime: tree.runtime,\n functionNames: Array.sort(tree.functionNames, String.Order),\n },\n ...Array.flatMap(\n Array.sort(Object.keys(tree.groups), String.Order),\n (name: string) => visit(GroupPath.append(path, name), tree.groups[name]!),\n ),\n ];\n return Array.flatMap(Array.fromIterable(snapshot.leaves), ([path, tree]) =>\n visit(rootPath(path), tree),\n );\n};\n\nexport const functionPaths = (\n snapshot: GenerationSnapshot,\n): FunctionPaths.FunctionPaths =>\n FunctionPaths.FunctionPaths.make(\n HashSet.fromIterable(\n Array.flatMap(groups(snapshot), (group) =>\n group.functionNames.map((name) =>\n FunctionPath.FunctionPath.make({ groupPath: group.path, name }),\n ),\n ),\n ),\n );\n\nconst generatedGroups = (snapshot: GenerationSnapshot) =>\n HashMap.fromIterable(\n Array.filterMap(groups(snapshot), (group) =>\n group.functionNames.length === 0\n ? Result.fail(undefined)\n : Result.succeed([group.path, group] as const),\n ),\n );\n\nexport interface ModulePlan {\n readonly removed: ReadonlyArray<GroupPath.GroupPath>;\n readonly changed: ReadonlyArray<GroupSummary>;\n}\n\nexport const plan = (\n snapshot: GenerationSnapshot,\n existing: Iterable<GroupPath.GroupPath>,\n): ModulePlan => {\n const current = generatedGroups(snapshot);\n return {\n removed: Array.fromIterable(existing).filter(\n (path) => !HashMap.has(current, path),\n ),\n changed: Array.fromIterable(HashMap.values(current)),\n };\n};\n\nconst equivalentGroup = Schema.toEquivalence(GroupSummary);\n\nexport const diff = (\n before: GenerationSnapshot,\n after: GenerationSnapshot,\n): ModulePlan => {\n const previous = generatedGroups(before);\n const current = generatedGroups(after);\n return {\n removed: Array.filter(\n HashMap.keys(previous),\n (path) => !HashMap.has(current, path),\n ),\n changed: Array.filter(HashMap.values(current), (group) => {\n const old = HashMap.get(previous, group.path);\n return Option.isNone(old) || !equivalentGroup(old.value, group);\n }),\n };\n};\n\nconst parseNoParentChildNameCollisions = (\n leaves: HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n): Result.Result<\n HashMap.HashMap<SpecModulePath.SpecModulePath, GroupTree>,\n ParentChildNameCollisionError\n> => {\n for (const childPath of HashMap.keys(leaves)) {\n const segments = rootPath(childPath).pathSegments;\n for (let depth = 1; depth < segments.length; depth++) {\n const parentPath = SpecModulePath.SpecModulePath.make(\n `${segments.slice(0, depth).join(\"/\")}.spec.ts`,\n );\n const parent = HashMap.get(leaves, parentPath);\n if (Option.isNone(parent)) continue;\n const collisionName = segments[depth]!;\n const collisionKind = parent.value.functionNames.includes(collisionName)\n ? \"function\"\n : Object.hasOwn(parent.value.groups, collisionName)\n ? \"group\"\n : undefined;\n if (collisionKind !== undefined) {\n return Result.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentPath,\n childSpecPath: childPath,\n collisionName,\n collisionKind,\n }),\n );\n }\n }\n }\n return Result.succeed(leaves);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,eAAe,OAAO,OAAO;CACxC,MAAMA;CACN,SAAS,OAAO,SAAS,CAAC,UAAU,MAAM,CAAC;CAC3C,eAAe,OAAO,MAAM,OAAO,cAAc;AACnD,CAAC;AASD,MAAa,YAAqC,OAAO,OAAO;CAC9D,SAAS,aAAa,OAAO;CAC7B,eAAe,aAAa,OAAO;CACnC,QAAQ,OAAO,OACb,OAAO,QACP,OAAO,cAAc,SAAS,CAChC;AACF,CAAC;AAED,IAAM,WAAN,MAAM,SAAS;CACb;CAEA,YACE,QACA;EACA,KAAK,UAAU;CACjB;CAEA,OAAO,YACL,QACkE;EAClE,OAAO,OAAO,IACZ,iCAAiC,MAAM,IACtC,WAAW,IAAI,SAAS,MAAM,CACjC;CACF;CAEA,IAAI,SAAoE;EACtE,OAAO,KAAK;CACd;AACF;AAIA,MAAM,UAAU,OAAO,MAAM,OAAO,MAAM,CAAC,OAAO,QAAQ,SAAS,CAAC,CAAC;AACrE,MAAM,oBAAA,eAAkD,MACtD,OAAO,YAAY,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,CAClD;AACA,MAAM,YAAY,SAChBC,KAAe,OAAO,MAAM,KAAK,MAAM,GAAG,EAAkB,GAAG,GAAG,CAAC;AAErE,MAAM,aACJ,cACA,MACA,SAEA,OAAO,IAAI,aAAa;CACtB,OAAO,OAAO,IAAI;EAChB,WAAW;GACT,KAAK,MAAM,QAAQ,KAAK,eACtB,WAAW,kCAAkC,IAAI;EACrD;EACA,aACE,IAAI,cAAc;GAChB,QAAQ;GACR;GACA,cAAc,KAAK;EACrB,CAAC;CACL,CAAC;CACD,IACE,QAAQ,KAAK,QAAQ,aAAa,KAAK,aAAa,CAAC,MACrD,KAAK,cAAc,QAEnB,OAAO,OAAO,OAAO,KACnB,IAAI,cAAc;EAChB,QAAQ;EACR;EACA,cAAc,KAAK;CACrB,CAAC,CACH;CAEF,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,MAAM,GAAG;EACvD,OAAO,OAAO,IAAI;GAChB,WAAW,WAAW,kCAAkC,IAAI;GAC5D,aACE,IAAI,cAAc;IAChB,QAAQ;IACR;IACA,cAAc,CAAC,GAAG,KAAK,cAAc,IAAI;GAC3C,CAAC;EACL,CAAC;EACD,OAAO,UAAU,cAAcC,OAAiB,MAAM,IAAI,GAAG,KAAK;CACpE;CACA,OAAO;AACT,CAAC;AAEH,MAAM,eACJ,YAKA,OAAO,IAAI,aAAa;CACtB,IAAI,SAAS,QAAQ,MAAgD;CACrE,KAAK,MAAM,CAAC,KAAK,SAAS,SAAS;EACjC,MAAM,eAAe,OAAO,OAAO,aAAa,iBAAiB,CAAC,CAChE,GACF,CAAC,CAAC,KACA,OAAO,UACJ,UACC,IAAI,cAAc;GAChB,QAAQ;GACR,cAAc;GACd,cAAc,CAAC;GACf;EACF,CAAC,CACL,CACF;EACA,MAAM,OAAO,SAAS,YAAY;EAClC,OAAO,OAAO,IAAI;GAChB,WAAW;IACT,KAAK,MAAM,WAAW,KAAK,cACzB,WAAW,kCAAkC,OAAO;GACxD;GACA,aACE,IAAI,cAAc;IAChB,QAAQ;IACR;IACA,cAAc,KAAK;GACrB,CAAC;EACL,CAAC;EACD,IAAI,QAAQ,IAAI,QAAQ,YAAY,GAClC,OAAO,OAAO,OAAO,KACnB,IAAI,cAAc;GAChB,QAAQ;GACR;GACA,cAAc,KAAK;EACrB,CAAC,CACH;EAEF,MAAM,SAAS,OAAO,UAAU,cAAc,MAAM,IAAI;EACxD,SAAS,QAAQ,IAAI,QAAQ,cAAc,MAAM;CACnD;CACA,OAAO,OAAO,SAAS,YAAY,MAAM;AAC3C,CAAC;AAEH,MAAa,SACX,UAKA,OAAO,oBAAoB,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KACzC,OAAO,UACJ,UACC,IAAI,cAAc;CAChB,QAAQ;CACR,cAAc;CACd,cAAc,CAAC;CACf;AACF,CAAC,CACL,GACA,OAAO,QAAQ,WAAW,CAC5B;AAEF,MAAa,qBAAqB,QAAQ,KACxC,OAAO,SACL,OAAO,SAA6B,UAAU,iBAAiB,QAAQ,GACvE;CACE,QAAQ,aAAa,iBAAiB,SAAS,YAC7C,OAAO,WAAW,YAAY,OAAO,CAAC,CAAC,CAAC,KACtC,OAAO,UACJ,UACC,IAAI,YAAY,aACd,EACE,SAAS,MAAM,MAAM,KAAK,CAAC,CAAC,KAC1B,MAAM,eAAe;EACnB,gBAAgB,YAAY,QAAQ;EACpC,gCAAgC,YAC9B,GAAG,QAAQ,eAAe,cAAc,QAAQ,cAAc,SAAS,QAAQ,cAAc,sBAAsB,QAAQ;CAC/H,CAAC,CACH,EACF,GACA,SACA,OACF,CACJ,CACF,CACF;CACA,QAAQ,aAAa,WAAW,aAC9B,QAAQ,UAAU,SAAS,MAAM,CACnC;AACF,CACF,CACF;AAEA,MAAM,aAAa,WAA8C;CAC/D,SAAS,MAAM;CACf,eAAe,OAAO,KAAK,MAAM,SAAS;CAC1C,QAAQ,OAAO,IAAI,MAAM,QAAQ,SAAS;AAC5C;AAEA,MAAa,UACX,UACA,WAKA,OAAO,IAAI,aAAa;CACtB,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,MAAM,cAAc,OAAO,iBAAiB,MAAM;CAClD,OAAO,OAAO,SAAS,YACrB,QAAQ,MAAM,SAAS,QAAQ,YAAY,MAAM,CACnD;AACF,CAAC;AAEH,MAAa,oBACX,WAKA,MACE,OAAO,KACJ,SACC,CACE,KAAK,aAAa,WAAW,MAAM,GAAG,GACtC,UAAU,KAAK,IAAI,CACrB,CACJ,CACF;AAEF,MAAM,UAAU,aAA8D;CAC5E,MAAM,SACJ,MACA,SACgC,CAChC;EACE;EACA,SAAS,KAAK;EACd,eAAe,MAAM,KAAK,KAAK,eAAe,OAAO,KAAK;CAC5D,GACA,GAAG,MAAM,QACP,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,GAAG,OAAO,KAAK,IAChD,SAAiB,MAAMA,OAAiB,MAAM,IAAI,GAAG,KAAK,OAAO,KAAM,CAC1E,CACF;CACA,OAAO,MAAM,QAAQ,MAAM,aAAa,SAAS,MAAM,IAAI,CAAC,MAAM,UAChE,MAAM,SAAS,IAAI,GAAG,IAAI,CAC5B;AACF;AAEA,MAAa,iBACX,aAAA,cAE4B,KAC1B,QAAQ,aACN,MAAM,QAAQ,OAAO,QAAQ,IAAI,UAC/B,MAAM,cAAc,KAAK,SAAA,aACG,KAAK;CAAE,WAAW,MAAM;CAAM;AAAK,CAAC,CAChE,CACF,CACF,CACF;AAEF,MAAM,mBAAmB,aACvB,QAAQ,aACN,MAAM,UAAU,OAAO,QAAQ,IAAI,UACjC,MAAM,cAAc,WAAW,IAC3B,OAAO,KAAK,KAAA,CAAS,IACrB,OAAO,QAAQ,CAAC,MAAM,MAAM,KAAK,CAAU,CACjD,CACF;AAOF,MAAa,QACX,UACA,aACe;CACf,MAAM,UAAU,gBAAgB,QAAQ;CACxC,OAAO;EACL,SAAS,MAAM,aAAa,QAAQ,CAAC,CAAC,QACnC,SAAS,CAAC,QAAQ,IAAI,SAAS,IAAI,CACtC;EACA,SAAS,MAAM,aAAa,QAAQ,OAAO,OAAO,CAAC;CACrD;AACF;AAEA,MAAM,kBAAkB,OAAO,cAAc,YAAY;AAEzD,MAAa,QACX,QACA,UACe;CACf,MAAM,WAAW,gBAAgB,MAAM;CACvC,MAAM,UAAU,gBAAgB,KAAK;CACrC,OAAO;EACL,SAAS,MAAM,OACb,QAAQ,KAAK,QAAQ,IACpB,SAAS,CAAC,QAAQ,IAAI,SAAS,IAAI,CACtC;EACA,SAAS,MAAM,OAAO,QAAQ,OAAO,OAAO,IAAI,UAAU;GACxD,MAAM,MAAM,QAAQ,IAAI,UAAU,MAAM,IAAI;GAC5C,OAAO,OAAO,OAAO,GAAG,KAAK,CAAC,gBAAgB,IAAI,OAAO,KAAK;EAChE,CAAC;CACH;AACF;AAEA,MAAM,oCACJ,WAIG;CACH,KAAK,MAAM,aAAa,QAAQ,KAAK,MAAM,GAAG;EAC5C,MAAM,WAAW,SAAS,SAAS,CAAC,CAAC;EACrC,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS;GACpD,MAAM,aAAA,eAA2C,KAC/C,GAAG,SAAS,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,GAAG,EAAE,SACxC;GACA,MAAM,SAAS,QAAQ,IAAI,QAAQ,UAAU;GAC7C,IAAI,OAAO,OAAO,MAAM,GAAG;GAC3B,MAAM,gBAAgB,SAAS;GAC/B,MAAM,gBAAgB,OAAO,MAAM,cAAc,SAAS,aAAa,IACnE,aACA,OAAO,OAAO,OAAO,MAAM,QAAQ,aAAa,IAC9C,UACA,KAAA;GACN,IAAI,kBAAkB,KAAA,GACpB,OAAO,OAAO,KACZ,IAAI,8BAA8B;IAChC,gBAAgB;IAChB,eAAe;IACf;IACA;GACF,CAAC,CACH;EAEJ;CACF;CACA,OAAO,OAAO,QAAQ,MAAM;AAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"GroupPaths.mjs","names":["GroupPath.GroupPath"],"sources":["../src/GroupPaths.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath\";\n\nexport const GroupPaths = Schema.HashSet(GroupPath.GroupPath).pipe(\n Schema.brand(\"@confect/cli/GroupPaths\"),\n);\nexport type GroupPaths = typeof GroupPaths.Type;\n"],"mappings":";;;AAGA,MAAa,aAAa,OAAO,QAAQA,SAAmB,CAAC,CAAC,KAC5D,OAAO,MAAM,yBAAyB,CACxC"}
1
+ {"version":3,"file":"GroupPaths.mjs","names":["GroupPath.GroupPath"],"sources":["../src/GroupPaths.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath.js\";\n\nexport const GroupPaths = Schema.HashSet(GroupPath.GroupPath).pipe(\n Schema.brand(\"@confect/cli/GroupPaths\"),\n);\nexport type GroupPaths = typeof GroupPaths.Type;\n"],"mappings":";;;AAGA,MAAa,aAAa,OAAO,QAAQA,SAAmB,CAAC,CAAC,KAC5D,OAAO,MAAM,yBAAyB,CACxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImplModulePath.mjs","names":["RelativeModulePath.withSuffix"],"sources":["../src/ImplModulePath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as RelativeModulePath from \"./RelativeModulePath\";\n\nexport const ImplModulePath = RelativeModulePath.withSuffix(\".impl.ts\").pipe(\n Schema.brand(\"@confect/cli/ImplModulePath\"),\n);\n\nexport type ImplModulePath = typeof ImplModulePath.Type;\n"],"mappings":";;;AAGA,MAAa,iBAAiBA,WAA8B,UAAU,CAAC,CAAC,KACtE,OAAO,MAAM,6BAA6B,CAC5C"}
1
+ {"version":3,"file":"ImplModulePath.mjs","names":["RelativeModulePath.withSuffix"],"sources":["../src/ImplModulePath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as RelativeModulePath from \"./RelativeModulePath.js\";\n\nexport const ImplModulePath = RelativeModulePath.withSuffix(\".impl.ts\").pipe(\n Schema.brand(\"@confect/cli/ImplModulePath\"),\n);\n\nexport type ImplModulePath = typeof ImplModulePath.Type;\n"],"mappings":";;;AAGA,MAAa,iBAAiBA,WAA8B,UAAU,CAAC,CAAC,KACtE,OAAO,MAAM,6BAA6B,CAC5C"}
@@ -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();
@@ -49,7 +49,7 @@ const groupPathFromRelativeModulePath = Effect.fnUntraced(function* (relativePat
49
49
  });
50
50
  const specImportPathFromGenerated = Effect.fnUntraced(function* (specRelativePath) {
51
51
  const path = yield* Path.Path;
52
- return `../${toPosixPath(path, yield* removePathExtension(specRelativePath))}`;
52
+ return `../${toPosixPath(path, yield* removePathExtension(specRelativePath))}.js`;
53
53
  });
54
54
  const specPathForImpl = (implRelativePath) => swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);
55
55
  const implPathForSpec = (specRelativePath) => swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);
@@ -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\";\nimport * as Bundler from \"./Bundler\";\nimport {\n MissingImplFileError,\n MissingSpecFileError,\n ImplMissingDefaultLayerError,\n ImplMissingFunctionsError,\n ImplMissingMiddlewareError,\n ImplMissingSpecImportError,\n ImplNotFinalizedError,\n InvalidMiddlewareAttachmentError,\n SpecImportsServerError,\n SpecMissingDefaultGroupSpecError,\n} from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { ImplModulePath } from \"./ImplModulePath\";\nimport { removePathExtension, toPosixPath } from \"./utils\";\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}`;\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":";;;;;;;;;;;;;;;;;;;;;AA6CA,MAAM,mBAAmB,MAAM,QAA0B;AAEzD,MAAM,yBAAyB;AAE/B,MAAa,cAAc;AAC3B,MAAa,cAAc;AAE3B,MAAM,mBAAmB,OAAO,WAAW,WACzC,cACA,YACA,UACA;CACA,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,YAAY;CAClD,IAAI,QAAQ,SAAS,CAAC,KAAK,SAAS,WAAW,MAAM,GAAG,EAAa,CAAC,GACpE,OAAO;CAIT,MAAM,WAAW,GADJ,KAAK,MAAM,GAAG,CAAC,WAAW,MAAM,GAAG,EAAa,CAAC,CAAC,MACxC,IAAI,SAAS,MAAM,GAAG,EAAa;CAC1D,OAAO,IAAI,SAAS,IAChB,KAAK,KAAK,KAAK,GAAG,WAAW,KAAK,IAClC,GAAG,WAAW;AACpB,CAAC;AAED,MAAa,kBAAkB,iBAC7B,aAAa,SAAS,WAAW;AAEnC,MAAa,2BAA2B,OAAO,WAAW,WACxD,cACA;CAEA,MAAM,EAAE,MAAM,SAAQ,OADF,KAAK,KAAA,CACE,MAAM,YAAY;CAC7C,IAAI,QAAQ,OACV,OAAO;CAET,OAAO,KAAK,SAAS,OAAO,IAAI,KAAK,MAAM,GAAG,EAAe,IAAI;AACnE,CAAC;AAED,MAAa,kCAAkC,OAAO,WAAW,WAC/D,cACA;CACA,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,YAAY;CAClD,MAAM,OACJ,QAAQ,SAAS,KAAK,SAAS,OAAO,IAClC,KAAK,MAAM,GAAG,EAAe,IAC7B;CACN,MAAM,cAAc,MAAM,OACxB,OAAO,MAAM,KAAK,KAAK,GAAG,GAC1B,OAAO,UACT;CACA,MAAM,eAAe,MAAM,OAAO,aAAa,IAAI;CACnD,OAAO;EACL;EACA,cAAc,MAAM,KAAK,cAAc,GAAG;CAC5C;AACF,CAAC;AAED,MAAa,8BAA8B,OAAO,WAAW,WAC3D,kBACA;CACA,MAAM,OAAO,OAAO,KAAK;CAKzB,OAAO,MAJY,YACjB,MACA,OAAO,oBAAoB,gBAAgB,CAEvB;AACxB,CAAC;AAED,MAAa,mBAAmB,qBAC9B,iBAAiB,kBAAkB,aAAa,WAAW;AAE7D,MAAa,mBAAmB,qBAC9B,iBAAiB,kBAAkB,aAAa,WAAW;AAE7D,MAAa,kCAAkC,OAAO,WAAW,WAC/D,MACA;CAEA,QAAO,OADa,KAAK,KAAA,CACb,KAAK,uBAAuB,GAAG,KAAK,YAAY,IAAI;AAClE,CAAC;AAED,MAAa,wBAAwB,OAAO,IAAI,aAAa;CAC3D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,eAAe,QAAQ,KAAK,cAAc,UAAU,YAAY;CACtE,MAAM,gBAAgB,QAAQ,KAAK,eAAe,SAAS;CAE3D,MAAM,WAAW,OAAO,GAAG,cAAc,kBAAkB,EACzD,WAAW,KACb,CAAC;CAED,OAAO,MAAM,OAAO,WAAW,iBAAiB;EAC9C,IAAI,CAAC,eAAe,YAAY,GAC9B,OAAO;EAGT,IAAI,QAAQ,IAAI,eAAe,YAAY,GACzC,OAAO;EAGT,MAAM,WAAW,OAAO,MAAM,cAAc,KAAK,GAAG;EACpD,OAAO,CAAC,MAAM,KAAK,WAAW,YAC5B,QAAQ,IAAI,cAAc,OAAO,CACnC;CACF,CAAC;AACH,CAAC;AAED,MAAa,wBAAwB,OAAO,IAAI,aAAa;CAC3D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,eAAe,QAAQ,KAAK,cAAc,UAAU,YAAY;CAEtE,MAAM,WAAW,OAAO,GAAG,cAAc,kBAAkB,EACzD,WAAW,KACb,CAAC;CAED,OAAO,MAAM,OACX,MAAM,UAAU,WAAW,iBACzB,OAAO,aAAa,cAAc,CAAC,CAAC,YAAY,CAClD,IACC,iBAAiB;EAChB,MAAM,WAAW,OAAO,MAAM,cAAc,KAAK,GAAG;EACpD,OAAO,CAAC,MAAM,KAAK,WAAW,YAC5B,QAAQ,IAAI,cAAc,OAAO,CACnC;CACF,CACF;AACF,CAAC;AAED,MAAa,eAAe,OAAO,WAAW,WAC5C,kBACA;CACA,MAAM,aAAa,OAAO,yBAAyB,gBAAgB;CACnE,MAAM,EAAE,cAAc,iBACpB,OAAO,gCAAgC,gBAAgB;CAGzD,OAAO;EACL,cAAc;EACd;EACA;EACA;EACA,gBAAA,OAP4B,4BAA4B,gBAAgB;CAQ1E;AACF,CAAC;AAED,MAAM,qBAAqB,OAAO,WAAW,WAAW,cAAsB;CAC5E,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,QAAO,OADa,KAAK,KAAA,CACb,QAAQ,kBAAkB,YAAY;AACpD,CAAC;;;;;;;;;;;;;;;;;;AAmBD,MAAM,uBAAuB,OAAO,WAAW,WAC7C,MACA,SACA;CACA,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,KAAK,QAAQ,OAAO,iBAAiB,GAAG;CAEjE,MAAM,uBAAuB,iBAAyB;EACpD,MAAM,WAAW,KAAK,SAAS,kBAAkB,YAAY;EAC7D,OAAO,CAAC,SAAS,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,QAAQ;CAChE;CAEA,MAAM,YAAYA,mBAChB,SACA,mBACA,mBACF;CAEA,IAAI,UAAU,SAAS,GACrB,OAAO,OAAO,IAAI,uBAAuB;EACvC,UAAU,KAAK;EACf,eAAe,MAAM,IAAI,YAAY,iBACnC,YAAY,MAAM,KAAK,SAAS,kBAAkB,YAAY,CAAC,CACjE;CACF,CAAC;AAEL,CAAC;;;;;;;;AASD,MAAa,WAAW,OAAO,GAAG,qBAAqB,CAAC,CAAC,WACvD,MACA;CACA,MAAM,eAAe,OAAO,mBAAmB,KAAK,YAAY;CAChE,MAAM,UAAU,OAAOC,OAAe,YAAY,CAAC,CAAC,KAClD,OAAO,UAAU,UAAU,iBAAiB,KAAK,cAAc,KAAK,CAAC,CACvE;CAEA,MAAM,YAAY,QAAQ,OAAO;CAEjC,IAAI,CAAC,UAAU,YAAY,SAAS,GAClC,OAAO,OAAO,IAAI,iCAAiC,EACjD,UAAU,KAAK,aACjB,CAAC;CAGH,OAAO,qBAAqB,MAAM,OAAO;CAEzC,OAAO,OAAO,WAAW,UAAU,mBAAmB,SAAS,CAAC,CAAC,CAAC,KAChE,OAAO,UACJ,UACC,IAAI,iCAAiC;EACnC,UAAU,KAAK;EACf,SAAS,qBAAqB,sBAAsB,KAAK;CAC3D,CAAC,CACL,CACF;CAEA,OAAO,iBAAiB;EACtB,GAAG;EACH,MAAM;CACR,CAAC;AACH,CAAC;;;;;;AAOD,MAAM,0BACJ,YAEA,MAAM,UAAU,QAAQ,UAAU,OAAO,GAAG,UAAU,oBAAoB;;;;;;;;;AAU5E,MAAM,iBAAiB,OAAO,WAAW,WACvC,WACA;CACA,MAAM,WAAW,IAAI,WAAwC,CAAC,CAAC;CAC/D,OAAO,OAAO,MAAM,MAClB,SACF,CAAC,CAAC,KAAK,OAAO,eAAe,SAAS,UAAU,QAAQ,CAAC;AAC3D,GAAG,OAAO,MAAM;;;;;;AAOhB,MAAa,eAAe,OAAO,GAAG,yBAAyB,CAAC,CAAC,WAC/D,MACA;CACA,MAAM,mBAAmB,OAAO,gBAAgB,KAAK,YAAY;CACjE,MAAM,mBAAmB,OAAO,mBAAmB,gBAAgB;CACnE,MAAM,mBAAmB,OAAO,mBAAmB,KAAK,YAAY;CAEpE,MAAM,UAAU,OAAOA,OAAe,gBAAgB,CAAC,CAAC,KACtD,OAAO,UAAU,UAAU,iBAAiB,kBAAkB,KAAK,CAAC,CACtE;CAEA,IACE,EAAE,OAAOC,gBACP,SACA,kBACA,gBACF,IAEA,OAAO,OAAO,IAAI,2BAA2B;EAC3C,UAAU;EACV,kBAAkB,KAAK;CACzB,CAAC;CAGH,IAAI,CAAC,MAAM,QAAQ,QAAQ,OAAO,OAAO,GACvC,OAAO,OAAO,IAAI,6BAA6B,EAC7C,UAAU,iBACZ,CAAC;CAGH,MAAM,YAAY,KAAK;CACvB,MAAM,wBAAwB,OAAO,KAAK,UAAU,SAAS;CAE7D,MAAM,UAAU,OAAO,eACrB,QAAQ,OAAO,OACjB;CACA,MAAM,qBAAqB,OAAO,OAAO,MACvC,uBAAuB,OAAO,GAC9B;EACE,cAAc,IAAI,sBAAsB,EAAE,UAAU,iBAAiB,CAAC;EACtE,QAAQ,OAAO;CACjB,CACF;CAEA,MAAM,gBAAgB,QAAQ,aAC5B,mBAAmB,uBACrB;CACA,MAAM,UAAU,sBAAsB,QACnC,SAAS,CAAC,QAAQ,IAAI,eAAe,IAAI,CAC5C;CAEA,IAAI,QAAQ,SAAS,GACnB,OAAO,OAAO,IAAI,0BAA0B;EAC1C,UAAU;EACV,WAAW,KAAK;EAChB,sBAAsB;CACxB,CAAC;CAGH,MAAM,yBAAyB,MAAM,OAAO,CAC1C,IAAI,UAAU,mBAAmB,CAAC,EAAA,CAAG,KAClC,mBAAmB,eAAe,GACrC,GACA,GAAG,OAAO,OAAO,UAAU,SAAS,CAAC,CAAC,SAAS,eAC5C,UAAU,mBAAmB,CAAC,EAAA,CAAG,KAC/B,mBAAmB,eAAe,GACrC,CACF,CACF,CAAC;CACD,MAAM,2BAA2B,QAAQ,aACvC,mBAAmB,4BAA4B,CAAC,CAClD;CACA,MAAM,oBAAoB,MAAM,OAC9B,yBACC,QAAQ,CAAC,QAAQ,IAAI,0BAA0B,GAAG,CACrD;CAEA,IAAI,kBAAkB,SAAS,GAC7B,OAAO,OAAO,IAAI,2BAA2B;EAC3C,UAAU;EACV,WAAW,KAAK;EAChB,uBAAuB;CACzB,CAAC;AAEL,CAAC;AAED,MAAa,gBAAgB,OAAO,WAAW,WAC7C,eACA,KACA;CACA,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,QAAQ,OAAO,OAAO,QAAQ,gBAAgB,qBAClD,gBAAgB,gBAAgB,CAAC,CAAC,KAChC,OAAO,KAAK,sBAAsB;EAChC;EACA;CACF,EAAE,CACJ,CACF;CAEA,OAAO,OAAOC,UACZ,MAAM,SAAS,EAAE,kBAAkB,uBAAuB,CACxD,KAAK,QAAQ,kBAAkB,gBAAgB,GAC/C,KAAK,QAAQ,kBAAkB,gBAAgB,CACjD,CAAC,GACD,OAAO,IAAI,aAAa;EAyBtB,OAAO,OAAO,IAAI,OAxBI,OAAO,QAC3B,OACA,OAAO,WAAW,WAAW,EAAE,kBAAkB,oBAAoB;GACnE,IACE,EAAE,OAAO,GAAG,OAAO,KAAK,KAAK,kBAAkB,gBAAgB,CAAC,IAEhE,OAAO,OAAO,IAAI,qBAAqB;IACrC,UAAU;IACV,kBAAkB;GACpB,CAAC;GAEH,IACE,EAAE,OAAO,GAAG,OAAO,KAAK,KAAK,kBAAkB,gBAAgB,CAAC,IAEhE,OAAO,OAAO,IAAI,qBAAqB;IACrC,UAAU;IACV,kBAAkB;GACpB,CAAC;GAGH,OAAO,OADa,SAAS,OAAO,aAAa,gBAAgB,CAAC;EAEpE,CAAC,GACD,EAAE,aAAa,uBAAuB,CACxC,CACwB;CAC1B,CAAC,CACH;AACF,CAAC;AAED,MAAa,oBAAoB,OAAO,GAAG,8BAA8B,CAAC,EACvE,kBACC,cAAc,eAAe,gBAAgB,CACjD;AAEA,MAAa,mBAAmB,OAAO,WAAW,WAChD,QACA;CACA,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,sBAAsB,OAAO,OAAO,QACxC,SACC,EAAE,mBACD,gBAAgB,YAAY,CAAC,CAAC,KAC5B,OAAO,KAAK,aAAa,KAAK,QAAQ,kBAAkB,QAAQ,CAAC,CACnE,CACJ;CACA,OAAOA,UACL,qBACA,OAAO,QAAQ,QAAQ,cAAc;EACnC,aAAa;EACb,SAAS;CACX,CAAC,CACH;AACF,CAAC;AAED,MAAa,UAAU,OAAO,IAAI,aAAa;CAC7C,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,YAAY,OAAO;CAEzB,MAAM,UAAU,OAAOA,UACrB,UAAU,KAAK,iBACb,KAAK,QAAQ,kBAAkB,YAAY,CAC7C,GACA,OAAO,QACL,WACA,OAAO,WAAW,WAAW,kBAA0B;EACrD,MAAM,aAAa,OAAO,aAAa,gBAAgB;EACvD,MAAM,OAAO,OAAO,SAAS,UAAU;EAEvC,MAAM,mBAAmB,OAAO,gBAAgB,gBAAgB;EAChE,MAAM,mBAAmB,KAAK,KAAK,kBAAkB,gBAAgB;EACrE,IAAI,EAAE,OAAO,GAAG,OAAO,gBAAgB,IACrC,OAAO,OAAO,IAAI,qBAAqB;GACrC,UAAU;GACV,kBAAkB;EACpB,CAAC;EAGH,OAAO;CACT,CAAC,GACD,EAAE,aAAa,uBAAuB,CACxC,CACF;CAEA,OAAO,oBAAoB,SAAS;CAEpC,OAAO;AACT,CAAC;;;;;;;;;AAUD,MAAM,sBAAsB,OAAO,WAAW,WAC5C,WACA;CACA,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,YAAY,OAAO;CACzB,MAAM,YAAY,QAAQ,aAAa,SAAS;CAEhD,OAAO,OAAO,QACZ,WACA,OAAO,WAAW,WAAW,kBAA0B;EACrD,MAAM,mBAAmB,OAAO,gBAAgB,gBAAgB;EAChE,IAAI,QAAQ,IAAI,WAAW,gBAAgB,GACzC;EAGF,MAAM,mBAAmB,KAAK,KAAK,kBAAkB,gBAAgB;EACrE,IAAI,EAAE,OAAO,GAAG,OAAO,gBAAgB,IACrC,OAAO,OAAO,IAAI,qBAAqB;GACrC,UAAU;GACV,kBAAkB;EACpB,CAAC;CAEL,CAAC,CACH;AACF,CAAC"}
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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Remove.mjs","names":[],"sources":["../src/Remove.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Schedule from \"effect/Schedule\";\nimport { RemoveBusyError } from \"./CodegenError\";\n\nconst MAX_ATTEMPTS = 4;\n\nexport const remove = Effect.fn(\"Remove.remove\")(function* (path: string) {\n const fs = yield* FileSystem.FileSystem;\n yield* fs.remove(path, { recursive: true, force: true }).pipe(\n Effect.retry({\n while: (error) => error.reason._tag === \"Busy\",\n times: MAX_ATTEMPTS - 1,\n schedule: Schedule.exponential(\"25 millis\"),\n }),\n Effect.mapError((error) =>\n error.reason._tag === \"Busy\"\n ? new RemoveBusyError({ path, attempts: MAX_ATTEMPTS, cause: error })\n : error,\n ),\n );\n});\n"],"mappings":";;;;;AAKA,MAAM,eAAe;AAErB,MAAa,SAAS,OAAO,GAAG,eAAe,CAAC,CAAC,WAAW,MAAc;CAExE,QAAO,OADW,WAAW,WAAA,CACnB,OAAO,MAAM;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC,CAAC,CAAC,KACvD,OAAO,MAAM;EACX,QAAQ,UAAU,MAAM,OAAO,SAAS;EACxC,OAAO;EACP,UAAU,SAAS,YAAY,WAAW;CAC5C,CAAC,GACD,OAAO,UAAU,UACf,MAAM,OAAO,SAAS,SAClB,IAAI,gBAAgB;EAAE;EAAM,UAAU;EAAc,OAAO;CAAM,CAAC,IAClE,KACN,CACF;AACF,CAAC"}
1
+ {"version":3,"file":"Remove.mjs","names":[],"sources":["../src/Remove.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Schedule from \"effect/Schedule\";\nimport { RemoveBusyError } from \"./CodegenError.js\";\n\nconst MAX_ATTEMPTS = 4;\n\nexport const remove = Effect.fn(\"Remove.remove\")(function* (path: string) {\n const fs = yield* FileSystem.FileSystem;\n yield* fs.remove(path, { recursive: true, force: true }).pipe(\n Effect.retry({\n while: (error) => error.reason._tag === \"Busy\",\n times: MAX_ATTEMPTS - 1,\n schedule: Schedule.exponential(\"25 millis\"),\n }),\n Effect.mapError((error) =>\n error.reason._tag === \"Busy\"\n ? new RemoveBusyError({ path, attempts: MAX_ATTEMPTS, cause: error })\n : error,\n ),\n );\n});\n"],"mappings":";;;;;AAKA,MAAM,eAAe;AAErB,MAAa,SAAS,OAAO,GAAG,eAAe,CAAC,CAAC,WAAW,MAAc;CAExE,QAAO,OADW,WAAW,WAAA,CACnB,OAAO,MAAM;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC,CAAC,CAAC,KACvD,OAAO,MAAM;EACX,QAAQ,UAAU,MAAM,OAAO,SAAS;EACxC,OAAO;EACP,UAAU,SAAS,YAAY,WAAW;CAC5C,CAAC,GACD,OAAO,UAAU,UACf,MAAM,OAAO,SAAS,SAClB,IAAI,gBAAgB;EAAE;EAAM,UAAU;EAAc,OAAO;CAAM,CAAC,IAClE,KACN,CACF;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Rollback.mjs","names":[],"sources":["../src/Rollback.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport * as Schema from \"effect/Schema\";\nimport type * as Scope from \"effect/Scope\";\nimport { ComponentNodeGroupError, logCodegenError } from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { CONVEX_CONFIG_FILENAME } from \"./ConvexConfig\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\nimport { logFileRemoved, logWarn } from \"./log\";\nimport { remove } from \"./Remove\";\n\nconst isNodeGroupRejection = Schema.is(ComponentNodeGroupError);\n\n/**\n * Keep a component's previous generated output when generation rejects a Node\n * group. Specs can import bootstrap output, so generation writes it before\n * their runtimes are known. `duringRestore` pauses whatever watches the output\n * while it is replaced.\n */\nexport const preserveComponentOutput = <A, E, R>(\n generation: Effect.Effect<A, E, R>,\n duringRestore: Effect.Effect<void, never, Scope.Scope> = Effect.void,\n) =>\n Effect.gen(function* () {\n if ((yield* ConvexDirectory.target).kind === \"app\")\n return yield* generation;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const backupDirectory = yield* fs.makeTempDirectoryScoped();\n const configPath = path.join(\n yield* ConvexDirectory.get,\n CONVEX_CONFIG_FILENAME,\n );\n const snapshots = yield* Effect.forEach(\n [path.join(yield* ConfectDirectory.get, \"_generated\"), configPath],\n Effect.fnUntraced(function* (original, index) {\n const backup = path.join(backupDirectory, String(index));\n const existed = yield* fs.exists(original);\n if (existed) yield* fs.copy(original, backup);\n return { original, backup, existed };\n }),\n );\n const restore = (rejection: ComponentNodeGroupError) =>\n Effect.gen(function* () {\n yield* duringRestore;\n yield* Effect.forEach(snapshots, ({ original, backup, existed }) =>\n Effect.gen(function* () {\n if (\n existed &&\n original === configPath &&\n (yield* fs.exists(original)) &&\n (yield* fs.readFileString(original)) ===\n (yield* fs.readFileString(backup))\n ) {\n return;\n }\n if (yield* fs.exists(original)) {\n yield* remove(original);\n }\n if (existed) yield* fs.copy(backup, original);\n else yield* logFileRemoved(original);\n }),\n );\n yield* logWarn(\n \"Restored generated output after rejecting the Node group.\",\n );\n }).pipe(\n Effect.scoped,\n Effect.tapError(() => logCodegenError(rejection)),\n );\n return yield* generation.pipe(\n Effect.tapError((error) =>\n isNodeGroupRejection(error) ? restore(error) : Effect.void,\n ),\n );\n }).pipe(Effect.scoped);\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,uBAAuB,OAAO,GAAG,uBAAuB;;;;;;;AAQ9D,MAAa,2BACX,YACA,gBAAyD,OAAO,SAEhE,OAAO,IAAI,aAAa;CACtB,KAAK,OAAO,gBAAgB,OAAA,CAAQ,SAAS,OAC3C,OAAO,OAAO;CAChB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,GAAG,wBAAwB;CAC1D,MAAM,aAAa,KAAK,KACtB,OAAO,gBAAgB,KACvB,sBACF;CACA,MAAM,YAAY,OAAO,OAAO,QAC9B,CAAC,KAAK,KAAK,OAAO,iBAAiB,KAAK,YAAY,GAAG,UAAU,GACjE,OAAO,WAAW,WAAW,UAAU,OAAO;EAC5C,MAAM,SAAS,KAAK,KAAK,iBAAiB,OAAO,KAAK,CAAC;EACvD,MAAM,UAAU,OAAO,GAAG,OAAO,QAAQ;EACzC,IAAI,SAAS,OAAO,GAAG,KAAK,UAAU,MAAM;EAC5C,OAAO;GAAE;GAAU;GAAQ;EAAQ;CACrC,CAAC,CACH;CACA,MAAM,WAAW,cACf,OAAO,IAAI,aAAa;EACtB,OAAO;EACP,OAAO,OAAO,QAAQ,YAAY,EAAE,UAAU,QAAQ,cACpD,OAAO,IAAI,aAAa;GACtB,IACE,WACA,aAAa,eACZ,OAAO,GAAG,OAAO,QAAQ,OACzB,OAAO,GAAG,eAAe,QAAQ,QAC/B,OAAO,GAAG,eAAe,MAAM,IAElC;GAEF,IAAI,OAAO,GAAG,OAAO,QAAQ,GAC3B,OAAO,OAAO,QAAQ;GAExB,IAAI,SAAS,OAAO,GAAG,KAAK,QAAQ,QAAQ;QACvC,OAAO,eAAe,QAAQ;EACrC,CAAC,CACH;EACA,OAAO,QACL,2DACF;CACF,CAAC,CAAC,CAAC,KACD,OAAO,QACP,OAAO,eAAe,gBAAgB,SAAS,CAAC,CAClD;CACF,OAAO,OAAO,WAAW,KACvB,OAAO,UAAU,UACf,qBAAqB,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,IACxD,CACF;AACF,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM"}
1
+ {"version":3,"file":"Rollback.mjs","names":[],"sources":["../src/Rollback.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport * as Schema from \"effect/Schema\";\nimport type * as Scope from \"effect/Scope\";\nimport { ComponentNodeGroupError, logCodegenError } from \"./CodegenError.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { CONVEX_CONFIG_FILENAME } from \"./ConvexConfig.js\";\nimport { ConvexDirectory } from \"./ConvexDirectory.js\";\nimport { logFileRemoved, logWarn } from \"./log.js\";\nimport { remove } from \"./Remove.js\";\n\nconst isNodeGroupRejection = Schema.is(ComponentNodeGroupError);\n\n/**\n * Keep a component's previous generated output when generation rejects a Node\n * group. Specs can import bootstrap output, so generation writes it before\n * their runtimes are known. `duringRestore` pauses whatever watches the output\n * while it is replaced.\n */\nexport const preserveComponentOutput = <A, E, R>(\n generation: Effect.Effect<A, E, R>,\n duringRestore: Effect.Effect<void, never, Scope.Scope> = Effect.void,\n) =>\n Effect.gen(function* () {\n if ((yield* ConvexDirectory.target).kind === \"app\")\n return yield* generation;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const backupDirectory = yield* fs.makeTempDirectoryScoped();\n const configPath = path.join(\n yield* ConvexDirectory.get,\n CONVEX_CONFIG_FILENAME,\n );\n const snapshots = yield* Effect.forEach(\n [path.join(yield* ConfectDirectory.get, \"_generated\"), configPath],\n Effect.fnUntraced(function* (original, index) {\n const backup = path.join(backupDirectory, String(index));\n const existed = yield* fs.exists(original);\n if (existed) yield* fs.copy(original, backup);\n return { original, backup, existed };\n }),\n );\n const restore = (rejection: ComponentNodeGroupError) =>\n Effect.gen(function* () {\n yield* duringRestore;\n yield* Effect.forEach(snapshots, ({ original, backup, existed }) =>\n Effect.gen(function* () {\n if (\n existed &&\n original === configPath &&\n (yield* fs.exists(original)) &&\n (yield* fs.readFileString(original)) ===\n (yield* fs.readFileString(backup))\n ) {\n return;\n }\n if (yield* fs.exists(original)) {\n yield* remove(original);\n }\n if (existed) yield* fs.copy(backup, original);\n else yield* logFileRemoved(original);\n }),\n );\n yield* logWarn(\n \"Restored generated output after rejecting the Node group.\",\n );\n }).pipe(\n Effect.scoped,\n Effect.tapError(() => logCodegenError(rejection)),\n );\n return yield* generation.pipe(\n Effect.tapError((error) =>\n isNodeGroupRejection(error) ? restore(error) : Effect.void,\n ),\n );\n }).pipe(Effect.scoped);\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,uBAAuB,OAAO,GAAG,uBAAuB;;;;;;;AAQ9D,MAAa,2BACX,YACA,gBAAyD,OAAO,SAEhE,OAAO,IAAI,aAAa;CACtB,KAAK,OAAO,gBAAgB,OAAA,CAAQ,SAAS,OAC3C,OAAO,OAAO;CAChB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,GAAG,wBAAwB;CAC1D,MAAM,aAAa,KAAK,KACtB,OAAO,gBAAgB,KACvB,sBACF;CACA,MAAM,YAAY,OAAO,OAAO,QAC9B,CAAC,KAAK,KAAK,OAAO,iBAAiB,KAAK,YAAY,GAAG,UAAU,GACjE,OAAO,WAAW,WAAW,UAAU,OAAO;EAC5C,MAAM,SAAS,KAAK,KAAK,iBAAiB,OAAO,KAAK,CAAC;EACvD,MAAM,UAAU,OAAO,GAAG,OAAO,QAAQ;EACzC,IAAI,SAAS,OAAO,GAAG,KAAK,UAAU,MAAM;EAC5C,OAAO;GAAE;GAAU;GAAQ;EAAQ;CACrC,CAAC,CACH;CACA,MAAM,WAAW,cACf,OAAO,IAAI,aAAa;EACtB,OAAO;EACP,OAAO,OAAO,QAAQ,YAAY,EAAE,UAAU,QAAQ,cACpD,OAAO,IAAI,aAAa;GACtB,IACE,WACA,aAAa,eACZ,OAAO,GAAG,OAAO,QAAQ,OACzB,OAAO,GAAG,eAAe,QAAQ,QAC/B,OAAO,GAAG,eAAe,MAAM,IAElC;GAEF,IAAI,OAAO,GAAG,OAAO,QAAQ,GAC3B,OAAO,OAAO,QAAQ;GAExB,IAAI,SAAS,OAAO,GAAG,KAAK,QAAQ,QAAQ;QACvC,OAAO,eAAe,QAAQ;EACrC,CAAC,CACH;EACA,OAAO,QACL,2DACF;CACF,CAAC,CAAC,CAAC,KACD,OAAO,QACP,OAAO,eAAe,gBAAgB,SAAS,CAAC,CAClD;CACF,OAAO,OAAO,WAAW,KACvB,OAAO,UAAU,UACf,qBAAqB,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,IACxD,CACF;AACF,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"SpecAssemblyNode.mjs","names":[],"sources":["../src/SpecAssemblyNode.ts"],"sourcesContent":["import type { LeafModule } from \"./LeafModule\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter\";\nimport * as Option from \"effect/Option\";\nimport * as Order from \"effect/Order\";\nimport * as Record from \"effect/Record\";\n\nexport interface SpecImportBinding {\n readonly importPath: string;\n readonly exportName: string;\n readonly localName: string;\n}\n\nexport interface SpecAssemblyNode {\n readonly segment: string;\n readonly importBinding: Option.Option<SpecImportBinding>;\n readonly children: ReadonlyArray<SpecAssemblyNode>;\n}\n\nconst importBindingFromLeaf = (leaf: LeafModule): SpecImportBinding => ({\n importPath: leaf.specImportPath,\n exportName: leaf.exportName,\n localName: Array.join(leaf.pathSegments, \"_\"),\n});\n\nconst assemblyNodesAtDepth = (\n leaves: ReadonlyArray<LeafModule>,\n depth: number,\n): ReadonlyArray<SpecAssemblyNode> =>\n pipe(\n Array.groupBy(leaves, (leaf) => leaf.pathSegments[depth]!),\n Record.toEntries,\n Array.sortBy(Order.mapInput(Order.String, ([segment]) => segment)),\n Array.map(([segment, groupLeaves]) => {\n const terminal = Array.findFirst(\n groupLeaves,\n (leaf) => leaf.pathSegments.length === depth + 1,\n );\n const descendants = Array.filter(\n groupLeaves,\n (leaf) => leaf.pathSegments.length > depth + 1,\n );\n return {\n segment,\n importBinding: Option.map(terminal, importBindingFromLeaf),\n children: assemblyNodesAtDepth(descendants, depth + 1),\n };\n }),\n );\n\nexport const assemblyNodesFromLeaves = (\n leaves: ReadonlyArray<LeafModule>,\n): ReadonlyArray<SpecAssemblyNode> => assemblyNodesAtDepth(leaves, 0);\n\nconst importBindingsForNode = (\n node: SpecAssemblyNode,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(node.children, Array.flatMap(importBindingsForNode), (childBindings) =>\n Option.match(node.importBinding, {\n onNone: () => childBindings,\n onSome: (binding) => Array.prepend(childBindings, binding),\n }),\n );\n\nexport const collectImportBindings = (\n nodes: ReadonlyArray<SpecAssemblyNode>,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(\n Array.flatMap(nodes, importBindingsForNode),\n (bindings) =>\n Record.fromIterableBy(bindings, (binding) => binding.importPath),\n Record.toEntries,\n Array.map(([, binding]) => binding),\n Array.sortBy(Order.mapInput(Order.String, (binding) => binding.localName)),\n );\n\nconst writeGroupEntry = Effect.fnUntraced(function* (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n): Effect.fn.Return<void> {\n yield* cbw.write(\"[\");\n yield* cbw.quote(node.segment);\n yield* cbw.write(\"]: \");\n yield* writeGroupAssembly(cbw, node);\n yield* cbw.write(\",\\n\");\n});\n\nconst writeGroupAssembly: (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n) => Effect.Effect<void> = Effect.fnUntraced(function* (cbw, node) {\n const group = Option.match(node.importBinding, {\n onNone: () => \"GroupSpec.make()\",\n onSome: (binding) => binding.localName,\n });\n yield* Array.match(node.children, {\n onEmpty: () => cbw.write(group),\n onNonEmpty: (children) =>\n Effect.gen(function* () {\n yield* cbw.write(`GroupSpec.addGroupsAt(${group}, {\\n`);\n yield* cbw.indent(\n Effect.forEach(children, (child) => writeGroupEntry(cbw, child)),\n );\n yield* cbw.write(\"})\");\n }),\n });\n});\n\nconst groupTypeExpr = (node: SpecAssemblyNode): string =>\n Array.match(node.children, {\n onEmpty: () =>\n Option.match(node.importBinding, {\n onNone: () =>\n `GroupSpec.GroupSpec<\"Convex\", \"${node.segment}\", never, never>`,\n onSome: (binding) => `typeof ${binding.localName}`,\n }),\n onNonEmpty: (children) => {\n const childUnion = pipe(\n children,\n Array.map(rootGroupTypeMember),\n Array.join(\" | \"),\n );\n return Option.match(node.importBinding, {\n onNone: () =>\n `GroupSpec.GroupSpec<\"Convex\", \"${node.segment}\", never, ${childUnion}>`,\n onSome: (binding) =>\n `GroupSpec.AddGroups<typeof ${binding.localName}, ${childUnion}>`,\n });\n },\n });\n\nconst rootGroupTypeMember = (node: SpecAssemblyNode): string =>\n `GroupSpec.NamedAt<${groupTypeExpr(node)}, \"${node.segment}\">`;\n\nexport const render = Effect.fnUntraced(function* (\n nodes: ReadonlyArray<SpecAssemblyNode>,\n) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(\n Array.match(nodes, {\n onEmpty: () => `import { Spec } from \"@confect/core\";`,\n onNonEmpty: () => `import { GroupSpec, Spec } from \"@confect/core\";`,\n }),\n );\n\n yield* Effect.forEach(collectImportBindings(nodes), (binding) =>\n cbw.writeLine(`import ${binding.localName} from \"${binding.importPath}\";`),\n );\n\n yield* cbw.blankLine();\n\n yield* cbw.write(\"const spec: \");\n yield* Array.match(nodes, {\n onEmpty: () => cbw.write(\"Spec.Spec\"),\n onNonEmpty: (nonEmptyNodes) =>\n Effect.gen(function* () {\n yield* cbw.write(\"Spec.Spec<{\\n\");\n yield* cbw.indent(\n Effect.forEach(nonEmptyNodes, (node) =>\n cbw.writeLine(\n `readonly ${node.segment}: ${rootGroupTypeMember(node)};`,\n ),\n ),\n );\n yield* cbw.write(\"}>\");\n }),\n });\n yield* cbw.write(\" = Spec.fromGroups({\\n\");\n yield* cbw.indent(\n Effect.forEach(nodes, (node) => writeGroupEntry(cbw, node)),\n );\n yield* cbw.writeLine(\"}) as typeof spec;\");\n yield* cbw.blankLine();\n yield* cbw.writeLine(`export default spec;`);\n\n return yield* cbw.toString();\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"SpecAssemblyNode.mjs","names":[],"sources":["../src/SpecAssemblyNode.ts"],"sourcesContent":["import type { LeafModule } from \"./LeafModule.js\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter.js\";\nimport * as Option from \"effect/Option\";\nimport * as Order from \"effect/Order\";\nimport * as Record from \"effect/Record\";\n\nexport interface SpecImportBinding {\n readonly importPath: string;\n readonly exportName: string;\n readonly localName: string;\n}\n\nexport interface SpecAssemblyNode {\n readonly segment: string;\n readonly importBinding: Option.Option<SpecImportBinding>;\n readonly children: ReadonlyArray<SpecAssemblyNode>;\n}\n\nconst importBindingFromLeaf = (leaf: LeafModule): SpecImportBinding => ({\n importPath: leaf.specImportPath,\n exportName: leaf.exportName,\n localName: Array.join(leaf.pathSegments, \"_\"),\n});\n\nconst assemblyNodesAtDepth = (\n leaves: ReadonlyArray<LeafModule>,\n depth: number,\n): ReadonlyArray<SpecAssemblyNode> =>\n pipe(\n Array.groupBy(leaves, (leaf) => leaf.pathSegments[depth]!),\n Record.toEntries,\n Array.sortBy(Order.mapInput(Order.String, ([segment]) => segment)),\n Array.map(([segment, groupLeaves]) => {\n const terminal = Array.findFirst(\n groupLeaves,\n (leaf) => leaf.pathSegments.length === depth + 1,\n );\n const descendants = Array.filter(\n groupLeaves,\n (leaf) => leaf.pathSegments.length > depth + 1,\n );\n return {\n segment,\n importBinding: Option.map(terminal, importBindingFromLeaf),\n children: assemblyNodesAtDepth(descendants, depth + 1),\n };\n }),\n );\n\nexport const assemblyNodesFromLeaves = (\n leaves: ReadonlyArray<LeafModule>,\n): ReadonlyArray<SpecAssemblyNode> => assemblyNodesAtDepth(leaves, 0);\n\nconst importBindingsForNode = (\n node: SpecAssemblyNode,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(node.children, Array.flatMap(importBindingsForNode), (childBindings) =>\n Option.match(node.importBinding, {\n onNone: () => childBindings,\n onSome: (binding) => Array.prepend(childBindings, binding),\n }),\n );\n\nexport const collectImportBindings = (\n nodes: ReadonlyArray<SpecAssemblyNode>,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(\n Array.flatMap(nodes, importBindingsForNode),\n (bindings) =>\n Record.fromIterableBy(bindings, (binding) => binding.importPath),\n Record.toEntries,\n Array.map(([, binding]) => binding),\n Array.sortBy(Order.mapInput(Order.String, (binding) => binding.localName)),\n );\n\nconst writeGroupEntry = Effect.fnUntraced(function* (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n): Effect.fn.Return<void> {\n yield* cbw.write(\"[\");\n yield* cbw.quote(node.segment);\n yield* cbw.write(\"]: \");\n yield* writeGroupAssembly(cbw, node);\n yield* cbw.write(\",\\n\");\n});\n\nconst writeGroupAssembly: (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n) => Effect.Effect<void> = Effect.fnUntraced(function* (cbw, node) {\n const group = Option.match(node.importBinding, {\n onNone: () => \"GroupSpec.make()\",\n onSome: (binding) => binding.localName,\n });\n yield* Array.match(node.children, {\n onEmpty: () => cbw.write(group),\n onNonEmpty: (children) =>\n Effect.gen(function* () {\n yield* cbw.write(`GroupSpec.addGroupsAt(${group}, {\\n`);\n yield* cbw.indent(\n Effect.forEach(children, (child) => writeGroupEntry(cbw, child)),\n );\n yield* cbw.write(\"})\");\n }),\n });\n});\n\nconst groupTypeExpr = (node: SpecAssemblyNode): string =>\n Array.match(node.children, {\n onEmpty: () =>\n Option.match(node.importBinding, {\n onNone: () =>\n `GroupSpec.GroupSpec<\"Convex\", \"${node.segment}\", never, never>`,\n onSome: (binding) => `typeof ${binding.localName}`,\n }),\n onNonEmpty: (children) => {\n const childUnion = pipe(\n children,\n Array.map(rootGroupTypeMember),\n Array.join(\" | \"),\n );\n return Option.match(node.importBinding, {\n onNone: () =>\n `GroupSpec.GroupSpec<\"Convex\", \"${node.segment}\", never, ${childUnion}>`,\n onSome: (binding) =>\n `GroupSpec.AddGroups<typeof ${binding.localName}, ${childUnion}>`,\n });\n },\n });\n\nconst rootGroupTypeMember = (node: SpecAssemblyNode): string =>\n `GroupSpec.NamedAt<${groupTypeExpr(node)}, \"${node.segment}\">`;\n\nexport const render = Effect.fnUntraced(function* (\n nodes: ReadonlyArray<SpecAssemblyNode>,\n) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(\n Array.match(nodes, {\n onEmpty: () => `import { Spec } from \"@confect/core\";`,\n onNonEmpty: () => `import { GroupSpec, Spec } from \"@confect/core\";`,\n }),\n );\n\n yield* Effect.forEach(collectImportBindings(nodes), (binding) =>\n cbw.writeLine(`import ${binding.localName} from \"${binding.importPath}\";`),\n );\n\n yield* cbw.blankLine();\n\n yield* cbw.write(\"const spec: \");\n yield* Array.match(nodes, {\n onEmpty: () => cbw.write(\"Spec.Spec\"),\n onNonEmpty: (nonEmptyNodes) =>\n Effect.gen(function* () {\n yield* cbw.write(\"Spec.Spec<{\\n\");\n yield* cbw.indent(\n Effect.forEach(nonEmptyNodes, (node) =>\n cbw.writeLine(\n `readonly ${node.segment}: ${rootGroupTypeMember(node)};`,\n ),\n ),\n );\n yield* cbw.write(\"}>\");\n }),\n });\n yield* cbw.write(\" = Spec.fromGroups({\\n\");\n yield* cbw.indent(\n Effect.forEach(nodes, (node) => writeGroupEntry(cbw, node)),\n );\n yield* cbw.writeLine(\"}) as typeof spec;\");\n yield* cbw.blankLine();\n yield* cbw.writeLine(`export default spec;`);\n\n return yield* cbw.toString();\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SpecModulePath.mjs","names":["RelativeModulePath.withSuffix"],"sources":["../src/SpecModulePath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport { ImplModulePath } from \"./ImplModulePath\";\nimport * as RelativeModulePath from \"./RelativeModulePath\";\n\nexport const SpecModulePath = RelativeModulePath.withSuffix(\".spec.ts\").pipe(\n Schema.brand(\"@confect/cli/SpecModulePath\"),\n);\n\nexport type SpecModulePath = typeof SpecModulePath.Type;\n\nexport const toImpl = (path: SpecModulePath): ImplModulePath =>\n ImplModulePath.make(`${path.slice(0, -\".spec.ts\".length)}.impl.ts`);\n\nexport const fromImpl = (path: ImplModulePath): SpecModulePath =>\n SpecModulePath.make(`${path.slice(0, -\".impl.ts\".length)}.spec.ts`);\n"],"mappings":";;;;AAIA,MAAa,iBAAiBA,WAA8B,UAAU,CAAC,CAAC,KACtE,OAAO,MAAM,6BAA6B,CAC5C;AAIA,MAAa,UAAU,SACrB,eAAe,KAAK,GAAG,KAAK,MAAM,GAAG,EAAkB,EAAE,SAAS"}
1
+ {"version":3,"file":"SpecModulePath.mjs","names":["RelativeModulePath.withSuffix"],"sources":["../src/SpecModulePath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport { ImplModulePath } from \"./ImplModulePath.js\";\nimport * as RelativeModulePath from \"./RelativeModulePath.js\";\n\nexport const SpecModulePath = RelativeModulePath.withSuffix(\".spec.ts\").pipe(\n Schema.brand(\"@confect/cli/SpecModulePath\"),\n);\n\nexport type SpecModulePath = typeof SpecModulePath.Type;\n\nexport const toImpl = (path: SpecModulePath): ImplModulePath =>\n ImplModulePath.make(`${path.slice(0, -\".spec.ts\".length)}.impl.ts`);\n\nexport const fromImpl = (path: ImplModulePath): SpecModulePath =>\n SpecModulePath.make(`${path.slice(0, -\".impl.ts\".length)}.spec.ts`);\n"],"mappings":";;;;AAIA,MAAa,iBAAiBA,WAA8B,UAAU,CAAC,CAAC,KACtE,OAAO,MAAM,6BAA6B,CAC5C;AAIA,MAAa,UAAU,SACrB,eAAe,KAAK,GAAG,KAAK,MAAM,GAAG,EAAkB,EAAE,SAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"SyncState.mjs","names":[],"sources":["../src/SyncState.ts"],"sourcesContent":["import * as Array from \"effect/Array\";\nimport * as Data from \"effect/Data\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as HashMap from \"effect/HashMap\";\nimport * as Match from \"effect/Match\";\nimport type { Declaration, Kind, OptionalFile } from \"./EntryPoint\";\nimport type { ImplModulePath } from \"./ImplModulePath\";\nimport type { GenerationSnapshot } from \"./GenerationSnapshot\";\n\nexport type Work = Data.TaggedEnum<{\n None: {};\n Reconcile: {};\n Full: {};\n Impls: { readonly paths: Array.NonEmptyReadonlyArray<ImplModulePath> };\n Declarations: {\n readonly entries: Array.NonEmptyReadonlyArray<Declaration>;\n readonly paths: ReadonlyArray<ImplModulePath>;\n };\n}>;\nexport const Work = Data.taggedEnum<Work>();\n\nexport interface Pending {\n readonly work: Work;\n readonly optional: HashSet.HashSet<OptionalFile>;\n}\n\nexport const empty: Pending = { work: Work.None(), optional: HashSet.empty() };\nexport const isDirty = (pending: Pending): boolean =>\n !Work.$is(\"None\")(pending.work) || !HashSet.isEmpty(pending.optional);\nexport const full = (pending: Pending): Pending => ({\n ...pending,\n work: Work.Full(),\n});\n\nexport const reconcile = (pending: Pending): Pending => ({\n ...pending,\n work: Work.$is(\"None\")(pending.work) ? Work.Reconcile() : pending.work,\n});\n\nexport const add = (\n pending: Pending,\n entries: ReadonlyArray<Kind>,\n forceFull = false,\n): Pending => {\n const next = Array.reduce(\n entries,\n {\n needsFull: forceFull || Work.$is(\"Full\")(pending.work),\n paths: Work.$match(pending.work, {\n None: () => HashSet.empty<ImplModulePath>(),\n Reconcile: () => HashSet.empty<ImplModulePath>(),\n Full: () => HashSet.empty<ImplModulePath>(),\n Impls: ({ paths }) => HashSet.fromIterable(paths),\n Declarations: ({ paths }) => HashSet.fromIterable(paths),\n }),\n declarations: Work.$match(pending.work, {\n None: () => HashMap.empty<string, Declaration>(),\n Reconcile: () => HashMap.empty<string, Declaration>(),\n Full: () => HashMap.empty<string, Declaration>(),\n Impls: () => HashMap.empty<string, Declaration>(),\n Declarations: ({ entries: declarations }) =>\n HashMap.fromIterable(\n declarations.map(\n (entry) =>\n [`${entry._tag}:${entry.relativePath}`, entry] as const,\n ),\n ),\n }),\n optional: pending.optional,\n },\n (state, entry) =>\n Match.value(entry).pipe(\n Match.tag(\"Impl\", ({ relativePath }) => ({\n ...state,\n paths: HashSet.add(state.paths, relativePath),\n })),\n Match.tag(\"Http\", \"Crons\", \"Auth\", ({ _tag }) => ({\n ...state,\n optional: HashSet.add(state.optional, _tag),\n })),\n Match.tag(\"Spec\", \"Table\", (declaration) => ({\n ...state,\n declarations: HashMap.set(\n state.declarations,\n `${declaration._tag}:${declaration.relativePath}`,\n declaration,\n ),\n })),\n Match.tag(\"Config\", \"Env\", \"App\", \"Callbacks\", () => ({\n ...state,\n needsFull: true,\n })),\n Match.exhaustive,\n ),\n );\n const impls = Array.fromIterable(next.paths);\n const declarations = Array.fromIterable(HashMap.values(next.declarations));\n return {\n work: next.needsFull\n ? Work.Full()\n : Array.isReadonlyArrayNonEmpty(declarations)\n ? Work.Declarations({ entries: declarations, paths: impls })\n : Array.isReadonlyArrayNonEmpty(impls)\n ? Work.Impls({ paths: impls })\n : Work.$is(\"Reconcile\")(pending.work)\n ? Work.Reconcile()\n : Work.None(),\n optional: next.optional,\n };\n};\n\nexport interface Backend {\n readonly declared: boolean;\n readonly component: boolean;\n}\n\n/**\n * Full generation writes a declared backend's `convex/http.ts` and\n * `auth.config.ts` and rejects a component's `auth.ts`, so those edits need it\n * instead of the optional-file writers.\n */\nexport const forBackend = (pending: Pending, backend: Backend): Pending => {\n const generated = HashSet.filter(pending.optional, (file) =>\n Match.value(file).pipe(\n Match.when(\"Http\", () => backend.declared),\n Match.when(\"Auth\", () => backend.declared || backend.component),\n Match.when(\"Crons\", () => false),\n Match.exhaustive,\n ),\n );\n if (HashSet.isEmpty(generated)) return pending;\n return {\n work: Work.Full(),\n optional: backend.declared\n ? HashSet.difference(pending.optional, generated)\n : pending.optional,\n };\n};\n\nexport type Phase = Data.TaggedEnum<{\n Bootstrapping: {};\n NeedsFullSync: {};\n Incremental: {\n readonly failedImpls: HashSet.HashSet<ImplModulePath>;\n readonly snapshot: GenerationSnapshot;\n };\n}>;\nexport const Phase = Data.taggedEnum<Phase>();\n\nexport type Outcome = Data.TaggedEnum<{\n Succeeded: { readonly snapshot: GenerationSnapshot };\n GenerationFailed: {};\n ReconciliationFailed: {};\n ValidationFailed: {\n readonly snapshot: GenerationSnapshot;\n readonly paths: Array.NonEmptyReadonlyArray<ImplModulePath>;\n };\n}>;\nexport const Outcome = Data.taggedEnum<Outcome>();\n\nexport const transition = (outcome: Outcome): Phase =>\n Outcome.$match(outcome, {\n Succeeded: ({ snapshot }) =>\n Phase.Incremental({\n snapshot,\n failedImpls: HashSet.empty(),\n }),\n GenerationFailed: () => Phase.NeedsFullSync(),\n ReconciliationFailed: () => Phase.NeedsFullSync(),\n ValidationFailed: ({ snapshot, paths }) =>\n Phase.Incremental({\n snapshot,\n failedImpls: HashSet.fromIterable(paths),\n }),\n });\n\nexport const shouldRetry = (phase: Phase, outcome: Outcome): boolean =>\n Phase.$is(\"Bootstrapping\")(phase) && Outcome.$is(\"GenerationFailed\")(outcome);\n\nexport const needsDeploymentNotification = (phase: Phase): boolean =>\n Phase.$match(phase, {\n Bootstrapping: () => true,\n NeedsFullSync: () => true,\n Incremental: ({ failedImpls }) => !HashSet.isEmpty(failedImpls),\n });\n\nexport const implsToValidate = (\n phase: Phase,\n pending: Pending,\n): ReadonlyArray<ImplModulePath> =>\n Array.fromIterable(\n HashSet.union(\n Phase.$match(phase, {\n Bootstrapping: () => HashSet.empty<ImplModulePath>(),\n NeedsFullSync: () => HashSet.empty<ImplModulePath>(),\n Incremental: ({ failedImpls }) => failedImpls,\n }),\n Work.$match(pending.work, {\n None: () => HashSet.empty<ImplModulePath>(),\n Reconcile: () => HashSet.empty<ImplModulePath>(),\n Full: () => HashSet.empty<ImplModulePath>(),\n Impls: ({ paths }) => HashSet.fromIterable(paths),\n Declarations: ({ paths }) => HashSet.fromIterable(paths),\n }),\n ),\n );\n\nexport type Operation = Data.TaggedEnum<{\n Generate: {};\n Validate: {\n readonly snapshot: GenerationSnapshot;\n readonly paths: ReadonlyArray<ImplModulePath>;\n };\n Update: {\n readonly snapshot: GenerationSnapshot;\n readonly declarations: Array.NonEmptyReadonlyArray<Declaration>;\n readonly paths: ReadonlyArray<ImplModulePath>;\n };\n}>;\nexport const Operation = Data.taggedEnum<Operation>();\n\nexport const plan = (phase: Phase, pending: Pending): Operation =>\n Phase.$match(phase, {\n Bootstrapping: () => Operation.Generate(),\n NeedsFullSync: () => Operation.Generate(),\n Incremental: (ready) =>\n Match.value(pending.work).pipe(\n Match.tag(\"Full\", () => Operation.Generate()),\n Match.tag(\"None\", \"Reconcile\", \"Impls\", () =>\n Operation.Validate({\n snapshot: ready.snapshot,\n paths: implsToValidate(ready, pending),\n }),\n ),\n Match.tag(\"Declarations\", ({ entries }) =>\n Operation.Update({\n snapshot: ready.snapshot,\n declarations: entries,\n paths: implsToValidate(ready, pending),\n }),\n ),\n Match.exhaustive,\n ),\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"SyncState.mjs","names":[],"sources":["../src/SyncState.ts"],"sourcesContent":["import * as Array from \"effect/Array\";\nimport * as Data from \"effect/Data\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as HashMap from \"effect/HashMap\";\nimport * as Match from \"effect/Match\";\nimport type { Declaration, Kind, OptionalFile } from \"./EntryPoint.js\";\nimport type { ImplModulePath } from \"./ImplModulePath.js\";\nimport type { GenerationSnapshot } from \"./GenerationSnapshot.js\";\n\nexport type Work = Data.TaggedEnum<{\n None: {};\n Reconcile: {};\n Full: {};\n Impls: { readonly paths: Array.NonEmptyReadonlyArray<ImplModulePath> };\n Declarations: {\n readonly entries: Array.NonEmptyReadonlyArray<Declaration>;\n readonly paths: ReadonlyArray<ImplModulePath>;\n };\n}>;\nexport const Work = Data.taggedEnum<Work>();\n\nexport interface Pending {\n readonly work: Work;\n readonly optional: HashSet.HashSet<OptionalFile>;\n}\n\nexport const empty: Pending = { work: Work.None(), optional: HashSet.empty() };\nexport const isDirty = (pending: Pending): boolean =>\n !Work.$is(\"None\")(pending.work) || !HashSet.isEmpty(pending.optional);\nexport const full = (pending: Pending): Pending => ({\n ...pending,\n work: Work.Full(),\n});\n\nexport const reconcile = (pending: Pending): Pending => ({\n ...pending,\n work: Work.$is(\"None\")(pending.work) ? Work.Reconcile() : pending.work,\n});\n\nexport const add = (\n pending: Pending,\n entries: ReadonlyArray<Kind>,\n forceFull = false,\n): Pending => {\n const next = Array.reduce(\n entries,\n {\n needsFull: forceFull || Work.$is(\"Full\")(pending.work),\n paths: Work.$match(pending.work, {\n None: () => HashSet.empty<ImplModulePath>(),\n Reconcile: () => HashSet.empty<ImplModulePath>(),\n Full: () => HashSet.empty<ImplModulePath>(),\n Impls: ({ paths }) => HashSet.fromIterable(paths),\n Declarations: ({ paths }) => HashSet.fromIterable(paths),\n }),\n declarations: Work.$match(pending.work, {\n None: () => HashMap.empty<string, Declaration>(),\n Reconcile: () => HashMap.empty<string, Declaration>(),\n Full: () => HashMap.empty<string, Declaration>(),\n Impls: () => HashMap.empty<string, Declaration>(),\n Declarations: ({ entries: declarations }) =>\n HashMap.fromIterable(\n declarations.map(\n (entry) =>\n [`${entry._tag}:${entry.relativePath}`, entry] as const,\n ),\n ),\n }),\n optional: pending.optional,\n },\n (state, entry) =>\n Match.value(entry).pipe(\n Match.tag(\"Impl\", ({ relativePath }) => ({\n ...state,\n paths: HashSet.add(state.paths, relativePath),\n })),\n Match.tag(\"Http\", \"Crons\", \"Auth\", ({ _tag }) => ({\n ...state,\n optional: HashSet.add(state.optional, _tag),\n })),\n Match.tag(\"Spec\", \"Table\", (declaration) => ({\n ...state,\n declarations: HashMap.set(\n state.declarations,\n `${declaration._tag}:${declaration.relativePath}`,\n declaration,\n ),\n })),\n Match.tag(\"Config\", \"Env\", \"App\", \"Callbacks\", () => ({\n ...state,\n needsFull: true,\n })),\n Match.exhaustive,\n ),\n );\n const impls = Array.fromIterable(next.paths);\n const declarations = Array.fromIterable(HashMap.values(next.declarations));\n return {\n work: next.needsFull\n ? Work.Full()\n : Array.isReadonlyArrayNonEmpty(declarations)\n ? Work.Declarations({ entries: declarations, paths: impls })\n : Array.isReadonlyArrayNonEmpty(impls)\n ? Work.Impls({ paths: impls })\n : Work.$is(\"Reconcile\")(pending.work)\n ? Work.Reconcile()\n : Work.None(),\n optional: next.optional,\n };\n};\n\nexport interface Backend {\n readonly declared: boolean;\n readonly component: boolean;\n}\n\n/**\n * Full generation writes a declared backend's `convex/http.ts` and\n * `auth.config.ts` and rejects a component's `auth.ts`, so those edits need it\n * instead of the optional-file writers.\n */\nexport const forBackend = (pending: Pending, backend: Backend): Pending => {\n const generated = HashSet.filter(pending.optional, (file) =>\n Match.value(file).pipe(\n Match.when(\"Http\", () => backend.declared),\n Match.when(\"Auth\", () => backend.declared || backend.component),\n Match.when(\"Crons\", () => false),\n Match.exhaustive,\n ),\n );\n if (HashSet.isEmpty(generated)) return pending;\n return {\n work: Work.Full(),\n optional: backend.declared\n ? HashSet.difference(pending.optional, generated)\n : pending.optional,\n };\n};\n\nexport type Phase = Data.TaggedEnum<{\n Bootstrapping: {};\n NeedsFullSync: {};\n Incremental: {\n readonly failedImpls: HashSet.HashSet<ImplModulePath>;\n readonly snapshot: GenerationSnapshot;\n };\n}>;\nexport const Phase = Data.taggedEnum<Phase>();\n\nexport type Outcome = Data.TaggedEnum<{\n Succeeded: { readonly snapshot: GenerationSnapshot };\n GenerationFailed: {};\n ReconciliationFailed: {};\n ValidationFailed: {\n readonly snapshot: GenerationSnapshot;\n readonly paths: Array.NonEmptyReadonlyArray<ImplModulePath>;\n };\n}>;\nexport const Outcome = Data.taggedEnum<Outcome>();\n\nexport const transition = (outcome: Outcome): Phase =>\n Outcome.$match(outcome, {\n Succeeded: ({ snapshot }) =>\n Phase.Incremental({\n snapshot,\n failedImpls: HashSet.empty(),\n }),\n GenerationFailed: () => Phase.NeedsFullSync(),\n ReconciliationFailed: () => Phase.NeedsFullSync(),\n ValidationFailed: ({ snapshot, paths }) =>\n Phase.Incremental({\n snapshot,\n failedImpls: HashSet.fromIterable(paths),\n }),\n });\n\nexport const shouldRetry = (phase: Phase, outcome: Outcome): boolean =>\n Phase.$is(\"Bootstrapping\")(phase) && Outcome.$is(\"GenerationFailed\")(outcome);\n\nexport const needsDeploymentNotification = (phase: Phase): boolean =>\n Phase.$match(phase, {\n Bootstrapping: () => true,\n NeedsFullSync: () => true,\n Incremental: ({ failedImpls }) => !HashSet.isEmpty(failedImpls),\n });\n\nexport const implsToValidate = (\n phase: Phase,\n pending: Pending,\n): ReadonlyArray<ImplModulePath> =>\n Array.fromIterable(\n HashSet.union(\n Phase.$match(phase, {\n Bootstrapping: () => HashSet.empty<ImplModulePath>(),\n NeedsFullSync: () => HashSet.empty<ImplModulePath>(),\n Incremental: ({ failedImpls }) => failedImpls,\n }),\n Work.$match(pending.work, {\n None: () => HashSet.empty<ImplModulePath>(),\n Reconcile: () => HashSet.empty<ImplModulePath>(),\n Full: () => HashSet.empty<ImplModulePath>(),\n Impls: ({ paths }) => HashSet.fromIterable(paths),\n Declarations: ({ paths }) => HashSet.fromIterable(paths),\n }),\n ),\n );\n\nexport type Operation = Data.TaggedEnum<{\n Generate: {};\n Validate: {\n readonly snapshot: GenerationSnapshot;\n readonly paths: ReadonlyArray<ImplModulePath>;\n };\n Update: {\n readonly snapshot: GenerationSnapshot;\n readonly declarations: Array.NonEmptyReadonlyArray<Declaration>;\n readonly paths: ReadonlyArray<ImplModulePath>;\n };\n}>;\nexport const Operation = Data.taggedEnum<Operation>();\n\nexport const plan = (phase: Phase, pending: Pending): Operation =>\n Phase.$match(phase, {\n Bootstrapping: () => Operation.Generate(),\n NeedsFullSync: () => Operation.Generate(),\n Incremental: (ready) =>\n Match.value(pending.work).pipe(\n Match.tag(\"Full\", () => Operation.Generate()),\n Match.tag(\"None\", \"Reconcile\", \"Impls\", () =>\n Operation.Validate({\n snapshot: ready.snapshot,\n paths: implsToValidate(ready, pending),\n }),\n ),\n Match.tag(\"Declarations\", ({ entries }) =>\n Operation.Update({\n snapshot: ready.snapshot,\n declarations: entries,\n paths: implsToValidate(ready, pending),\n }),\n ),\n Match.exhaustive,\n ),\n });\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TableModule.mjs","names":["Bundler.bundle","Bundler.withBatch"],"sources":["../src/TableModule.ts"],"sourcesContent":["import { Identifier } from \"@confect/core\";\nimport * as Table from \"@confect/core/Table\";\nimport * 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 Order from \"effect/Order\";\nimport { fromBundlerError } from \"./BuildError\";\nimport * as Bundler from \"./Bundler\";\nimport {\n DuplicateTableNameError,\n InvalidTableDefaultExportError,\n InvalidTableFilenameError,\n} from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\n\nexport const TABLES_DIRNAME = \"tables\";\n\n/**\n * Discovered metadata for a single user-authored table module under\n * `confect/tables/`.\n *\n * - `relativePath`—path from `confect/` to the file (e.g. `tables/notes.ts`).\n * - `tableName`—the file basename (e.g. `notes`). This is also the import binding\n * used in generated files, and the table name surfaced to Convex.\n */\nexport interface TableModule {\n readonly relativePath: string;\n readonly tableName: string;\n}\n\nconst tableNameFromRelativePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { name } = path.parse(relativePath);\n return name;\n});\n\nexport const discoverTableFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const tablesDirectory = path.join(confectDirectory, TABLES_DIRNAME);\n\n if (!(yield* fs.exists(tablesDirectory))) {\n return [] as ReadonlyArray<string>;\n }\n\n const allPaths = yield* fs.readDirectory(tablesDirectory, {\n recursive: true,\n });\n\n return pipe(\n allPaths,\n Array.filter((p) => p.endsWith(\".ts\") && !p.endsWith(\".test.ts\")),\n Array.map((p) => path.join(TABLES_DIRNAME, p)),\n );\n});\n\nconst byTableName = Order.mapInput(\n Order.String,\n (tableModule: TableModule) => tableModule.tableName,\n);\n\n/**\n * Discover every `confect/tables/**\\/*.ts` module by listing the directory.\n * Validates that each filename is a legal table identifier—the table name is\n * derived from the file basename, so the filename must be a valid JavaScript\n * identifier with no leading underscore (Convex reserves `_<name>` for system\n * tables).\n *\n * This step does _not_ bundle the table modules. It runs early in the codegen\n * pipeline so the `_generated/id.ts` constructor can be emitted _before_ any\n * user-authored table is bundled (those modules import from `_generated/id.ts`\n * for cross-table refs).\n *\n * A missing `confect/tables/` directory is allowed and produces an empty list.\n *\n * Fails with {@link InvalidTableFilenameError} if any filename is not a valid\n * table identifier, or {@link DuplicateTableNameError} if two files resolve to\n * the same table name (the directory is scanned recursively but names are\n * derived from the basename alone, so `tables/a/notes.ts` and\n * `tables/b/notes.ts` would collide).\n */\nexport const discover = Effect.gen(function* () {\n const relativePaths = yield* discoverTableFiles;\n\n const tableModules = yield* Effect.forEach(\n relativePaths,\n Effect.fnUntraced(function* (relativePath: string) {\n const tableName = yield* tableNameFromRelativePath(relativePath);\n yield* Effect.try({\n try: () => Identifier.validateConfectTableIdentifier(tableName),\n catch: (e) =>\n new InvalidTableFilenameError({\n tablePath: relativePath,\n reason: e instanceof Error ? e.message : String(e),\n }),\n });\n return { relativePath, tableName } satisfies TableModule;\n }),\n { concurrency: \"unbounded\" },\n );\n\n const sorted = pipe(tableModules, Array.sortBy(byTableName));\n\n const collisions = Object.entries(\n Array.groupBy(sorted, (tableModule) => tableModule.tableName),\n )\n .filter(([, group]) => group.length > 1)\n .map(([tableName, group]) => ({\n tableName,\n tablePaths: Array.map(group, (tableModule) => tableModule.relativePath),\n }));\n\n if (collisions.length > 0) {\n return yield* new DuplicateTableNameError({ collisions });\n }\n\n return sorted;\n});\n\n/**\n * Bundle every discovered table module and verify that its default export is an\n * {@link Table.UnnamedTable} (the result of `Table.make(...)` before a name has\n * been bound). Fails with {@link InvalidTableDefaultExportError} if any\n * module's default export is missing or has the wrong shape.\n *\n * Must run _after_ `_generated/id.ts` has been emitted, because user-authored\n * table modules typically `import { Id } from \"../_generated/id\"` for\n * cross-table references.\n */\nexport const validate = Effect.fnUntraced(function* (\n tableModules: ReadonlyArray<TableModule>,\n) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const validateRelativePath = Effect.fnUntraced(function* (\n relativePath: string,\n ) {\n const absolutePath = path.resolve(confectDirectory, relativePath);\n const { module } = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(relativePath, error)),\n );\n\n if (!Table.isUnnamedTable(module.default)) {\n return yield* new InvalidTableDefaultExportError({\n tablePath: relativePath,\n });\n }\n });\n\n const relativePaths = tableModules.map(({ relativePath }) => relativePath);\n yield* Bundler.withBatch(\n relativePaths.map((relativePath) =>\n path.resolve(confectDirectory, relativePath),\n ),\n Effect.forEach(relativePaths, validateRelativePath, { concurrency: 4 }),\n );\n});\n"],"mappings":";;;;;;;;;;;;;AAiBA,MAAa,iBAAiB;AAe9B,MAAM,4BAA4B,OAAO,WAAW,WAClD,cACA;CAEA,MAAM,EAAE,UAAS,OADG,KAAK,KAAA,CACH,MAAM,YAAY;CACxC,OAAO;AACT,CAAC;AAED,MAAa,qBAAqB,OAAO,IAAI,aAAa;CACxD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,kBAAkB,KAAK,KAAK,kBAAkB,cAAc;CAElE,IAAI,EAAE,OAAO,GAAG,OAAO,eAAe,IACpC,OAAO,CAAC;CAGV,MAAM,WAAW,OAAO,GAAG,cAAc,iBAAiB,EACxD,WAAW,KACb,CAAC;CAED,OAAO,KACL,UACA,MAAM,QAAQ,MAAM,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU,CAAC,GAChE,MAAM,KAAK,MAAM,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAC/C;AACF,CAAC;AAED,MAAM,cAAc,MAAM,SACxB,MAAM,SACL,gBAA6B,YAAY,SAC5C;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,WAAW,OAAO,IAAI,aAAa;CAC9C,MAAM,gBAAgB,OAAO;CAE7B,MAAM,eAAe,OAAO,OAAO,QACjC,eACA,OAAO,WAAW,WAAW,cAAsB;EACjD,MAAM,YAAY,OAAO,0BAA0B,YAAY;EAC/D,OAAO,OAAO,IAAI;GAChB,WAAW,WAAW,+BAA+B,SAAS;GAC9D,QAAQ,MACN,IAAI,0BAA0B;IAC5B,WAAW;IACX,QAAQ,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;GACnD,CAAC;EACL,CAAC;EACD,OAAO;GAAE;GAAc;EAAU;CACnC,CAAC,GACD,EAAE,aAAa,YAAY,CAC7B;CAEA,MAAM,SAAS,KAAK,cAAc,MAAM,OAAO,WAAW,CAAC;CAE3D,MAAM,aAAa,OAAO,QACxB,MAAM,QAAQ,SAAS,gBAAgB,YAAY,SAAS,CAC9D,CAAC,CACE,QAAQ,GAAG,WAAW,MAAM,SAAS,CAAC,CAAC,CACvC,KAAK,CAAC,WAAW,YAAY;EAC5B;EACA,YAAY,MAAM,IAAI,QAAQ,gBAAgB,YAAY,YAAY;CACxE,EAAE;CAEJ,IAAI,WAAW,SAAS,GACtB,OAAO,OAAO,IAAI,wBAAwB,EAAE,WAAW,CAAC;CAG1D,OAAO;AACT,CAAC;;;;;;;;;;;AAYD,MAAa,WAAW,OAAO,WAAW,WACxC,cACA;CACA,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,uBAAuB,OAAO,WAAW,WAC7C,cACA;EACA,MAAM,eAAe,KAAK,QAAQ,kBAAkB,YAAY;EAChE,MAAM,EAAE,WAAW,OAAOA,OAAe,YAAY,CAAC,CAAC,KACrD,OAAO,UAAU,UAAU,iBAAiB,cAAc,KAAK,CAAC,CAClE;EAEA,IAAI,CAAC,MAAM,eAAe,OAAO,OAAO,GACtC,OAAO,OAAO,IAAI,+BAA+B,EAC/C,WAAW,aACb,CAAC;CAEL,CAAC;CAED,MAAM,gBAAgB,aAAa,KAAK,EAAE,mBAAmB,YAAY;CACzE,OAAOC,UACL,cAAc,KAAK,iBACjB,KAAK,QAAQ,kBAAkB,YAAY,CAC7C,GACA,OAAO,QAAQ,eAAe,sBAAsB,EAAE,aAAa,EAAE,CAAC,CACxE;AACF,CAAC"}
1
+ {"version":3,"file":"TableModule.mjs","names":["Bundler.bundle","Bundler.withBatch"],"sources":["../src/TableModule.ts"],"sourcesContent":["import { Identifier } from \"@confect/core\";\nimport * as Table from \"@confect/core/Table\";\nimport * 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 Order from \"effect/Order\";\nimport { fromBundlerError } from \"./BuildError.js\";\nimport * as Bundler from \"./Bundler.js\";\nimport {\n DuplicateTableNameError,\n InvalidTableDefaultExportError,\n InvalidTableFilenameError,\n} from \"./CodegenError.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\n\nexport const TABLES_DIRNAME = \"tables\";\n\n/**\n * Discovered metadata for a single user-authored table module under\n * `confect/tables/`.\n *\n * - `relativePath`—path from `confect/` to the file (e.g. `tables/notes.ts`).\n * - `tableName`—the file basename (e.g. `notes`). This is also the import binding\n * used in generated files, and the table name surfaced to Convex.\n */\nexport interface TableModule {\n readonly relativePath: string;\n readonly tableName: string;\n}\n\nconst tableNameFromRelativePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { name } = path.parse(relativePath);\n return name;\n});\n\nexport const discoverTableFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const tablesDirectory = path.join(confectDirectory, TABLES_DIRNAME);\n\n if (!(yield* fs.exists(tablesDirectory))) {\n return [] as ReadonlyArray<string>;\n }\n\n const allPaths = yield* fs.readDirectory(tablesDirectory, {\n recursive: true,\n });\n\n return pipe(\n allPaths,\n Array.filter((p) => p.endsWith(\".ts\") && !p.endsWith(\".test.ts\")),\n Array.map((p) => path.join(TABLES_DIRNAME, p)),\n );\n});\n\nconst byTableName = Order.mapInput(\n Order.String,\n (tableModule: TableModule) => tableModule.tableName,\n);\n\n/**\n * Discover every `confect/tables/**\\/*.ts` module by listing the directory.\n * Validates that each filename is a legal table identifier—the table name is\n * derived from the file basename, so the filename must be a valid JavaScript\n * identifier with no leading underscore (Convex reserves `_<name>` for system\n * tables).\n *\n * This step does _not_ bundle the table modules. It runs early in the codegen\n * pipeline so the `_generated/id.ts` constructor can be emitted _before_ any\n * user-authored table is bundled (those modules import from `_generated/id.ts`\n * for cross-table refs).\n *\n * A missing `confect/tables/` directory is allowed and produces an empty list.\n *\n * Fails with {@link InvalidTableFilenameError} if any filename is not a valid\n * table identifier, or {@link DuplicateTableNameError} if two files resolve to\n * the same table name (the directory is scanned recursively but names are\n * derived from the basename alone, so `tables/a/notes.ts` and\n * `tables/b/notes.ts` would collide).\n */\nexport const discover = Effect.gen(function* () {\n const relativePaths = yield* discoverTableFiles;\n\n const tableModules = yield* Effect.forEach(\n relativePaths,\n Effect.fnUntraced(function* (relativePath: string) {\n const tableName = yield* tableNameFromRelativePath(relativePath);\n yield* Effect.try({\n try: () => Identifier.validateConfectTableIdentifier(tableName),\n catch: (e) =>\n new InvalidTableFilenameError({\n tablePath: relativePath,\n reason: e instanceof Error ? e.message : String(e),\n }),\n });\n return { relativePath, tableName } satisfies TableModule;\n }),\n { concurrency: \"unbounded\" },\n );\n\n const sorted = pipe(tableModules, Array.sortBy(byTableName));\n\n const collisions = Object.entries(\n Array.groupBy(sorted, (tableModule) => tableModule.tableName),\n )\n .filter(([, group]) => group.length > 1)\n .map(([tableName, group]) => ({\n tableName,\n tablePaths: Array.map(group, (tableModule) => tableModule.relativePath),\n }));\n\n if (collisions.length > 0) {\n return yield* new DuplicateTableNameError({ collisions });\n }\n\n return sorted;\n});\n\n/**\n * Bundle every discovered table module and verify that its default export is an\n * {@link Table.UnnamedTable} (the result of `Table.make(...)` before a name has\n * been bound). Fails with {@link InvalidTableDefaultExportError} if any\n * module's default export is missing or has the wrong shape.\n *\n * Must run _after_ `_generated/id.ts` has been emitted, because user-authored\n * table modules typically `import { Id } from \"../_generated/id\"` for\n * cross-table references.\n */\nexport const validate = Effect.fnUntraced(function* (\n tableModules: ReadonlyArray<TableModule>,\n) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const validateRelativePath = Effect.fnUntraced(function* (\n relativePath: string,\n ) {\n const absolutePath = path.resolve(confectDirectory, relativePath);\n const { module } = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(relativePath, error)),\n );\n\n if (!Table.isUnnamedTable(module.default)) {\n return yield* new InvalidTableDefaultExportError({\n tablePath: relativePath,\n });\n }\n });\n\n const relativePaths = tableModules.map(({ relativePath }) => relativePath);\n yield* Bundler.withBatch(\n relativePaths.map((relativePath) =>\n path.resolve(confectDirectory, relativePath),\n ),\n Effect.forEach(relativePaths, validateRelativePath, { concurrency: 4 }),\n );\n});\n"],"mappings":";;;;;;;;;;;;;AAiBA,MAAa,iBAAiB;AAe9B,MAAM,4BAA4B,OAAO,WAAW,WAClD,cACA;CAEA,MAAM,EAAE,UAAS,OADG,KAAK,KAAA,CACH,MAAM,YAAY;CACxC,OAAO;AACT,CAAC;AAED,MAAa,qBAAqB,OAAO,IAAI,aAAa;CACxD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,kBAAkB,KAAK,KAAK,kBAAkB,cAAc;CAElE,IAAI,EAAE,OAAO,GAAG,OAAO,eAAe,IACpC,OAAO,CAAC;CAGV,MAAM,WAAW,OAAO,GAAG,cAAc,iBAAiB,EACxD,WAAW,KACb,CAAC;CAED,OAAO,KACL,UACA,MAAM,QAAQ,MAAM,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU,CAAC,GAChE,MAAM,KAAK,MAAM,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAC/C;AACF,CAAC;AAED,MAAM,cAAc,MAAM,SACxB,MAAM,SACL,gBAA6B,YAAY,SAC5C;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,WAAW,OAAO,IAAI,aAAa;CAC9C,MAAM,gBAAgB,OAAO;CAE7B,MAAM,eAAe,OAAO,OAAO,QACjC,eACA,OAAO,WAAW,WAAW,cAAsB;EACjD,MAAM,YAAY,OAAO,0BAA0B,YAAY;EAC/D,OAAO,OAAO,IAAI;GAChB,WAAW,WAAW,+BAA+B,SAAS;GAC9D,QAAQ,MACN,IAAI,0BAA0B;IAC5B,WAAW;IACX,QAAQ,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;GACnD,CAAC;EACL,CAAC;EACD,OAAO;GAAE;GAAc;EAAU;CACnC,CAAC,GACD,EAAE,aAAa,YAAY,CAC7B;CAEA,MAAM,SAAS,KAAK,cAAc,MAAM,OAAO,WAAW,CAAC;CAE3D,MAAM,aAAa,OAAO,QACxB,MAAM,QAAQ,SAAS,gBAAgB,YAAY,SAAS,CAC9D,CAAC,CACE,QAAQ,GAAG,WAAW,MAAM,SAAS,CAAC,CAAC,CACvC,KAAK,CAAC,WAAW,YAAY;EAC5B;EACA,YAAY,MAAM,IAAI,QAAQ,gBAAgB,YAAY,YAAY;CACxE,EAAE;CAEJ,IAAI,WAAW,SAAS,GACtB,OAAO,OAAO,IAAI,wBAAwB,EAAE,WAAW,CAAC;CAG1D,OAAO;AACT,CAAC;;;;;;;;;;;AAYD,MAAa,WAAW,OAAO,WAAW,WACxC,cACA;CACA,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,uBAAuB,OAAO,WAAW,WAC7C,cACA;EACA,MAAM,eAAe,KAAK,QAAQ,kBAAkB,YAAY;EAChE,MAAM,EAAE,WAAW,OAAOA,OAAe,YAAY,CAAC,CAAC,KACrD,OAAO,UAAU,UAAU,iBAAiB,cAAc,KAAK,CAAC,CAClE;EAEA,IAAI,CAAC,MAAM,eAAe,OAAO,OAAO,GACtC,OAAO,OAAO,IAAI,+BAA+B,EAC/C,WAAW,aACb,CAAC;CAEL,CAAC;CAED,MAAM,gBAAgB,aAAa,KAAK,EAAE,mBAAmB,YAAY;CACzE,OAAOC,UACL,cAAc,KAAK,iBACjB,KAAK,QAAQ,kBAAkB,YAAY,CAC7C,GACA,OAAO,QAAQ,eAAe,sBAAsB,EAAE,aAAa,EAAE,CAAC,CACxE;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TableModulePath.mjs","names":["RelativeModulePath.withSuffix"],"sources":["../src/TableModulePath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as RelativeModulePath from \"./RelativeModulePath\";\n\nexport const TableModulePath = RelativeModulePath.withSuffix(\".ts\")\n .check(Schema.makeFilter((value) => value.split(/[/\\\\]/)[0] === \"tables\"))\n .pipe(Schema.brand(\"@confect/cli/TableModulePath\"));\n\nexport type TableModulePath = typeof TableModulePath.Type;\n"],"mappings":";;;AAGA,MAAa,kBAAkBA,WAA8B,KAAK,CAAC,CAChE,MAAM,OAAO,YAAY,UAAU,MAAM,MAAM,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CACzE,KAAK,OAAO,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"TableModulePath.mjs","names":["RelativeModulePath.withSuffix"],"sources":["../src/TableModulePath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as RelativeModulePath from \"./RelativeModulePath.js\";\n\nexport const TableModulePath = RelativeModulePath.withSuffix(\".ts\")\n .check(Schema.makeFilter((value) => value.split(/[/\\\\]/)[0] === \"tables\"))\n .pipe(Schema.brand(\"@confect/cli/TableModulePath\"));\n\nexport type TableModulePath = typeof TableModulePath.Type;\n"],"mappings":";;;AAGA,MAAa,kBAAkBA,WAA8B,KAAK,CAAC,CAChE,MAAM,OAAO,YAAY,UAAU,MAAM,MAAM,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CACzE,KAAK,OAAO,MAAM,8BAA8B,CAAC"}