@confect/cli 8.0.0 → 9.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -1
- package/dist/BuildError.mjs +101 -0
- package/dist/BuildError.mjs.map +1 -0
- package/dist/Bundler.mjs +91 -0
- package/dist/Bundler.mjs.map +1 -0
- package/dist/CodeBlockWriter.mjs +55 -0
- package/dist/CodeBlockWriter.mjs.map +1 -0
- package/dist/CodegenError.mjs +94 -0
- package/dist/CodegenError.mjs.map +1 -0
- package/dist/FunctionPaths.mjs +1 -1
- package/dist/LeafModule.mjs +167 -0
- package/dist/LeafModule.mjs.map +1 -0
- package/dist/SpecAssemblyNode.mjs +33 -0
- package/dist/SpecAssemblyNode.mjs.map +1 -0
- package/dist/confect/codegen.mjs +222 -72
- package/dist/confect/codegen.mjs.map +1 -1
- package/dist/confect/dev.mjs +234 -180
- package/dist/confect/dev.mjs.map +1 -1
- package/dist/log.mjs +13 -1
- package/dist/log.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/templates.mjs +65 -72
- package/dist/templates.mjs.map +1 -1
- package/dist/utils.mjs +77 -73
- package/dist/utils.mjs.map +1 -1
- package/package.json +4 -3
- package/src/BuildError.ts +210 -0
- package/src/Bundler.ts +144 -0
- package/src/CodeBlockWriter.ts +65 -0
- package/src/CodegenError.ts +344 -0
- package/src/LeafModule.ts +313 -0
- package/src/SpecAssemblyNode.ts +82 -0
- package/src/confect/codegen.ts +390 -141
- package/src/confect/dev.ts +556 -435
- package/src/log.ts +21 -0
- package/src/templates.ts +141 -109
- package/src/utils.ts +118 -93
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.mjs","names":["templates.api","templates.nodeApi","templates.schema","templates.services","templates.registeredFunctions","templates.nodeRegisteredFunctions","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { DatabaseSchema, Spec } from \"@confect/core\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Match, Option } from \"effect\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as templates from \"../templates\";\nimport {\n bundleAndImport,\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n writeFileStringAndLog,\n} from \"../utils\";\n\nconst getNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, \"nodeSpec.ts\");\n});\n\nconst loadNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const nodeSpecModule = yield* bundleAndImport(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.die(\"nodeSpec.ts does not export a valid Node Spec\");\n }\n\n return Option.some(nodeSpec);\n});\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler;\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n yield* Effect.all(\n [\n generateApi,\n generateRefs,\n generateRegisteredFunctions,\n generateNodeApi,\n generateNodeRegisteredFunctions,\n generateServices,\n ],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* fs.remove(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const specPath = path.join(confectDirectory, \"spec.ts\");\n\n const specModule = yield* bundleAndImport(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.die(\"spec.ts does not export a valid Convex Spec\");\n }\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecOption = yield* loadNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n yield* bundleAndImport(confectSchemaPath).pipe(\n Effect.andThen((schemaModule) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isDatabaseSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.die(\"Invalid schema module\");\n }),\n );\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRegisteredFunctions = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const registeredFunctionsPath = path.join(\n confectGeneratedDirectory,\n \"registeredFunctions.ts\",\n );\n const implImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(registeredFunctionsPath),\n path.join(confectDirectory, \"impl.ts\"),\n ),\n );\n\n const registeredFunctionsContents = yield* templates.registeredFunctions({\n implImportPath,\n });\n\n yield* writeFileStringAndLog(\n registeredFunctionsPath,\n registeredFunctionsContents,\n );\n});\n\nexport const generateNodeRegisteredFunctions = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeRegisteredFunctionsPath = path.join(\n confectDirectory,\n \"_generated\",\n \"nodeRegisteredFunctions.ts\",\n );\n\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n\n if (!nodeImplExists || !nodeSpecExists) {\n if (yield* fs.exists(nodeRegisteredFunctionsPath)) {\n yield* fs.remove(nodeRegisteredFunctionsPath);\n yield* logFileRemoved(nodeRegisteredFunctionsPath);\n }\n return;\n }\n\n const nodeImplImportPath = yield* removePathExtension(\n path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),\n );\n\n const nodeRegisteredFunctionsContents =\n yield* templates.nodeRegisteredFunctions({\n nodeImplImportPath,\n });\n\n yield* writeFileStringAndLog(\n nodeRegisteredFunctionsPath,\n nodeRegisteredFunctionsContents,\n );\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* removePathExtension(\n path.relative(refsDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath))\n : null;\n\n const refsContents = yield* templates.refs({\n specImportPath,\n ...(nodeSpecImportPath === null ? {} : { nodeSpecImportPath }),\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","templates.api","templates.nodeApi","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport * as DatabaseSchema from \"@confect/server/DatabaseSchema\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Array, Effect, Either, HashSet, Match, Option, Ref } from \"effect\";\nimport { fromBundlerError } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n MissingImplFileError,\n MissingSchemaFileError,\n MissingSpecFileError,\n SchemaInvalidDefaultExportError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport {\n discoverLeafImplFiles,\n discoverLeafSpecFiles,\n implPathForSpec,\n registeredFunctionsRelativePath,\n specPathForImpl,\n toLeafModule,\n toNodeRegistryLeaf,\n validateImpl,\n validateSpec,\n type LeafModule,\n} from \"../LeafModule\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n} from \"../SpecAssemblyNode\";\nimport * as templates from \"../templates\";\nimport * as Bundler from \"../Bundler\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_SPEC_PATH = \"_generated/spec.ts\";\nconst GENERATED_NODE_SPEC_PATH = \"_generated/nodeSpec.ts\";\n\nconst LEGACY_PATHS = [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n \"notesAndRandom.impl.ts\",\n \"groups.impl.ts\",\n \"_generated/registeredFunctions.ts\",\n \"_generated/nodeRegisteredFunctions.ts\",\n \"_generated/impl.ts\",\n \"_generated/nodeImpl.ts\",\n];\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler.pipe(\n Effect.asVoid,\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.tapAndLog,\n );\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `convex.config.ts` and `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n const tracker = yield* Ref.make(false);\n\n const functionPaths = yield* runCodegen.pipe(\n Effect.provideService(WriteTracker, tracker),\n );\n\n const anyWritesHappened = yield* Ref.get(tracker);\n return { functionPaths, anyWritesHappened };\n});\n\nconst runCodegen = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n // Validate schema first so its missing-file / invalid-default-export\n // diagnostics surface ahead of impl bundling, which transitively depends\n // on schema via `_generated/api.ts` and would otherwise blow up with a\n // less actionable bundler error.\n yield* validateSchema;\n const leaves = yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* generateAssembledSpecs(leaves);\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n yield* Effect.all(\n [generateApi, generateRefs, generateNodeApi, generateServices],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* touchConvexSchema;\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst loadAndValidateLeafModules = 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 leaves = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n yield* validateSpec(leaf);\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 );\n\n yield* validateOrphanImpls(specFiles);\n\n return leaves;\n});\n\nconst validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>\n Effect.gen(function* () {\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 = new Set(specFiles);\n\n yield* Effect.forEach(implFiles, (implRelativePath) =>\n Effect.gen(function* () {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (specPaths.has(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\nconst removeLegacyFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(LEGACY_PATHS, (relativePath) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n }),\n );\n});\n\nconst generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const { convex, node } = partitionByRuntime(leaves);\n\n if (convex.length > 0) {\n const nodes = assemblyNodesFromLeaves(convex);\n const specContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Convex\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_SPEC_PATH),\n specContents,\n );\n }\n\n if (node.length > 0) {\n const nodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n const nodeSpecContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Node\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_NODE_SPEC_PATH),\n nodeSpecContents,\n );\n }\n });\n\nconst validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.forEach(leaves, validateImpl);\n\nconst generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(leaves, (leaf) =>\n Effect.gen(function* () {\n const registryRelativePath =\n yield* registeredFunctionsRelativePath(leaf);\n const registryPath = path.join(\n confectDirectory,\n \"_generated\",\n registryRelativePath,\n );\n const registryDir = path.dirname(registryPath);\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(registryDir))) {\n yield* fs.makeDirectory(registryDir, { recursive: true });\n }\n\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const apiFileName = leaf.runtime === \"Node\" ? \"nodeApi.ts\" : \"api.ts\";\n const apiImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", apiFileName),\n ),\n );\n const implImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, implRelativePath),\n ),\n );\n\n const contents = yield* templates.registeredFunctionsForGroup({\n apiImportPath,\n groupPathDot: leaf.registryGroupPathDot,\n implImportPath,\n layerExportName: leaf.exportName,\n useNode: leaf.runtime === \"Node\",\n });\n\n yield* writeFileStringAndLog(registryPath, contents);\n }),\n );\n });\n\nconst removeObsoleteRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const registryRoot = path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n );\n\n if (!(yield* fs.exists(registryRoot))) {\n return;\n }\n\n const expected = new Set(\n yield* Effect.forEach(leaves, (leaf) =>\n registeredFunctionsRelativePath(leaf),\n ),\n );\n\n const existing = yield* fs.readDirectory(registryRoot, { recursive: true });\n yield* Effect.forEach(existing, (relativePath) => {\n if (path.extname(relativePath) !== \".ts\") {\n return Effect.void;\n }\n const normalized = path.join(\"registeredFunctions\", relativePath);\n if (!expected.has(normalized)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(registryRoot, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n });\n }\n return Effect.void;\n });\n });\n\nconst getGeneratedSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_SPEC_PATH);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_NODE_SPEC_PATH);\n});\n\nconst loadGeneratedSpec = Effect.gen(function* () {\n const specPath = yield* getGeneratedSpecPath;\n const { module: specModule } = yield* Bundler.bundle(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.dieMessage(\n \"_generated/spec.ts does not export a valid Convex Spec\",\n );\n }\n\n return spec;\n});\n\nconst loadGeneratedNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.dieMessage(\n \"_generated/nodeSpec.ts does not export a valid Node Spec\",\n );\n }\n\n return Option.some(nodeSpec);\n});\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\nexport const loadPreviousFunctionPaths = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getGeneratedSpecPath;\n\n if (!(yield* fs.exists(specPath))) {\n return emptyFunctionPaths;\n }\n\n const specEither = yield* loadGeneratedSpec.pipe(Effect.either);\n\n return yield* Either.match(specEither, {\n onLeft: () => Effect.succeed(emptyFunctionPaths),\n onRight: (spec) =>\n Effect.gen(function* () {\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n return FunctionPaths.make(mergedSpec);\n }),\n });\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* removePathIfExists(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const spec = yield* loadGeneratedSpec;\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nexport const validateSchema = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n if (!(yield* fs.exists(confectSchemaPath))) {\n return yield* new MissingSchemaFileError({ schemaPath: \"schema.ts\" });\n }\n\n yield* Bundler.bundle(confectSchemaPath).pipe(\n Effect.mapError((error) => fromBundlerError(\"schema.ts\", error)),\n Effect.andThen(({ module: schemaModule }) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isDatabaseSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.fail(\n new SchemaInvalidDefaultExportError({\n schemaPath: \"schema.ts\",\n }),\n );\n }),\n );\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n // `validateSchema` runs once at the top of `runCodegen`; no need to\n // bundle the schema again here.\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? Option.some(\n yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),\n )\n : Option.none<string>();\n\n const refsContents = yield* templates.refs({\n specImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
|
package/dist/confect/dev.mjs
CHANGED
|
@@ -1,26 +1,35 @@
|
|
|
1
|
-
import { modulePath, toString } from "../GroupPath.mjs";
|
|
2
1
|
import { ProjectRoot } from "../ProjectRoot.mjs";
|
|
3
|
-
import {
|
|
2
|
+
import { logFunctionAdded, logFunctionRemoved, logPending, logSuccess } from "../log.mjs";
|
|
3
|
+
import { logCoalescedBuildErrors } from "../BuildError.mjs";
|
|
4
|
+
import { catchAndLog } from "../CodegenError.mjs";
|
|
4
5
|
import { ConvexDirectory } from "../ConvexDirectory.mjs";
|
|
5
6
|
import { ConfectDirectory } from "../ConfectDirectory.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import { EXTERNAL_PACKAGES,
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { FunctionPaths, diff } from "../FunctionPaths.mjs";
|
|
8
|
+
import { EXTERNAL_PACKAGES, absoluteExternalsPlugin } from "../Bundler.mjs";
|
|
9
|
+
import { generateAuthConfig, generateCrons, generateHttp } from "../utils.mjs";
|
|
10
|
+
import { discoverLeafImplFiles, isLeafImplPath, isLeafSpecPath } from "../LeafModule.mjs";
|
|
11
|
+
import { codegenHandler, loadPreviousFunctionPaths } from "./codegen.mjs";
|
|
12
|
+
import { Array, Chunk, Clock, Console, Duration, Effect, Equal, ExecutionStrategy, Exit, HashSet, Match, Option, Order, Queue, Ref, Scope, Stream, String, pipe } from "effect";
|
|
10
13
|
import { Command } from "@effect/cli";
|
|
11
|
-
import { Spec } from "@confect/core";
|
|
12
14
|
import { FileSystem, Path } from "@effect/platform";
|
|
13
15
|
import { Ansi, AnsiDoc } from "@effect/printer-ansi";
|
|
14
16
|
import * as esbuild from "esbuild";
|
|
15
17
|
|
|
16
18
|
//#region src/confect/dev.ts
|
|
19
|
+
const GENERATED_SPEC_PATH = "_generated/spec.ts";
|
|
20
|
+
const GENERATED_NODE_SPEC_PATH = "_generated/nodeSpec.ts";
|
|
21
|
+
const COALESCE_QUIESCENCE = Duration.millis(300);
|
|
22
|
+
const COALESCE_MAX_WAIT = Duration.seconds(5);
|
|
23
|
+
const ECHO_COOLDOWN = Duration.millis(500);
|
|
24
|
+
const emptyFunctionPaths = FunctionPaths.make(HashSet.empty());
|
|
17
25
|
const pendingInit = {
|
|
18
26
|
specDirty: false,
|
|
19
|
-
nodeImplDirty: false,
|
|
20
27
|
httpDirty: false,
|
|
21
28
|
cronsDirty: false,
|
|
22
29
|
authDirty: false
|
|
23
30
|
};
|
|
31
|
+
const isPendingDirty = (p) => p.specDirty || p.httpDirty || p.cronsDirty || p.authDirty;
|
|
32
|
+
const emptyWatcherErrors = /* @__PURE__ */ new Map();
|
|
24
33
|
const changeChar = (change) => Match.value(change).pipe(Match.when("Added", () => ({
|
|
25
34
|
char: "+",
|
|
26
35
|
color: Ansi.green
|
|
@@ -37,182 +46,255 @@ const logFileChangeIndented = (change, fullPath) => Effect.gen(function* () {
|
|
|
37
46
|
const { char, color } = changeChar(change);
|
|
38
47
|
yield* Console.log(pipe(AnsiDoc.char(char), AnsiDoc.annotate(color), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color))])), AnsiDoc.render({ style: "pretty" })));
|
|
39
48
|
});
|
|
40
|
-
const
|
|
41
|
-
const
|
|
49
|
+
const logFunctionPathDiff = (previous, current) => Effect.gen(function* () {
|
|
50
|
+
const { functionsAdded, functionsRemoved, groupsRemoved, groupsAdded, groupsChanged } = diff(previous, current);
|
|
51
|
+
const logForGroups = (groupPaths, fnPaths, logFn) => Effect.forEach(groupPaths, (gp) => Effect.forEach(Array.fromIterable(HashSet.filter(fnPaths, (fp) => Equal.equals(fp.groupPath, gp))), logFn));
|
|
52
|
+
yield* logForGroups(groupsRemoved, functionsRemoved, logFunctionRemoved);
|
|
53
|
+
yield* logForGroups(groupsAdded, functionsAdded, logFunctionAdded);
|
|
54
|
+
yield* Effect.forEach(groupsChanged, (gp) => Effect.gen(function* () {
|
|
55
|
+
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionAdded);
|
|
56
|
+
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionRemoved);
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
42
59
|
const dev = Command.make("dev", {}, () => Effect.gen(function* () {
|
|
43
60
|
yield* logPending("Performing initial sync…");
|
|
44
|
-
const
|
|
61
|
+
const previousFunctionPaths = yield* loadPreviousFunctionPaths;
|
|
62
|
+
const initialResult = yield* codegenHandler.pipe(Effect.tap(({ functionPaths }) => logFunctionPathDiff(previousFunctionPaths, functionPaths)), Effect.tap(() => logSuccess("Generated files are up-to-date")), catchAndLog);
|
|
63
|
+
const initialFunctionPaths = Option.match(initialResult, {
|
|
64
|
+
onNone: () => emptyFunctionPaths,
|
|
65
|
+
onSome: ({ functionPaths }) => functionPaths
|
|
66
|
+
});
|
|
45
67
|
const pendingRef = yield* Ref.make(pendingInit);
|
|
46
68
|
const signal = yield* Queue.sliding(1);
|
|
47
|
-
const
|
|
69
|
+
const restartQueue = yield* Queue.sliding(1);
|
|
70
|
+
const watcherErrorsRef = yield* Ref.make(emptyWatcherErrors);
|
|
48
71
|
yield* Effect.all([
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
syncLoop(signal, pendingRef, initialFunctionPaths)
|
|
72
|
+
Effect.scoped(entryPointsWatcher(signal, pendingRef, restartQueue, watcherErrorsRef)),
|
|
73
|
+
confectStructureWatcher(signal, pendingRef, restartQueue),
|
|
74
|
+
syncLoop(signal, pendingRef, initialFunctionPaths, watcherErrorsRef)
|
|
52
75
|
], { concurrency: "unbounded" });
|
|
53
76
|
})).pipe(Command.withDescription("Start the Confect development server"));
|
|
54
|
-
const
|
|
77
|
+
const esbuildMessageKey = (m) => `${m.location?.file ?? ""}:${m.location?.line ?? ""}:${m.location?.column ?? ""}:${m.text}`;
|
|
78
|
+
const allMessages = (errors) => pipe(Array.fromIterable(errors.values()), Array.flatten);
|
|
79
|
+
const dedupeWatcherErrors = (errors) => pipe(allMessages(errors), Array.dedupeWith((messageA, messageB) => esbuildMessageKey(messageA) === esbuildMessageKey(messageB)));
|
|
80
|
+
const watcherErrorsSignature = (errors) => pipe(allMessages(errors), Array.map(esbuildMessageKey), Array.dedupe, Array.sort(Order.string), Array.join("\n"));
|
|
81
|
+
/**
|
|
82
|
+
* Log any watcher errors that haven't already been logged at their
|
|
83
|
+
* current signature. Suppresses the per-watcher fanout that happens
|
|
84
|
+
* when one root cause (e.g. a missing import) breaks every entry
|
|
85
|
+
* point's build at the same source location.
|
|
86
|
+
*/
|
|
87
|
+
const logChangedWatcherErrors = (watcherErrorsRef, lastLoggedSignatureRef) => Effect.gen(function* () {
|
|
88
|
+
const errors = yield* Ref.get(watcherErrorsRef);
|
|
89
|
+
const signature = watcherErrorsSignature(errors);
|
|
90
|
+
if (signature === (yield* Ref.get(lastLoggedSignatureRef))) return;
|
|
91
|
+
yield* Ref.set(lastLoggedSignatureRef, signature);
|
|
92
|
+
if (errors.size === 0) return;
|
|
93
|
+
yield* logCoalescedBuildErrors(dedupeWatcherErrors(errors));
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* Block until the signal queue has been quiet for `quiescence`. esbuild
|
|
97
|
+
* watchers' `onEnd` events for a single user edit can be spread across
|
|
98
|
+
* hundreds of milliseconds, so a fixed window misses late arrivals.
|
|
99
|
+
* Bounded by `maxWait` so pathological signal floods can't pin the
|
|
100
|
+
* loop forever.
|
|
101
|
+
*/
|
|
102
|
+
const drainUntilQuiescent = (signal, quiescence, maxWait) => Effect.gen(function* () {
|
|
103
|
+
const start = yield* Clock.currentTimeMillis;
|
|
104
|
+
const maxMillis = Duration.toMillis(maxWait);
|
|
105
|
+
yield* Effect.iterate(true, {
|
|
106
|
+
while: (keepGoing) => keepGoing,
|
|
107
|
+
body: () => Effect.gen(function* () {
|
|
108
|
+
yield* Effect.sleep(quiescence);
|
|
109
|
+
const drained = yield* Queue.takeAll(signal);
|
|
110
|
+
if (Chunk.isEmpty(drained)) return false;
|
|
111
|
+
return (yield* Clock.currentTimeMillis) - start < maxMillis;
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
const syncLoop = (signal, pendingRef, initialFunctionPaths, watcherErrorsRef) => Effect.gen(function* () {
|
|
55
116
|
const functionPathsRef = yield* Ref.make(initialFunctionPaths);
|
|
56
|
-
const
|
|
117
|
+
const lastLoggedErrorsRef = yield* Ref.make("");
|
|
57
118
|
return yield* Effect.forever(Effect.gen(function* () {
|
|
58
|
-
yield* Effect.logDebug("Running sync loop
|
|
119
|
+
yield* Effect.logDebug("Running sync loop…");
|
|
59
120
|
yield* Queue.take(signal);
|
|
60
|
-
|
|
61
|
-
yield*
|
|
62
|
-
yield* Deferred.succeed(initialSyncDone, void 0);
|
|
121
|
+
yield* drainUntilQuiescent(signal, COALESCE_QUIESCENCE, COALESCE_MAX_WAIT);
|
|
122
|
+
yield* logChangedWatcherErrors(watcherErrorsRef, lastLoggedErrorsRef);
|
|
63
123
|
const pending = yield* Ref.getAndSet(pendingRef, pendingInit);
|
|
64
|
-
if (pending
|
|
65
|
-
|
|
66
|
-
|
|
124
|
+
if (!isPendingDirty(pending)) return;
|
|
125
|
+
yield* logPending("Dependencies may have changed, reloading…");
|
|
126
|
+
if (pending.specDirty) {
|
|
127
|
+
const current = yield* codegenHandler.pipe(Effect.tap(({ functionPaths: nextFunctionPaths }) => Effect.gen(function* () {
|
|
128
|
+
yield* logFunctionPathDiff(yield* Ref.get(functionPathsRef), nextFunctionPaths);
|
|
129
|
+
yield* Ref.set(functionPathsRef, nextFunctionPaths);
|
|
130
|
+
})), catchAndLog);
|
|
131
|
+
if (Option.isNone(current)) return;
|
|
132
|
+
if (current.value.anyWritesHappened) yield* Effect.sleep(ECHO_COOLDOWN);
|
|
133
|
+
yield* drainUntilQuiescent(signal, COALESCE_QUIESCENCE, COALESCE_MAX_WAIT);
|
|
134
|
+
yield* Ref.set(pendingRef, pendingInit);
|
|
67
135
|
}
|
|
68
|
-
const specResult = yield* Effect.if(pending.specDirty, {
|
|
69
|
-
onTrue: () => loadSpec.pipe(Effect.andThen(Effect.fn(function* (spec) {
|
|
70
|
-
yield* Effect.logDebug("Spec loaded");
|
|
71
|
-
const previous = yield* Ref.get(functionPathsRef);
|
|
72
|
-
const path = yield* Path.Path;
|
|
73
|
-
const convexDirectory = yield* ConvexDirectory.get;
|
|
74
|
-
const current = make(spec);
|
|
75
|
-
const { functionsAdded, functionsRemoved, groupsRemoved, groupsAdded, groupsChanged } = diff(previous, current);
|
|
76
|
-
yield* removeGroups(groupsRemoved);
|
|
77
|
-
yield* Effect.forEach(groupsRemoved, (gp) => Effect.gen(function* () {
|
|
78
|
-
const relativeModulePath = yield* modulePath(gp);
|
|
79
|
-
yield* logFileChangeIndented("Removed", path.join(convexDirectory, relativeModulePath));
|
|
80
|
-
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionRemovedIndented);
|
|
81
|
-
}));
|
|
82
|
-
yield* writeGroups(spec, groupsAdded);
|
|
83
|
-
yield* Effect.forEach(groupsAdded, (gp) => Effect.gen(function* () {
|
|
84
|
-
const relativeModulePath = yield* modulePath(gp);
|
|
85
|
-
yield* logFileChangeIndented("Added", path.join(convexDirectory, relativeModulePath));
|
|
86
|
-
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionAddedIndented);
|
|
87
|
-
}));
|
|
88
|
-
yield* writeGroups(spec, groupsChanged);
|
|
89
|
-
yield* Effect.forEach(groupsChanged, (gp) => Effect.gen(function* () {
|
|
90
|
-
const relativeModulePath = yield* modulePath(gp);
|
|
91
|
-
yield* logFileChangeIndented("Modified", path.join(convexDirectory, relativeModulePath));
|
|
92
|
-
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionAddedIndented);
|
|
93
|
-
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionRemovedIndented);
|
|
94
|
-
}));
|
|
95
|
-
yield* Ref.set(functionPathsRef, current);
|
|
96
|
-
return Option.some(void 0);
|
|
97
|
-
})), Effect.catchTag("SpecImportFailedError", () => logFailure("Spec import failed").pipe(Effect.as(Option.none()))), Effect.catchTag("SpecFileDoesNotExportSpecError", () => logFailure("Spec file does not default export a Convex spec").pipe(Effect.as(Option.none()))), Effect.catchTag("NodeSpecFileDoesNotExportSpecError", () => logFailure("Node spec file does not default export a Node spec").pipe(Effect.as(Option.none())))),
|
|
98
|
-
onFalse: () => Effect.succeed(Option.some(void 0))
|
|
99
|
-
});
|
|
100
136
|
const dirtyOptionalFiles = [
|
|
101
137
|
...pending.httpDirty ? [syncOptionalFile(generateHttp, "http.ts")] : [],
|
|
102
138
|
...pending.cronsDirty ? [syncOptionalFile(generateCrons, "crons.ts")] : [],
|
|
103
139
|
...pending.authDirty ? [syncOptionalFile(generateAuthConfig, "auth.config.ts")] : []
|
|
104
140
|
];
|
|
105
141
|
yield* Array.isNonEmptyReadonlyArray(dirtyOptionalFiles) ? Effect.all(dirtyOptionalFiles, { concurrency: "unbounded" }) : Effect.void;
|
|
106
|
-
yield*
|
|
107
|
-
onSome: () => logSuccess("Generated files are up-to-date"),
|
|
108
|
-
onNone: () => Effect.void
|
|
109
|
-
});
|
|
142
|
+
yield* logSuccess("Generated files are up-to-date");
|
|
110
143
|
}));
|
|
111
144
|
});
|
|
112
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Every file whose import graph codegen should react to. Each one becomes
|
|
147
|
+
* its own scoped esbuild watcher; the union of their watches gives us
|
|
148
|
+
* dependency-aware tracking of anything reachable from `confect/`,
|
|
149
|
+
* including files outside `confect/`.
|
|
150
|
+
*/
|
|
151
|
+
const discoverEntryPoints = Effect.gen(function* () {
|
|
113
152
|
const fs = yield* FileSystem.FileSystem;
|
|
114
153
|
const path = yield* Path.Path;
|
|
154
|
+
const projectRoot = yield* ProjectRoot.get;
|
|
115
155
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
156
|
+
const tryEntry = (relativePath, pendingKey) => Effect.gen(function* () {
|
|
157
|
+
const absolutePath = path.join(confectDirectory, relativePath);
|
|
158
|
+
if (!(yield* fs.exists(absolutePath))) return Option.none();
|
|
159
|
+
return Option.some({
|
|
160
|
+
absolutePath,
|
|
161
|
+
displayPath: path.relative(projectRoot, absolutePath),
|
|
162
|
+
pendingKey
|
|
163
|
+
});
|
|
124
164
|
});
|
|
165
|
+
const fixedEntryOptions = yield* Effect.all([
|
|
166
|
+
tryEntry(GENERATED_SPEC_PATH, "specDirty"),
|
|
167
|
+
tryEntry(GENERATED_NODE_SPEC_PATH, "specDirty"),
|
|
168
|
+
tryEntry("schema.ts", "specDirty"),
|
|
169
|
+
tryEntry("http.ts", "httpDirty"),
|
|
170
|
+
tryEntry("crons.ts", "cronsDirty"),
|
|
171
|
+
tryEntry("auth.ts", "authDirty")
|
|
172
|
+
]);
|
|
173
|
+
const implRelativePaths = yield* discoverLeafImplFiles;
|
|
174
|
+
const implEntryOptions = yield* Effect.forEach(implRelativePaths, (relativePath) => tryEntry(relativePath, "specDirty"));
|
|
175
|
+
return Array.getSomes([...fixedEntryOptions, ...implEntryOptions]);
|
|
125
176
|
});
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
setup(build) {
|
|
156
|
-
build.onEnd((result) => {
|
|
157
|
-
if (result.errors.length === 0) build._emit?.();
|
|
158
|
-
else Effect.runPromise(Effect.gen(function* () {
|
|
159
|
-
const formattedMessages = yield* Effect.promise(() => esbuild.formatMessages(result.errors, {
|
|
160
|
-
kind: "error",
|
|
161
|
-
color: true,
|
|
162
|
-
terminalWidth: 80
|
|
177
|
+
const esbuildOptions = (entry, signal, pendingRef, watcherErrorsRef) => {
|
|
178
|
+
const initialBuildSeenRef = Ref.unsafeMake(false);
|
|
179
|
+
return {
|
|
180
|
+
entryPoints: [entry.absolutePath],
|
|
181
|
+
bundle: true,
|
|
182
|
+
write: false,
|
|
183
|
+
metafile: true,
|
|
184
|
+
platform: "node",
|
|
185
|
+
format: "esm",
|
|
186
|
+
logLevel: "silent",
|
|
187
|
+
external: EXTERNAL_PACKAGES,
|
|
188
|
+
plugins: [absoluteExternalsPlugin, {
|
|
189
|
+
name: "notify-rebuild",
|
|
190
|
+
setup(build) {
|
|
191
|
+
build.onEnd((result) => {
|
|
192
|
+
Effect.runPromise(Effect.gen(function* () {
|
|
193
|
+
const isInitial = !(yield* Ref.getAndSet(initialBuildSeenRef, true));
|
|
194
|
+
yield* Ref.update(watcherErrorsRef, (current) => {
|
|
195
|
+
const next = new Map(current);
|
|
196
|
+
if (result.errors.length > 0) next.set(entry.absolutePath, result.errors);
|
|
197
|
+
else next.delete(entry.absolutePath);
|
|
198
|
+
return next;
|
|
199
|
+
});
|
|
200
|
+
if (isInitial && result.errors.length === 0) return;
|
|
201
|
+
yield* Ref.update(pendingRef, (p) => ({
|
|
202
|
+
...p,
|
|
203
|
+
[entry.pendingKey]: true
|
|
204
|
+
}));
|
|
205
|
+
yield* Queue.offer(signal, void 0);
|
|
163
206
|
}));
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}));
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}]
|
|
171
|
-
});
|
|
172
|
-
const createSpecWatcher = (entryPoint) => Stream.asyncPush((emit) => Effect.acquireRelease(Effect.promise(async () => {
|
|
173
|
-
const opts = esbuildOptions(entryPoint);
|
|
174
|
-
const plugin = opts.plugins[0];
|
|
175
|
-
const originalSetup = plugin.setup;
|
|
176
|
-
plugin.setup = (build) => {
|
|
177
|
-
build._emit = () => emit.single();
|
|
178
|
-
return originalSetup(build);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}]
|
|
179
210
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
});
|
|
211
|
+
};
|
|
212
|
+
const createEntryPointWatcher = (entry, signal, pendingRef, watcherErrorsRef) => Effect.acquireRelease(Effect.promise(async () => {
|
|
213
|
+
const ctx = await esbuild.context(esbuildOptions(entry, signal, pendingRef, watcherErrorsRef));
|
|
184
214
|
await ctx.watch();
|
|
185
215
|
return ctx;
|
|
186
|
-
}), (ctx) => Effect.
|
|
187
|
-
|
|
188
|
-
|
|
216
|
+
}), (ctx) => Effect.gen(function* () {
|
|
217
|
+
yield* Effect.promise(() => ctx.dispose());
|
|
218
|
+
yield* Ref.update(watcherErrorsRef, (current) => {
|
|
219
|
+
if (!current.has(entry.absolutePath)) return current;
|
|
220
|
+
const next = new Map(current);
|
|
221
|
+
next.delete(entry.absolutePath);
|
|
222
|
+
return next;
|
|
223
|
+
});
|
|
224
|
+
yield* Effect.logDebug(`esbuild watcher disposed: ${entry.displayPath}`);
|
|
225
|
+
}));
|
|
226
|
+
/**
|
|
227
|
+
* Holds one scoped esbuild watcher per entry point and reconciles the set
|
|
228
|
+
* whenever something offers to `restartQueue`. Adding or removing an entry
|
|
229
|
+
* point only spawns/disposes the affected watcher; unchanged entries keep
|
|
230
|
+
* their existing context, so a structural change doesn't churn watchers
|
|
231
|
+
* for unrelated files.
|
|
232
|
+
*/
|
|
233
|
+
const entryPointsWatcher = (signal, pendingRef, restartQueue, watcherErrorsRef) => Effect.gen(function* () {
|
|
234
|
+
const parentScope = yield* Effect.scope;
|
|
235
|
+
const scopesRef = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
236
|
+
const sync = Effect.gen(function* () {
|
|
237
|
+
const desired = yield* discoverEntryPoints;
|
|
238
|
+
const desiredByPath = new Map(desired.map((entryPoint) => [entryPoint.absolutePath, entryPoint]));
|
|
239
|
+
const current = yield* Ref.get(scopesRef);
|
|
240
|
+
yield* Effect.forEach(Array.fromIterable(current), ([absolutePath, childScope]) => desiredByPath.has(absolutePath) ? Effect.void : Scope.close(childScope, Exit.void).pipe(Effect.andThen(Ref.update(scopesRef, (scopes) => {
|
|
241
|
+
const updated = new Map(scopes);
|
|
242
|
+
updated.delete(absolutePath);
|
|
243
|
+
return updated;
|
|
244
|
+
}))));
|
|
245
|
+
yield* Effect.forEach(desired, (entry) => Effect.gen(function* () {
|
|
246
|
+
if ((yield* Ref.get(scopesRef)).has(entry.absolutePath)) return;
|
|
247
|
+
const childScope = yield* Scope.fork(parentScope, ExecutionStrategy.sequential);
|
|
248
|
+
yield* createEntryPointWatcher(entry, signal, pendingRef, watcherErrorsRef).pipe(Scope.extend(childScope));
|
|
249
|
+
yield* Ref.update(scopesRef, (scopes) => {
|
|
250
|
+
const updated = new Map(scopes);
|
|
251
|
+
updated.set(entry.absolutePath, childScope);
|
|
252
|
+
return updated;
|
|
253
|
+
});
|
|
254
|
+
}));
|
|
255
|
+
});
|
|
256
|
+
yield* sync;
|
|
257
|
+
return yield* Effect.forever(Queue.take(restartQueue).pipe(Effect.andThen(sync)));
|
|
189
258
|
});
|
|
190
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Single recursive `fs.watch` on `confect/`. Flips the matching dirty flag
|
|
261
|
+
* for any change to an entry-point-shaped file (so codegen runs without
|
|
262
|
+
* waiting on a newly spawned esbuild watcher), and offers to
|
|
263
|
+
* `restartQueue` when an entry point is created or removed so the watcher
|
|
264
|
+
* manager picks up the new set.
|
|
265
|
+
*/
|
|
266
|
+
const confectStructureWatcher = (signal, pendingRef, restartQueue) => Effect.gen(function* () {
|
|
191
267
|
const fs = yield* FileSystem.FileSystem;
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
268
|
+
const path = yield* Path.Path;
|
|
269
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
270
|
+
yield* pipe(fs.watch(confectDirectory, { recursive: true }), Stream.debounce(Duration.millis(200)), Stream.runForEach((event) => handleConfectChange({
|
|
271
|
+
relativePath: path.relative(confectDirectory, event.path),
|
|
272
|
+
eventTag: event._tag,
|
|
273
|
+
signal,
|
|
274
|
+
pendingRef,
|
|
275
|
+
restartQueue
|
|
276
|
+
})));
|
|
277
|
+
});
|
|
278
|
+
const TOP_LEVEL_OPTIONAL_KEYS = new Map([
|
|
279
|
+
["http.ts", "httpDirty"],
|
|
280
|
+
["crons.ts", "cronsDirty"],
|
|
281
|
+
["auth.ts", "authDirty"]
|
|
282
|
+
]);
|
|
283
|
+
const flipDirtyAndSignal = (pendingRef, signal, key, restartQueue, restart) => pipe(Ref.update(pendingRef, (p) => ({
|
|
284
|
+
...p,
|
|
285
|
+
[key]: true
|
|
286
|
+
})), Effect.andThen(Queue.offer(signal, void 0)), Effect.andThen(restart ? Queue.offer(restartQueue, void 0) : Effect.void));
|
|
287
|
+
const handleConfectChange = ({ relativePath, eventTag, signal, pendingRef, restartQueue }) => {
|
|
288
|
+
if (relativePath.split(/[/\\]/).includes("_generated")) return Effect.void;
|
|
289
|
+
if (!relativePath.endsWith(".ts")) return Effect.void;
|
|
290
|
+
const isLifecycleChange = eventTag !== "Update";
|
|
291
|
+
const topLevelKey = TOP_LEVEL_OPTIONAL_KEYS.get(relativePath);
|
|
292
|
+
if (topLevelKey !== void 0) return flipDirtyAndSignal(pendingRef, signal, topLevelKey, restartQueue, isLifecycleChange);
|
|
293
|
+
if (relativePath === "schema.ts") return flipDirtyAndSignal(pendingRef, signal, "specDirty", restartQueue, isLifecycleChange);
|
|
294
|
+
if (isLeafSpecPath(relativePath) || isLeafImplPath(relativePath)) return flipDirtyAndSignal(pendingRef, signal, "specDirty", restartQueue, isLifecycleChange);
|
|
295
|
+
if (eventTag === "Create") return flipDirtyAndSignal(pendingRef, signal, "specDirty", restartQueue, false);
|
|
296
|
+
return Effect.void;
|
|
211
297
|
};
|
|
212
|
-
const formatBuildErrors = (errors, formattedMessages) => pipe(formattedMessages, Array.map((message, i) => formatBuildError(errors[i], message)), Array.join(""), String.trimEnd);
|
|
213
|
-
var SpecFileDoesNotExportSpecError = class extends Schema.TaggedError()("SpecFileDoesNotExportSpecError", {}) {};
|
|
214
|
-
var NodeSpecFileDoesNotExportSpecError = class extends Schema.TaggedError()("NodeSpecFileDoesNotExportSpecError", {}) {};
|
|
215
|
-
var SpecImportFailedError = class extends Schema.TaggedError()("SpecImportFailedError", { error: Schema.Unknown }) {};
|
|
216
298
|
const syncOptionalFile = (generate, convexFile) => pipe(generate, Effect.andThen(Option.match({
|
|
217
299
|
onSome: ({ change, convexFilePath }) => Match.value(change).pipe(Match.when("Unchanged", () => Effect.void), Match.whenOr("Added", "Modified", (addedOrModified) => logFileChangeIndented(addedOrModified, convexFilePath)), Match.exhaustive),
|
|
218
300
|
onNone: () => Effect.gen(function* () {
|
|
@@ -226,34 +308,6 @@ const syncOptionalFile = (generate, convexFile) => pipe(generate, Effect.andThen
|
|
|
226
308
|
}
|
|
227
309
|
})
|
|
228
310
|
})));
|
|
229
|
-
const optionalConfectFiles = {
|
|
230
|
-
"http.ts": "httpDirty",
|
|
231
|
-
"crons.ts": "cronsDirty",
|
|
232
|
-
"auth.ts": "authDirty",
|
|
233
|
-
"nodeSpec.ts": "specDirty",
|
|
234
|
-
"nodeImpl.ts": "nodeImplDirty"
|
|
235
|
-
};
|
|
236
|
-
const confectDirectoryWatcher = (signal, pendingRef, specWatcherRestartQueue) => Effect.gen(function* () {
|
|
237
|
-
const fs = yield* FileSystem.FileSystem;
|
|
238
|
-
const path = yield* Path.Path;
|
|
239
|
-
const confectDirectory = yield* ConfectDirectory.get;
|
|
240
|
-
yield* pipe(fs.watch(confectDirectory), Stream.runForEach((event) => {
|
|
241
|
-
const basename = path.basename(event.path);
|
|
242
|
-
const pendingKey = optionalConfectFiles[basename];
|
|
243
|
-
if (pendingKey !== void 0) return pipe(pendingRef, Ref.update((pending) => {
|
|
244
|
-
const next = {
|
|
245
|
-
...pending,
|
|
246
|
-
[pendingKey]: true
|
|
247
|
-
};
|
|
248
|
-
if (basename === "nodeImpl.ts") return {
|
|
249
|
-
...next,
|
|
250
|
-
specDirty: true
|
|
251
|
-
};
|
|
252
|
-
return next;
|
|
253
|
-
}), Effect.andThen(Queue.offer(signal, void 0)), Effect.andThen(basename === "nodeSpec.ts" ? Queue.offer(specWatcherRestartQueue, void 0) : Effect.void));
|
|
254
|
-
return Effect.void;
|
|
255
|
-
}));
|
|
256
|
-
});
|
|
257
311
|
|
|
258
312
|
//#endregion
|
|
259
313
|
export { dev };
|