@gaganref/confect-cli 10.3.1-fork.3 → 10.3.1-fork.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"EvaluationWorker.mjs","names":["CodegenError.ComponentNodeGroupError","CodegenError.isCodegenError","CodegenError.renderCodegenError"],"sources":["../src/EvaluationWorker.ts"],"sourcesContent":["import * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport * as NodeWorkerRunner from \"@effect/platform-node/NodeWorkerRunner\";\nimport * as IdScope from \"@confect/core/IdScope\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as References from \"effect/References\";\nimport * as Schema from \"effect/Schema\";\nimport * as RpcServer from \"effect/rpc/RpcServer\";\nimport * as esbuild from \"esbuild\";\nimport * as CodegenError from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\nimport type { RequestContext } from \"./Evaluation\";\nimport { EvaluationError, requests } from \"./Evaluation\";\nimport { validateImplFiles } from \"./LeafModule\";\nimport { ProjectRoot } from \"./ProjectRoot\";\nimport {\n generateWithSnapshot,\n loadPreviousFunctionPaths,\n updateDeclarations,\n} from \"./confect/codegen\";\n\nconst evaluate = <A, E, R>(\n requestContext: RequestContext,\n effect: Effect.Effect<A, E, R>,\n) =>\n effect.pipe(\n Effect.provideService(\n References.MinimumLogLevel,\n requestContext.minimumLogLevel,\n ),\n Effect.provideService(ProjectRoot, {\n get: Effect.succeed(requestContext.projectRoot),\n }),\n Effect.provideService(ConfectDirectory, {\n get: Effect.succeed(requestContext.confectDirectory),\n }),\n Effect.provideService(ConvexDirectory, {\n get: Effect.succeed(requestContext.convexDirectory),\n target: Match.value(requestContext.target).pipe(\n Match.when({ kind: \"app\" }, () => ({\n kind: \"app\" as const,\n scope: IdScope.app,\n })),\n Match.when({ kind: \"component\" }, ({ definition }) => ({\n kind: \"component\" as const,\n scope: IdScope.component(definition),\n })),\n Match.exhaustive,\n ),\n }),\n Effect.catchCause(\n (\n cause,\n ): Effect.Effect<\n never,\n EvaluationError | CodegenError.ComponentNodeGroupError\n > => {\n const failure = Cause.findErrorOption(cause);\n if (\n Option.isSome(failure) &&\n Schema.is(CodegenError.ComponentNodeGroupError)(failure.value)\n )\n return Effect.fail(failure.value);\n return Effect.fail(\n new EvaluationError({\n diagnostic:\n Option.isSome(failure) &&\n CodegenError.isCodegenError(failure.value)\n ? CodegenError.renderCodegenError(failure.value)\n : Cause.pretty(cause),\n }),\n );\n },\n ),\n );\n\nconst handlers = requests.toLayer({\n Previous: (requestContext) =>\n evaluate(requestContext, loadPreviousFunctionPaths),\n Generate: (requestContext) =>\n evaluate(\n requestContext,\n generateWithSnapshot.pipe(Effect.map(({ snapshot }) => snapshot)),\n ),\n Validate: (request) => evaluate(request, validateImplFiles(request.paths)),\n Update: (request) =>\n evaluate(\n request,\n updateDeclarations(request.snapshot, request.declarations, request.paths),\n ),\n});\n\nRpcServer.layer(requests).pipe(\n Layer.provide(handlers),\n Layer.provide(NodeServices.layer),\n Layer.provide(\n RpcServer.layerProtocolWorkerRunner.pipe(\n Layer.provide(NodeWorkerRunner.layer),\n ),\n ),\n Layer.launch,\n Effect.ensuring(Effect.promise(() => esbuild.stop())),\n NodeRuntime.runMain,\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,YACJ,gBACA,WAEA,OAAO,KACL,OAAO,eACL,WAAW,iBACX,eAAe,eACjB,GACA,OAAO,eAAe,aAAa,EACjC,KAAK,OAAO,QAAQ,eAAe,WAAW,EAChD,CAAC,GACD,OAAO,eAAe,kBAAkB,EACtC,KAAK,OAAO,QAAQ,eAAe,gBAAgB,EACrD,CAAC,GACD,OAAO,eAAe,iBAAiB;CACrC,KAAK,OAAO,QAAQ,eAAe,eAAe;CAClD,QAAQ,MAAM,MAAM,eAAe,MAAM,CAAC,CAAC,KACzC,MAAM,KAAK,EAAE,MAAM,MAAM,UAAU;EACjC,MAAM;EACN,OAAO,QAAQ;CACjB,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,YAAY,IAAI,EAAE,kBAAkB;EACrD,MAAM;EACN,OAAO,QAAQ,UAAU,UAAU;CACrC,EAAE,GACF,MAAM,UACR;AACF,CAAC,GACD,OAAO,YAEH,UAIG;CACH,MAAM,UAAU,MAAM,gBAAgB,KAAK;CAC3C,IACE,OAAO,OAAO,OAAO,KACrB,OAAO,GAAGA,uBAAoC,CAAC,CAAC,QAAQ,KAAK,GAE7D,OAAO,OAAO,KAAK,QAAQ,KAAK;CAClC,OAAO,OAAO,KACZ,IAAI,gBAAgB,EAClB,YACE,OAAO,OAAO,OAAO,KACrBC,eAA4B,QAAQ,KAAK,IACrCC,mBAAgC,QAAQ,KAAK,IAC7C,MAAM,OAAO,KAAK,EAC1B,CAAC,CACH;AACF,CACF,CACF;AAEF,MAAM,WAAW,SAAS,QAAQ;CAChC,WAAW,mBACT,SAAS,gBAAgB,yBAAyB;CACpD,WAAW,mBACT,SACE,gBACA,qBAAqB,KAAK,OAAO,KAAK,EAAE,eAAe,QAAQ,CAAC,CAClE;CACF,WAAW,YAAY,SAAS,SAAS,kBAAkB,QAAQ,KAAK,CAAC;CACzE,SAAS,YACP,SACE,SACA,mBAAmB,QAAQ,UAAU,QAAQ,cAAc,QAAQ,KAAK,CAC1E;AACJ,CAAC;AAED,UAAU,MAAM,QAAQ,CAAC,CAAC,KACxB,MAAM,QAAQ,QAAQ,GACtB,MAAM,QAAQ,aAAa,KAAK,GAChC,MAAM,QACJ,UAAU,0BAA0B,KAClC,MAAM,QAAQ,iBAAiB,KAAK,CACtC,CACF,GACA,MAAM,QACN,OAAO,SAAS,OAAO,cAAc,QAAQ,KAAK,CAAC,CAAC,GACpD,YAAY,OACd"}
1
+ {"version":3,"file":"EvaluationWorker.mjs","names":["CodegenError.ComponentNodeGroupError","CodegenError.isCodegenError","CodegenError.renderCodegenError"],"sources":["../src/EvaluationWorker.ts"],"sourcesContent":["import * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport * as NodeWorkerRunner from \"@effect/platform-node/NodeWorkerRunner\";\nimport * as IdScope from \"@confect/core/IdScope\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as References from \"effect/References\";\nimport * as Schema from \"effect/Schema\";\nimport * as RpcServer from \"effect/rpc/RpcServer\";\nimport * as esbuild from \"esbuild\";\nimport * as CodegenError from \"./CodegenError.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ConvexDirectory } from \"./ConvexDirectory.js\";\nimport type { RequestContext } from \"./Evaluation.js\";\nimport { EvaluationError, requests } from \"./Evaluation.js\";\nimport { validateImplFiles } from \"./LeafModule.js\";\nimport { ProjectRoot } from \"./ProjectRoot.js\";\nimport {\n generateWithSnapshot,\n loadPreviousFunctionPaths,\n updateDeclarations,\n} from \"./confect/codegen.js\";\n\nconst evaluate = <A, E, R>(\n requestContext: RequestContext,\n effect: Effect.Effect<A, E, R>,\n) =>\n effect.pipe(\n Effect.provideService(\n References.MinimumLogLevel,\n requestContext.minimumLogLevel,\n ),\n Effect.provideService(ProjectRoot, {\n get: Effect.succeed(requestContext.projectRoot),\n }),\n Effect.provideService(ConfectDirectory, {\n get: Effect.succeed(requestContext.confectDirectory),\n }),\n Effect.provideService(ConvexDirectory, {\n get: Effect.succeed(requestContext.convexDirectory),\n target: Match.value(requestContext.target).pipe(\n Match.when({ kind: \"app\" }, () => ({\n kind: \"app\" as const,\n scope: IdScope.app,\n })),\n Match.when({ kind: \"component\" }, ({ definition }) => ({\n kind: \"component\" as const,\n scope: IdScope.component(definition),\n })),\n Match.exhaustive,\n ),\n }),\n Effect.catchCause(\n (\n cause,\n ): Effect.Effect<\n never,\n EvaluationError | CodegenError.ComponentNodeGroupError\n > => {\n const failure = Cause.findErrorOption(cause);\n if (\n Option.isSome(failure) &&\n Schema.is(CodegenError.ComponentNodeGroupError)(failure.value)\n )\n return Effect.fail(failure.value);\n return Effect.fail(\n new EvaluationError({\n diagnostic:\n Option.isSome(failure) &&\n CodegenError.isCodegenError(failure.value)\n ? CodegenError.renderCodegenError(failure.value)\n : Cause.pretty(cause),\n }),\n );\n },\n ),\n );\n\nconst handlers = requests.toLayer({\n Previous: (requestContext) =>\n evaluate(requestContext, loadPreviousFunctionPaths),\n Generate: (requestContext) =>\n evaluate(\n requestContext,\n generateWithSnapshot.pipe(Effect.map(({ snapshot }) => snapshot)),\n ),\n Validate: (request) => evaluate(request, validateImplFiles(request.paths)),\n Update: (request) =>\n evaluate(\n request,\n updateDeclarations(request.snapshot, request.declarations, request.paths),\n ),\n});\n\nRpcServer.layer(requests).pipe(\n Layer.provide(handlers),\n Layer.provide(NodeServices.layer),\n Layer.provide(\n RpcServer.layerProtocolWorkerRunner.pipe(\n Layer.provide(NodeWorkerRunner.layer),\n ),\n ),\n Layer.launch,\n Effect.ensuring(Effect.promise(() => esbuild.stop())),\n NodeRuntime.runMain,\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,YACJ,gBACA,WAEA,OAAO,KACL,OAAO,eACL,WAAW,iBACX,eAAe,eACjB,GACA,OAAO,eAAe,aAAa,EACjC,KAAK,OAAO,QAAQ,eAAe,WAAW,EAChD,CAAC,GACD,OAAO,eAAe,kBAAkB,EACtC,KAAK,OAAO,QAAQ,eAAe,gBAAgB,EACrD,CAAC,GACD,OAAO,eAAe,iBAAiB;CACrC,KAAK,OAAO,QAAQ,eAAe,eAAe;CAClD,QAAQ,MAAM,MAAM,eAAe,MAAM,CAAC,CAAC,KACzC,MAAM,KAAK,EAAE,MAAM,MAAM,UAAU;EACjC,MAAM;EACN,OAAO,QAAQ;CACjB,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,YAAY,IAAI,EAAE,kBAAkB;EACrD,MAAM;EACN,OAAO,QAAQ,UAAU,UAAU;CACrC,EAAE,GACF,MAAM,UACR;AACF,CAAC,GACD,OAAO,YAEH,UAIG;CACH,MAAM,UAAU,MAAM,gBAAgB,KAAK;CAC3C,IACE,OAAO,OAAO,OAAO,KACrB,OAAO,GAAGA,uBAAoC,CAAC,CAAC,QAAQ,KAAK,GAE7D,OAAO,OAAO,KAAK,QAAQ,KAAK;CAClC,OAAO,OAAO,KACZ,IAAI,gBAAgB,EAClB,YACE,OAAO,OAAO,OAAO,KACrBC,eAA4B,QAAQ,KAAK,IACrCC,mBAAgC,QAAQ,KAAK,IAC7C,MAAM,OAAO,KAAK,EAC1B,CAAC,CACH;AACF,CACF,CACF;AAEF,MAAM,WAAW,SAAS,QAAQ;CAChC,WAAW,mBACT,SAAS,gBAAgB,yBAAyB;CACpD,WAAW,mBACT,SACE,gBACA,qBAAqB,KAAK,OAAO,KAAK,EAAE,eAAe,QAAQ,CAAC,CAClE;CACF,WAAW,YAAY,SAAS,SAAS,kBAAkB,QAAQ,KAAK,CAAC;CACzE,SAAS,YACP,SACE,SACA,mBAAmB,QAAQ,UAAU,QAAQ,cAAc,QAAQ,KAAK,CAC1E;AACJ,CAAC;AAED,UAAU,MAAM,QAAQ,CAAC,CAAC,KACxB,MAAM,QAAQ,QAAQ,GACtB,MAAM,QAAQ,aAAa,KAAK,GAChC,MAAM,QACJ,UAAU,0BAA0B,KAClC,MAAM,QAAQ,iBAAiB,KAAK,CACtC,CACF,GACA,MAAM,QACN,OAAO,SAAS,OAAO,cAAc,QAAQ,KAAK,CAAC,CAAC,GACpD,YAAY,OACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionModule.mjs","names":["GroupPath.modulePath","modulePath","GenerationSnapshot.plan","GenerationSnapshot.functionPaths","GroupPath.fromGroupModulePath"],"sources":["../src/FunctionModule.ts"],"sourcesContent":["import * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as GenerationSnapshot from \"./GenerationSnapshot\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\nimport { removePathIfExists, toModuleImportPath } from \"./utils\";\n\nexport const render = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof renderEffect>[0]) =>\n renderEffect({ functionNames, registeredFunctionsImportPath, useNode });\n\nconst renderEffect = Effect.fnUntraced(function* ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (name) =>\n cbw.writeLine(`export const ${name} = registeredFunctions.${name};`),\n );\n\n return yield* cbw.toString();\n});\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof generateGroupModuleEffect>[0]) =>\n generateGroupModuleEffect({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\nconst generateGroupModuleEffect = Effect.fnUntraced(function* ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const functionsContentsString = yield* render({\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n});\n\n/**\n * Compute the module import specifier (relative to `modulePath`) for a group's\n * registry file under `confect/_generated/registeredFunctions/`. The registry\n * path mirrors the group's path one-to-one (see\n * `registeredFunctionsRelativePath` in `LeafModule.ts`) for both Convex and\n * Node groups.\n */\nexport const registeredFunctionsImportPathForGroup = Effect.fnUntraced(\n function* (groupPath: GroupPath.GroupPath, modulePath: string) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const registeredFunctionsPath =\n path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n ...groupPath.pathSegments,\n ) + \".ts\";\n\n return yield* toModuleImportPath(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n },\n);\n\nconst logGroupPaths = Effect.fnUntraced(function* <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n): Effect.fn.Return<void, never, R | Path.Path | ConvexDirectory> {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(\n groupPaths,\n Effect.fnUntraced(function* (gp: GroupPath.GroupPath) {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n});\n\nexport const generateFunctions = Effect.fnUntraced(function* (\n snapshot: GenerationSnapshot.GenerationSnapshot,\n) {\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n yield* applyFunctionPlan(GenerationSnapshot.plan(snapshot, groupPathsFromFs));\n return GenerationSnapshot.functionPaths(snapshot);\n});\n\nexport const applyFunctionPlan = Effect.fnUntraced(function* (\n plan: GenerationSnapshot.ModulePlan,\n) {\n const removed = GroupPaths.GroupPaths.make(\n HashSet.fromIterable(plan.removed),\n );\n yield* removeGroups(removed);\n yield* logGroupPaths(removed, logFileRemoved);\n yield* writeGroups(plan.changed);\n});\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n ]);\n\n const allConvexPaths = yield* fs.readDirectory(convexDirectory, {\n recursive: true,\n });\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) &&\n path.basename(path.dirname(convexPath)) !== \"_generated\",\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return GroupPaths.GroupPaths.make(HashSet.fromIterable(groupPathArray));\n});\n\nexport const removeGroups = Effect.fnUntraced(function* (\n groupPaths: GroupPaths.GroupPaths,\n) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* removePathIfExists(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n});\n\nexport const writeGroups = (\n groups: ReadonlyArray<GenerationSnapshot.GroupSummary>,\n) =>\n Effect.forEach(\n groups,\n Effect.fnUntraced(function* (group: GenerationSnapshot.GroupSummary) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const relativeModulePath = yield* GroupPath.modulePath(group.path);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n const registeredFunctionsImportPath =\n yield* registeredFunctionsImportPathForGroup(group.path, modulePath);\n const change = yield* generateGroupModule({\n groupPath: group.path,\n functionNames: group.functionNames,\n registeredFunctionsImportPath,\n useNode: group.runtime === \"Node\",\n });\n yield* Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(modulePath)),\n Match.when(\"Modified\", () => logFileModified(modulePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n );\n }),\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"FunctionModule.mjs","names":["GroupPath.modulePath","modulePath","GenerationSnapshot.plan","GenerationSnapshot.functionPaths","GroupPath.fromGroupModulePath"],"sources":["../src/FunctionModule.ts"],"sourcesContent":["import * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as GenerationSnapshot from \"./GenerationSnapshot.js\";\nimport * as GroupPath from \"./GroupPath.js\";\nimport * as GroupPaths from \"./GroupPaths.js\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter.js\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ConvexDirectory } from \"./ConvexDirectory.js\";\nimport { removePathIfExists, toModuleImportPath } from \"./utils.js\";\n\nexport const render = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof renderEffect>[0]) =>\n renderEffect({ functionNames, registeredFunctionsImportPath, useNode });\n\nconst renderEffect = Effect.fnUntraced(function* ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (name) =>\n cbw.writeLine(`export const ${name} = registeredFunctions.${name};`),\n );\n\n return yield* cbw.toString();\n});\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof generateGroupModuleEffect>[0]) =>\n generateGroupModuleEffect({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\nconst generateGroupModuleEffect = Effect.fnUntraced(function* ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const functionsContentsString = yield* render({\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n});\n\n/**\n * Compute the module import specifier (relative to `modulePath`) for a group's\n * registry file under `confect/_generated/registeredFunctions/`. The registry\n * path mirrors the group's path one-to-one (see\n * `registeredFunctionsRelativePath` in `LeafModule.ts`) for both Convex and\n * Node groups.\n */\nexport const registeredFunctionsImportPathForGroup = Effect.fnUntraced(\n function* (groupPath: GroupPath.GroupPath, modulePath: string) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const registeredFunctionsPath =\n path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n ...groupPath.pathSegments,\n ) + \".ts\";\n\n return yield* toModuleImportPath(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n },\n);\n\nconst logGroupPaths = Effect.fnUntraced(function* <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n): Effect.fn.Return<void, never, R | Path.Path | ConvexDirectory> {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(\n groupPaths,\n Effect.fnUntraced(function* (gp: GroupPath.GroupPath) {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n});\n\nexport const generateFunctions = Effect.fnUntraced(function* (\n snapshot: GenerationSnapshot.GenerationSnapshot,\n) {\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n yield* applyFunctionPlan(GenerationSnapshot.plan(snapshot, groupPathsFromFs));\n return GenerationSnapshot.functionPaths(snapshot);\n});\n\nexport const applyFunctionPlan = Effect.fnUntraced(function* (\n plan: GenerationSnapshot.ModulePlan,\n) {\n const removed = GroupPaths.GroupPaths.make(\n HashSet.fromIterable(plan.removed),\n );\n yield* removeGroups(removed);\n yield* logGroupPaths(removed, logFileRemoved);\n yield* writeGroups(plan.changed);\n});\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n ]);\n\n const allConvexPaths = yield* fs.readDirectory(convexDirectory, {\n recursive: true,\n });\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) &&\n path.basename(path.dirname(convexPath)) !== \"_generated\",\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return GroupPaths.GroupPaths.make(HashSet.fromIterable(groupPathArray));\n});\n\nexport const removeGroups = Effect.fnUntraced(function* (\n groupPaths: GroupPaths.GroupPaths,\n) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* removePathIfExists(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n});\n\nexport const writeGroups = (\n groups: ReadonlyArray<GenerationSnapshot.GroupSummary>,\n) =>\n Effect.forEach(\n groups,\n Effect.fnUntraced(function* (group: GenerationSnapshot.GroupSummary) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const relativeModulePath = yield* GroupPath.modulePath(group.path);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n const registeredFunctionsImportPath =\n yield* registeredFunctionsImportPathForGroup(group.path, modulePath);\n const change = yield* generateGroupModule({\n groupPath: group.path,\n functionNames: group.functionNames,\n registeredFunctionsImportPath,\n useNode: group.runtime === \"Node\",\n });\n yield* Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(modulePath)),\n Match.when(\"Modified\", () => logFileModified(modulePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n );\n }),\n );\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionPath.mjs","names":["GroupPath.GroupPath"],"sources":["../src/FunctionPath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath\";\n\n/**\n * The path to a function in the Confect API.\n */\nexport class FunctionPath extends Schema.Class<FunctionPath>(\"FunctionPath\")({\n groupPath: GroupPath.GroupPath,\n name: Schema.NonEmptyString,\n}) {}\n\n/**\n * Get the group path from a function path.\n */\nexport const groupPath = (functionPath: FunctionPath): GroupPath.GroupPath =>\n functionPath.groupPath;\n\n/**\n * Get the function name from a function path.\n */\nexport const name = (functionPath: FunctionPath): string => functionPath.name;\n\n/**\n * Get the function path as a string.\n */\nexport const toString = (functionPath: FunctionPath): string =>\n `${GroupPath.toString(functionPath.groupPath)}.${functionPath.name}`;\n"],"mappings":";;;;;;AAMA,IAAa,eAAb,cAAkC,OAAO,MAAoB,cAAc,CAAC,CAAC;CAC3E,WAAWA;CACX,MAAM,OAAO;AACf,CAAC,CAAC,CAAC,CAAC;;;;AAKJ,MAAa,aAAa,iBACxB,aAAa"}
1
+ {"version":3,"file":"FunctionPath.mjs","names":["GroupPath.GroupPath"],"sources":["../src/FunctionPath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath.js\";\n\n/**\n * The path to a function in the Confect API.\n */\nexport class FunctionPath extends Schema.Class<FunctionPath>(\"FunctionPath\")({\n groupPath: GroupPath.GroupPath,\n name: Schema.NonEmptyString,\n}) {}\n\n/**\n * Get the group path from a function path.\n */\nexport const groupPath = (functionPath: FunctionPath): GroupPath.GroupPath =>\n functionPath.groupPath;\n\n/**\n * Get the function name from a function path.\n */\nexport const name = (functionPath: FunctionPath): string => functionPath.name;\n\n/**\n * Get the function path as a string.\n */\nexport const toString = (functionPath: FunctionPath): string =>\n `${GroupPath.toString(functionPath.groupPath)}.${functionPath.name}`;\n"],"mappings":";;;;;;AAMA,IAAa,eAAb,cAAkC,OAAO,MAAoB,cAAc,CAAC,CAAC;CAC3E,WAAWA;CACX,MAAM,OAAO;AACf,CAAC,CAAC,CAAC,CAAC;;;;AAKJ,MAAa,aAAa,iBACxB,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionPaths.mjs","names":["FunctionPath.FunctionPath","GroupPath.make","GroupPath.append","FunctionPath.groupPath"],"sources":["../src/FunctionPaths.ts"],"sourcesContent":["import { type GroupSpec, Spec } from \"@confect/core\";\nimport { pipe } from \"effect/Function\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\n\nexport const FunctionPaths = Schema.HashSet(FunctionPath.FunctionPath).pipe(\n Schema.brand(\"@confect/cli/FunctionPaths\"),\n);\nexport type FunctionPaths = typeof FunctionPaths.Type;\n\nexport const make = (spec: Spec.AnyWithProps): FunctionPaths =>\n makeHelper(\n Spec.groups(spec),\n Option.none(),\n FunctionPaths.make(HashSet.empty()),\n );\n\nconst makeHelper = (\n groups: {\n [key: string]: GroupSpec.AnyWithProps;\n },\n currentGroupPath: Option.Option<GroupPath.GroupPath>,\n apiPaths: FunctionPaths,\n): FunctionPaths =>\n Record.reduce(groups, apiPaths, (acc, group, groupName) => {\n const groupPath = Option.match(currentGroupPath, {\n onNone: () => GroupPath.make([groupName]),\n onSome: (path) => GroupPath.append(path, groupName),\n });\n\n const accWithFunctions = Record.reduce(\n group.functions,\n acc,\n (acc_, _fn, name) =>\n FunctionPaths.make(\n HashSet.add(\n acc_,\n FunctionPath.FunctionPath.make({\n groupPath,\n name,\n }),\n ),\n ),\n );\n\n return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);\n });\n\nexport const groupPaths = (\n functionPaths: FunctionPaths,\n): GroupPaths.GroupPaths =>\n pipe(functionPaths, HashSet.map(FunctionPath.groupPath), (paths) =>\n GroupPaths.GroupPaths.make(paths),\n );\n\nexport const diff = (\n previousFunctions: FunctionPaths,\n currentFunctions: FunctionPaths,\n): {\n functionsAdded: FunctionPaths;\n functionsRemoved: FunctionPaths;\n groupsRemoved: GroupPaths.GroupPaths;\n groupsAdded: GroupPaths.GroupPaths;\n groupsChanged: GroupPaths.GroupPaths;\n} => {\n const currentGroups = groupPaths(currentFunctions);\n const previousGroups = groupPaths(previousFunctions);\n\n const groupsAdded = GroupPaths.GroupPaths.make(\n HashSet.difference(currentGroups, previousGroups),\n );\n const groupsRemoved = GroupPaths.GroupPaths.make(\n HashSet.difference(previousGroups, currentGroups),\n );\n\n const functionsAdded = FunctionPaths.make(\n HashSet.difference(currentFunctions, previousFunctions),\n );\n const existingGroupsToWhichFunctionsWereAdded = GroupPaths.GroupPaths.make(\n HashSet.intersection(currentGroups, groupPaths(functionsAdded)),\n );\n\n const functionsRemoved = FunctionPaths.make(\n HashSet.difference(previousFunctions, currentFunctions),\n );\n const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.GroupPaths.make(\n HashSet.intersection(previousGroups, groupPaths(functionsRemoved)),\n );\n\n const groupsChanged = pipe(\n existingGroupsToWhichFunctionsWereAdded,\n HashSet.union(existingGroupsToWhichFunctionsWereRemoved),\n HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)),\n (paths) => GroupPaths.GroupPaths.make(paths),\n );\n\n return {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n };\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,gBAAgB,OAAO,QAAQA,YAAyB,CAAC,CAAC,KACrE,OAAO,MAAM,4BAA4B,CAC3C;AAGA,MAAa,QAAQ,SACnB,WACE,KAAK,OAAO,IAAI,GAChB,OAAO,KAAK,GACZ,cAAc,KAAK,QAAQ,MAAM,CAAC,CACpC;AAEF,MAAM,cACJ,QAGA,kBACA,aAEA,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,cAAc;CACzD,MAAM,YAAY,OAAO,MAAM,kBAAkB;EAC/C,cAAcC,OAAe,CAAC,SAAS,CAAC;EACxC,SAAS,SAASC,OAAiB,MAAM,SAAS;CACpD,CAAC;CAED,MAAM,mBAAmB,OAAO,OAC9B,MAAM,WACN,MACC,MAAM,KAAK,SACV,cAAc,KACZ,QAAQ,IACN,MAAA,aAC0B,KAAK;EAC7B;EACA;CACF,CAAC,CACH,CACF,CACJ;CAEA,OAAO,WAAW,MAAM,QAAQ,OAAO,KAAK,SAAS,GAAG,gBAAgB;AAC1E,CAAC;AAEH,MAAa,cACX,kBAEA,KAAK,eAAe,QAAQ,IAAIC,SAAsB,IAAI,UAAA,WAClC,KAAK,KAAK,CAClC;AAEF,MAAa,QACX,mBACA,qBAOG;CACH,MAAM,gBAAgB,WAAW,gBAAgB;CACjD,MAAM,iBAAiB,WAAW,iBAAiB;CAEnD,MAAM,cAAA,WAAoC,KACxC,QAAQ,WAAW,eAAe,cAAc,CAClD;CACA,MAAM,gBAAA,WAAsC,KAC1C,QAAQ,WAAW,gBAAgB,aAAa,CAClD;CAEA,MAAM,iBAAiB,cAAc,KACnC,QAAQ,WAAW,kBAAkB,iBAAiB,CACxD;CACA,MAAM,0CAAA,WAAgE,KACpE,QAAQ,aAAa,eAAe,WAAW,cAAc,CAAC,CAChE;CAEA,MAAM,mBAAmB,cAAc,KACrC,QAAQ,WAAW,mBAAmB,gBAAgB,CACxD;CACA,MAAM,4CAAA,WAAkE,KACtE,QAAQ,aAAa,gBAAgB,WAAW,gBAAgB,CAAC,CACnE;CASA,OAAO;EACL;EACA;EACA;EACA;EACA,eAZoB,KACpB,yCACA,QAAQ,MAAM,yCAAyC,GACvD,QAAQ,WAAW,QAAQ,MAAM,aAAa,aAAa,CAAC,IAC3D,UAAA,WAAgC,KAAK,KAAK,CAQ/B;CACd;AACF"}
1
+ {"version":3,"file":"FunctionPaths.mjs","names":["FunctionPath.FunctionPath","GroupPath.make","GroupPath.append","FunctionPath.groupPath"],"sources":["../src/FunctionPaths.ts"],"sourcesContent":["import { type GroupSpec, Spec } from \"@confect/core\";\nimport { pipe } from \"effect/Function\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport * as FunctionPath from \"./FunctionPath.js\";\nimport * as GroupPath from \"./GroupPath.js\";\nimport * as GroupPaths from \"./GroupPaths.js\";\n\nexport const FunctionPaths = Schema.HashSet(FunctionPath.FunctionPath).pipe(\n Schema.brand(\"@confect/cli/FunctionPaths\"),\n);\nexport type FunctionPaths = typeof FunctionPaths.Type;\n\nexport const make = (spec: Spec.AnyWithProps): FunctionPaths =>\n makeHelper(\n Spec.groups(spec),\n Option.none(),\n FunctionPaths.make(HashSet.empty()),\n );\n\nconst makeHelper = (\n groups: {\n [key: string]: GroupSpec.AnyWithProps;\n },\n currentGroupPath: Option.Option<GroupPath.GroupPath>,\n apiPaths: FunctionPaths,\n): FunctionPaths =>\n Record.reduce(groups, apiPaths, (acc, group, groupName) => {\n const groupPath = Option.match(currentGroupPath, {\n onNone: () => GroupPath.make([groupName]),\n onSome: (path) => GroupPath.append(path, groupName),\n });\n\n const accWithFunctions = Record.reduce(\n group.functions,\n acc,\n (acc_, _fn, name) =>\n FunctionPaths.make(\n HashSet.add(\n acc_,\n FunctionPath.FunctionPath.make({\n groupPath,\n name,\n }),\n ),\n ),\n );\n\n return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);\n });\n\nexport const groupPaths = (\n functionPaths: FunctionPaths,\n): GroupPaths.GroupPaths =>\n pipe(functionPaths, HashSet.map(FunctionPath.groupPath), (paths) =>\n GroupPaths.GroupPaths.make(paths),\n );\n\nexport const diff = (\n previousFunctions: FunctionPaths,\n currentFunctions: FunctionPaths,\n): {\n functionsAdded: FunctionPaths;\n functionsRemoved: FunctionPaths;\n groupsRemoved: GroupPaths.GroupPaths;\n groupsAdded: GroupPaths.GroupPaths;\n groupsChanged: GroupPaths.GroupPaths;\n} => {\n const currentGroups = groupPaths(currentFunctions);\n const previousGroups = groupPaths(previousFunctions);\n\n const groupsAdded = GroupPaths.GroupPaths.make(\n HashSet.difference(currentGroups, previousGroups),\n );\n const groupsRemoved = GroupPaths.GroupPaths.make(\n HashSet.difference(previousGroups, currentGroups),\n );\n\n const functionsAdded = FunctionPaths.make(\n HashSet.difference(currentFunctions, previousFunctions),\n );\n const existingGroupsToWhichFunctionsWereAdded = GroupPaths.GroupPaths.make(\n HashSet.intersection(currentGroups, groupPaths(functionsAdded)),\n );\n\n const functionsRemoved = FunctionPaths.make(\n HashSet.difference(previousFunctions, currentFunctions),\n );\n const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.GroupPaths.make(\n HashSet.intersection(previousGroups, groupPaths(functionsRemoved)),\n );\n\n const groupsChanged = pipe(\n existingGroupsToWhichFunctionsWereAdded,\n HashSet.union(existingGroupsToWhichFunctionsWereRemoved),\n HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)),\n (paths) => GroupPaths.GroupPaths.make(paths),\n );\n\n return {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n };\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,gBAAgB,OAAO,QAAQA,YAAyB,CAAC,CAAC,KACrE,OAAO,MAAM,4BAA4B,CAC3C;AAGA,MAAa,QAAQ,SACnB,WACE,KAAK,OAAO,IAAI,GAChB,OAAO,KAAK,GACZ,cAAc,KAAK,QAAQ,MAAM,CAAC,CACpC;AAEF,MAAM,cACJ,QAGA,kBACA,aAEA,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,cAAc;CACzD,MAAM,YAAY,OAAO,MAAM,kBAAkB;EAC/C,cAAcC,OAAe,CAAC,SAAS,CAAC;EACxC,SAAS,SAASC,OAAiB,MAAM,SAAS;CACpD,CAAC;CAED,MAAM,mBAAmB,OAAO,OAC9B,MAAM,WACN,MACC,MAAM,KAAK,SACV,cAAc,KACZ,QAAQ,IACN,MAAA,aAC0B,KAAK;EAC7B;EACA;CACF,CAAC,CACH,CACF,CACJ;CAEA,OAAO,WAAW,MAAM,QAAQ,OAAO,KAAK,SAAS,GAAG,gBAAgB;AAC1E,CAAC;AAEH,MAAa,cACX,kBAEA,KAAK,eAAe,QAAQ,IAAIC,SAAsB,IAAI,UAAA,WAClC,KAAK,KAAK,CAClC;AAEF,MAAa,QACX,mBACA,qBAOG;CACH,MAAM,gBAAgB,WAAW,gBAAgB;CACjD,MAAM,iBAAiB,WAAW,iBAAiB;CAEnD,MAAM,cAAA,WAAoC,KACxC,QAAQ,WAAW,eAAe,cAAc,CAClD;CACA,MAAM,gBAAA,WAAsC,KAC1C,QAAQ,WAAW,gBAAgB,aAAa,CAClD;CAEA,MAAM,iBAAiB,cAAc,KACnC,QAAQ,WAAW,kBAAkB,iBAAiB,CACxD;CACA,MAAM,0CAAA,WAAgE,KACpE,QAAQ,aAAa,eAAe,WAAW,cAAc,CAAC,CAChE;CAEA,MAAM,mBAAmB,cAAc,KACrC,QAAQ,WAAW,mBAAmB,gBAAgB,CACxD;CACA,MAAM,4CAAA,WAAkE,KACtE,QAAQ,aAAa,gBAAgB,WAAW,gBAAgB,CAAC,CACnE;CASA,OAAO;EACL;EACA;EACA;EACA;EACA,eAZoB,KACpB,yCACA,QAAQ,MAAM,yCAAyC,GACvD,QAAQ,WAAW,QAAQ,MAAM,aAAa,aAAa,CAAC,IAC3D,UAAA,WAAgC,KAAK,KAAK,CAQ/B;CACd;AACF"}
@@ -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":"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"}
@@ -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 +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":"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"}
1
+ {"version":3,"file":"LeafModule.mjs","names":["Bundler.importersOfPackage","Bundler.bundle","Bundler.directlyImports","Bundler.withBatch"],"sources":["../src/LeafModule.ts"],"sourcesContent":["import { GroupSpec, MiddlewareAttachment } from \"@confect/core\";\nimport { Registry, type RegistryItems } from \"@confect/server\";\nimport * as GroupImpl from \"@confect/server/GroupImpl\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport type { Context } from \"effect\";\nimport * as Array from \"effect/Array\";\nimport * as Brand from \"effect/Brand\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\nimport * as String from \"effect/String\";\nimport { fromBundlerError } from \"./BuildError.js\";\nimport * as Bundler from \"./Bundler.js\";\nimport {\n MissingImplFileError,\n MissingSpecFileError,\n ImplMissingDefaultLayerError,\n ImplMissingFunctionsError,\n ImplMissingMiddlewareError,\n ImplMissingSpecImportError,\n ImplNotFinalizedError,\n InvalidMiddlewareAttachmentError,\n SpecImportsServerError,\n SpecMissingDefaultGroupSpecError,\n} from \"./CodegenError.js\";\nimport { ConfectDirectory } from \"./ConfectDirectory.js\";\nimport { ImplModulePath } from \"./ImplModulePath.js\";\nimport { removePathExtension, toPosixPath } from \"./utils.js\";\n\nexport interface LeafModule {\n readonly relativePath: string;\n readonly pathSegments: readonly [string, ...string[]];\n readonly groupPathDot: string;\n readonly exportName: string;\n readonly specImportPath: string;\n}\n\nexport type LoadedLeafModule = LeafModule & {\n readonly spec: GroupSpec.AnyWithProps;\n} & Brand.Brand<\"@confect/cli/LoadedLeafModule\">;\n\nconst LoadedLeafModule = Brand.nominal<LoadedLeafModule>();\n\nconst VALIDATION_CONCURRENCY = 4;\n\nexport const SPEC_SUFFIX = \".spec.ts\";\nexport const IMPL_SUFFIX = \".impl.ts\";\n\nconst swapModuleSuffix = Effect.fnUntraced(function* (\n relativePath: string,\n fromSuffix: string,\n toSuffix: string,\n) {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n if (ext !== \".ts\" || !name.endsWith(fromSuffix.slice(0, -\".ts\".length))) {\n return relativePath;\n }\n\n const stem = name.slice(0, -fromSuffix.slice(0, -\".ts\".length).length);\n const nextName = `${stem}${toSuffix.slice(0, -\".ts\".length)}`;\n return dir.length > 0\n ? path.join(dir, `${nextName}${ext}`)\n : `${nextName}${ext}`;\n});\n\nexport const isLeafSpecPath = (relativePath: string) =>\n relativePath.endsWith(SPEC_SUFFIX);\n\nexport const exportNameFromModulePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { name, ext } = path.parse(relativePath);\n if (ext !== \".ts\") {\n return name;\n }\n return name.endsWith(\".spec\") ? name.slice(0, -\".spec\".length) : name;\n});\n\nexport const groupPathFromRelativeModulePath = Effect.fnUntraced(function* (\n relativePath: string,\n) {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n const stem =\n ext === \".ts\" && name.endsWith(\".spec\")\n ? name.slice(0, -\".spec\".length)\n : name;\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n const pathSegments = Array.append(dirSegments, stem) as [string, ...string[]];\n return {\n pathSegments,\n groupPathDot: Array.join(pathSegments, \".\"),\n };\n});\n\nexport const specImportPathFromGenerated = Effect.fnUntraced(function* (\n specRelativePath: string,\n) {\n const path = yield* Path.Path;\n const withoutExt = toPosixPath(\n path,\n yield* removePathExtension(specRelativePath),\n );\n return `../${withoutExt}`;\n});\n\nexport const specPathForImpl = (implRelativePath: string) =>\n swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);\n\nexport const implPathForSpec = (specRelativePath: string) =>\n swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);\n\nexport const registeredFunctionsRelativePath = Effect.fnUntraced(function* (\n leaf: LeafModule,\n) {\n const path = yield* Path.Path;\n return path.join(\"registeredFunctions\", ...leaf.pathSegments) + \".ts\";\n});\n\nexport const discoverLeafSpecFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = HashSet.make(\"_generated\", \"tables\", \"middleware\");\n const excludedFiles = HashSet.make(\"nodeSpec.ts\", \"spec.ts\");\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafSpecPath(relativePath)) {\n return false;\n }\n\n if (HashSet.has(excludedFiles, relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) =>\n HashSet.has(excludedDirs, segment),\n );\n });\n});\n\nexport const discoverLeafImplFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = HashSet.make(\"_generated\", \"tables\", \"middleware\");\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(\n Array.filterMap(allPaths, (relativePath) =>\n Schema.decodeResult(ImplModulePath)(relativePath),\n ),\n (relativePath) => {\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) =>\n HashSet.has(excludedDirs, segment),\n );\n },\n );\n});\n\nexport const toLeafModule = Effect.fnUntraced(function* (\n specRelativePath: string,\n) {\n const exportName = yield* exportNameFromModulePath(specRelativePath);\n const { pathSegments, groupPathDot } =\n yield* groupPathFromRelativeModulePath(specRelativePath);\n const specImportPath = yield* specImportPathFromGenerated(specRelativePath);\n\n return {\n relativePath: specRelativePath,\n pathSegments,\n groupPathDot,\n exportName,\n specImportPath,\n } satisfies LeafModule;\n});\n\nconst absoluteModulePath = Effect.fnUntraced(function* (relativePath: string) {\n const confectDirectory = yield* ConfectDirectory.get;\n const path = yield* Path.Path;\n return path.resolve(confectDirectory, relativePath);\n});\n\n/**\n * Every `*.spec.ts` is reachable from `_generated/spec.ts`, which the client\n * imports through `_generated/refs.ts`—so a spec's whole import graph is\n * bundled into the browser whether or not the client calls those functions.\n * Server logic co-located with a declaration therefore ships to users,\n * silently.\n *\n * `@confect/server` is a sound proxy for \"server logic lives here\": an\n * implementation can't be written without `FunctionImpl`/`MiddlewareImpl`, both\n * of which live there. Table `Doc`/`Fields` schemas live in `@confect/core`, so\n * the documented `notes.Doc` pattern in a spec must not reach `@confect/server`\n * even through `tables/` or `_generated/`. The check runs over the spec\n * bundle's transitive inputs rather than the spec module alone, so it also\n * covers middleware declarations under `confect/middleware/` (which codegen\n * otherwise never visits) and any shared helper a spec pulls in—while only ever\n * flagging modules that genuinely reach the client.\n */\nconst validateClientSafety = Effect.fnUntraced(function* (\n leaf: LeafModule,\n bundled: Bundler.Bundled,\n) {\n const path = yield* Path.Path;\n const confectDirectory = path.resolve(yield* ConfectDirectory.get);\n\n const isCheckedUserModule = (absolutePath: string) => {\n const relative = path.relative(confectDirectory, absolutePath);\n return !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n };\n\n const importers = Bundler.importersOfPackage(\n bundled,\n \"@confect/server\",\n isCheckedUserModule,\n );\n\n if (importers.length > 0) {\n return yield* new SpecImportsServerError({\n specPath: leaf.relativePath,\n importerPaths: Array.map(importers, (absolutePath) =>\n toPosixPath(path, path.relative(confectDirectory, absolutePath)),\n ),\n });\n }\n});\n\n/**\n * Validate that the leaf's spec file default-exports a `GroupSpec`, and that\n * nothing it reaches drags server code into the client (see\n * {@link validateClientSafety}). Returns the leaf paired with its validated\n * spec, so subsequent operations reuse that association without re-bundling.\n * The runtime is declared by the spec, not its file location.\n */\nexport const loadSpec = Effect.fn(\"LeafModule.loadSpec\")(function* (\n leaf: LeafModule,\n) {\n const absolutePath = yield* absoluteModulePath(leaf.relativePath);\n const bundled = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n\n const groupSpec = bundled.module.default;\n\n if (!GroupSpec.isGroupSpec(groupSpec)) {\n return yield* new SpecMissingDefaultGroupSpecError({\n specPath: leaf.relativePath,\n });\n }\n\n yield* validateClientSafety(leaf, bundled);\n\n yield* Effect.fromResult(GroupSpec.validateMiddleware(groupSpec)).pipe(\n Effect.mapError(\n (error) =>\n new InvalidMiddlewareAttachmentError({\n specPath: leaf.relativePath,\n message: MiddlewareAttachment.formatValidationError(error),\n }),\n ),\n );\n\n return LoadedLeafModule({\n ...leaf,\n spec: groupSpec,\n });\n});\n\n/**\n * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The\n * lookup is value-shaped (via `GroupImpl.isFinalizedGroupImpl`) so we don't\n * need to know the group's path up front to construct a typed tag for it.\n */\nconst findFinalizedGroupImpl = <S>(\n context: Context.Context<S>,\n): Option.Option<GroupImpl.AnyFinalized> =>\n Array.findFirst(context.mapUnsafe.values(), GroupImpl.isFinalizedGroupImpl);\n\n/**\n * Build the impl layer with a fresh `Registry` so each validation is isolated\n * from prior validations' `FunctionImpl.make` writes. The CLI no longer reads\n * the registry directly—`GroupImpl.finalize` snapshots the registered function\n * names onto the produced `Finalized` `GroupImpl` service value—but a fresh\n * `Ref` is still required because the default `Context.Reference` is cached\n * globally and would otherwise accumulate items across impls.\n */\nconst buildImplLayer = Effect.fnUntraced(function* (\n implLayer: Layer.Layer<unknown>,\n) {\n const registry = Ref.makeUnsafe<RegistryItems.RegistryItems>({});\n return yield* Layer.build(\n implLayer as Layer.Layer<unknown, never, never>,\n ).pipe(Effect.provideService(Registry.Registry, registry));\n}, Effect.scoped);\n\n/**\n * Validate that the leaf's sibling impl file imports the spec, default-exports\n * a finalized `GroupImpl` layer, and provides a `FunctionImpl` for every\n * function declared by the spec.\n */\nexport const validateImpl = Effect.fn(\"LeafModule.validateImpl\")(function* (\n leaf: LoadedLeafModule,\n) {\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const implAbsolutePath = yield* absoluteModulePath(implRelativePath);\n const specAbsolutePath = yield* absoluteModulePath(leaf.relativePath);\n\n const bundled = yield* Bundler.bundle(implAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(implRelativePath, error)),\n );\n\n if (\n !(yield* Bundler.directlyImports(\n bundled,\n implAbsolutePath,\n specAbsolutePath,\n ))\n ) {\n return yield* new ImplMissingSpecImportError({\n implPath: implRelativePath,\n expectedSpecPath: leaf.relativePath,\n });\n }\n\n if (!Layer.isLayer(bundled.module.default)) {\n return yield* new ImplMissingDefaultLayerError({\n implPath: implRelativePath,\n });\n }\n\n const groupSpec = leaf.spec;\n const expectedFunctionNames = Object.keys(groupSpec.functions);\n\n const context = yield* buildImplLayer(\n bundled.module.default as Layer.Layer<unknown>,\n );\n const finalizedGroupImpl = yield* Option.match(\n findFinalizedGroupImpl(context),\n {\n onNone: () => new ImplNotFinalizedError({ implPath: implRelativePath }),\n onSome: Effect.succeed,\n },\n );\n\n const registeredSet = HashSet.fromIterable(\n finalizedGroupImpl.registeredFunctionNames,\n );\n const missing = expectedFunctionNames.filter(\n (name) => !HashSet.has(registeredSet, name),\n );\n\n if (missing.length > 0) {\n return yield* new ImplMissingFunctionsError({\n implPath: implRelativePath,\n groupPath: leaf.groupPathDot,\n missingFunctionNames: missing,\n });\n }\n\n const expectedMiddlewareKeys = Array.dedupe([\n ...(groupSpec.middlewareSpecs ?? []).map(\n (middlewareSpec) => middlewareSpec.key,\n ),\n ...Object.values(groupSpec.functions).flatMap((function_) =>\n (function_.middlewareSpecs ?? []).map(\n (middlewareSpec) => middlewareSpec.key,\n ),\n ),\n ]);\n const registeredMiddlewareKeys = HashSet.fromIterable(\n finalizedGroupImpl.registeredMiddlewareKeys ?? [],\n );\n const missingMiddleware = Array.filter(\n expectedMiddlewareKeys,\n (key) => !HashSet.has(registeredMiddlewareKeys, key),\n );\n\n if (missingMiddleware.length > 0) {\n return yield* new ImplMissingMiddlewareError({\n implPath: implRelativePath,\n groupPath: leaf.groupPathDot,\n missingMiddlewareKeys: missingMiddleware,\n });\n }\n});\n\nexport const withImplFiles = Effect.fnUntraced(function* <A, E, R>(\n relativePaths: ReadonlyArray<ImplModulePath>,\n use: (leaves: ReadonlyArray<LoadedLeafModule>) => Effect.Effect<A, E, R>,\n) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const pairs = yield* Effect.forEach(relativePaths, (implRelativePath) =>\n specPathForImpl(implRelativePath).pipe(\n Effect.map((specRelativePath) => ({\n implRelativePath,\n specRelativePath,\n })),\n ),\n );\n\n return yield* Bundler.withBatch(\n pairs.flatMap(({ implRelativePath, specRelativePath }) => [\n path.resolve(confectDirectory, implRelativePath),\n path.resolve(confectDirectory, specRelativePath),\n ]),\n Effect.gen(function* () {\n const leaves = yield* Effect.forEach(\n pairs,\n Effect.fnUntraced(function* ({ implRelativePath, specRelativePath }) {\n if (\n !(yield* fs.exists(path.join(confectDirectory, specRelativePath)))\n ) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n if (\n !(yield* fs.exists(path.join(confectDirectory, implRelativePath)))\n ) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n const leaf = yield* loadSpec(yield* toLeafModule(specRelativePath));\n return leaf;\n }),\n { concurrency: VALIDATION_CONCURRENCY },\n );\n return yield* use(leaves);\n }),\n );\n});\n\nexport const validateImplFiles = Effect.fn(\"LeafModule.validateImplFiles\")(\n (relativePaths: ReadonlyArray<ImplModulePath>) =>\n withImplFiles(relativePaths, validateAllImpls),\n);\n\nexport const validateAllImpls = Effect.fnUntraced(function* (\n leaves: ReadonlyArray<LoadedLeafModule>,\n) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implementationPaths = yield* Effect.forEach(\n leaves,\n ({ relativePath }) =>\n implPathForSpec(relativePath).pipe(\n Effect.map((implPath) => path.resolve(confectDirectory, implPath)),\n ),\n );\n yield* Bundler.withBatch(\n implementationPaths,\n Effect.forEach(leaves, validateImpl, {\n concurrency: VALIDATION_CONCURRENCY,\n discard: true,\n }),\n );\n});\n\nexport const loadAll = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const results = yield* Bundler.withBatch(\n specFiles.map((relativePath) =>\n path.resolve(confectDirectory, relativePath),\n ),\n Effect.forEach(\n specFiles,\n Effect.fnUntraced(function* (specRelativePath: string) {\n const discovered = yield* toLeafModule(specRelativePath);\n const leaf = yield* loadSpec(discovered);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return leaf;\n }),\n { concurrency: VALIDATION_CONCURRENCY },\n ),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n return results;\n});\n\n/**\n * Walk leaf ancestors and fail with a {@link ParentChildNameCollisionError} when\n * a parent leaf declares a function or subgroup whose name matches a sibling\n * subdirectory spec's segment. Without this check the colliding descendant\n * would overwrite the parent's entry in the assembled `GroupSpec.groups` map at\n * runtime, surfacing as a confusing `Refs.make` error rather than a\n * codegen-time diagnostic.\n */\nconst validateOrphanImpls = Effect.fnUntraced(function* (\n specFiles: ReadonlyArray<string>,\n) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = HashSet.fromIterable(specFiles);\n\n yield* Effect.forEach(\n implFiles,\n Effect.fnUntraced(function* (implRelativePath: string) {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (HashSet.has(specPaths, specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n});\n"],"mappings":"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"}
@@ -1 +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"}