@confect/cli 9.0.0-next.7 → 9.0.0-next.8
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 +31 -0
- package/dist/BuildError.mjs +9 -2
- package/dist/BuildError.mjs.map +1 -1
- package/dist/Bundler.mjs +5 -2
- package/dist/Bundler.mjs.map +1 -1
- package/dist/CodeBlockWriter.mjs +1 -1
- package/dist/CodeBlockWriter.mjs.map +1 -1
- package/dist/CodegenError.mjs +7 -2
- package/dist/CodegenError.mjs.map +1 -1
- package/dist/ConfectDirectory.mjs +5 -2
- package/dist/ConfectDirectory.mjs.map +1 -1
- package/dist/ConvexDirectory.mjs +6 -2
- package/dist/ConvexDirectory.mjs.map +1 -1
- package/dist/FunctionPath.mjs +1 -1
- package/dist/FunctionPath.mjs.map +1 -1
- package/dist/FunctionPaths.mjs +5 -1
- package/dist/FunctionPaths.mjs.map +1 -1
- package/dist/GroupPath.mjs +9 -2
- package/dist/GroupPath.mjs.map +1 -1
- package/dist/GroupPaths.mjs +1 -1
- package/dist/GroupPaths.mjs.map +1 -1
- package/dist/LeafModule.mjs +8 -2
- package/dist/LeafModule.mjs.map +1 -1
- package/dist/ProjectRoot.mjs +8 -3
- package/dist/ProjectRoot.mjs.map +1 -1
- package/dist/SpecAssemblyNode.mjs +5 -1
- package/dist/SpecAssemblyNode.mjs.map +1 -1
- package/dist/TableModule.mjs +6 -2
- package/dist/TableModule.mjs.map +1 -1
- package/dist/cliApp.mjs +1 -1
- package/dist/cliApp.mjs.map +1 -1
- package/dist/confect/codegen.mjs +10 -3
- package/dist/confect/codegen.mjs.map +1 -1
- package/dist/confect/dev.mjs +24 -4
- package/dist/confect/dev.mjs.map +1 -1
- package/dist/confect.mjs +2 -2
- package/dist/confect.mjs.map +1 -1
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/log.mjs +7 -3
- package/dist/log.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/templates.mjs +3 -1
- package/dist/templates.mjs.map +1 -1
- package/dist/utils.mjs +25 -15
- package/dist/utils.mjs.map +1 -1
- package/package.json +3 -3
- package/src/BuildError.ts +9 -2
- package/src/Bundler.ts +5 -2
- package/src/CodeBlockWriter.ts +1 -1
- package/src/CodegenError.ts +7 -2
- package/src/ConfectDirectory.ts +5 -2
- package/src/ConvexDirectory.ts +6 -2
- package/src/FunctionPath.ts +1 -1
- package/src/FunctionPaths.ts +5 -1
- package/src/GroupPath.ts +9 -11
- package/src/GroupPaths.ts +1 -1
- package/src/LeafModule.ts +8 -2
- package/src/ProjectRoot.ts +8 -3
- package/src/SpecAssemblyNode.ts +5 -1
- package/src/TableModule.ts +6 -2
- package/src/cliApp.ts +1 -1
- package/src/confect/codegen.ts +10 -3
- package/src/confect/dev.ts +24 -24
- package/src/confect.ts +2 -2
- package/src/index.ts +3 -2
- package/src/log.ts +7 -3
- package/src/templates.ts +3 -1
- package/src/utils.ts +12 -13
package/dist/ProjectRoot.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectRoot.mjs","names":[],"sources":["../src/ProjectRoot.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"ProjectRoot.mjs","names":[],"sources":["../src/ProjectRoot.ts"],"sourcesContent":["import * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/Path\";\nimport * as NodeFileSystem from \"@effect/platform-node/NodeFileSystem\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\n\nexport class ProjectRoot extends Effect.Service<ProjectRoot>()(\n \"@confect/cli/ProjectRoot\",\n {\n effect: Effect.gen(function* () {\n const projectRoot = yield* findProjectRoot;\n\n const ref = yield* Ref.make<string>(projectRoot);\n\n return { get: Ref.get(ref) } as const;\n }),\n dependencies: [NodeFileSystem.layer],\n accessors: true,\n },\n) {}\n\nexport const findProjectRoot = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const startDir = path.resolve(\".\");\n const root = path.parse(startDir).root;\n\n const directories = Array.unfold(startDir, (dir) =>\n dir === root\n ? Option.none()\n : Option.some([dir, path.dirname(dir)] as const),\n );\n\n const projectRoot = yield* Effect.findFirst(directories, (dir) =>\n fs.exists(path.join(dir, \"package.json\")),\n );\n\n return yield* Option.match(projectRoot, {\n onNone: () => Effect.fail(new ProjectRootNotFoundError()),\n onSome: Effect.succeed,\n });\n});\n\nexport class ProjectRootNotFoundError extends Schema.TaggedError<ProjectRootNotFoundError>()(\n \"ProjectRootNotFoundError\",\n {},\n) {\n override get message(): string {\n return \"Could not find project root (no 'package.json' found)\";\n }\n}\n"],"mappings":";;;;;;;;;;AASA,IAAa,cAAb,cAAiC,OAAO,SAAsB,CAC5D,4BACA;CACE,QAAQ,OAAO,IAAI,aAAa;EAC9B,MAAM,cAAc,OAAO;EAE3B,MAAM,MAAM,OAAO,IAAI,KAAa,YAAY;AAEhD,SAAO,EAAE,KAAK,IAAI,IAAI,IAAI,EAAE;GAC5B;CACF,cAAc,CAAC,eAAe,MAAM;CACpC,WAAW;CACZ,CACF,CAAC;AAEF,MAAa,kBAAkB,OAAO,IAAI,aAAa;CACrD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,WAAW,KAAK,QAAQ,IAAI;CAClC,MAAM,OAAO,KAAK,MAAM,SAAS,CAAC;CAElC,MAAM,cAAc,MAAM,OAAO,WAAW,QAC1C,QAAQ,OACJ,OAAO,MAAM,GACb,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAU,CACnD;CAED,MAAM,cAAc,OAAO,OAAO,UAAU,cAAc,QACxD,GAAG,OAAO,KAAK,KAAK,KAAK,eAAe,CAAC,CAC1C;AAED,QAAO,OAAO,OAAO,MAAM,aAAa;EACtC,cAAc,OAAO,KAAK,IAAI,0BAA0B,CAAC;EACzD,QAAQ,OAAO;EAChB,CAAC;EACF;AAEF,IAAa,2BAAb,cAA8C,OAAO,aAAuC,CAC1F,4BACA,EAAE,CACH,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Array from "effect/Array";
|
|
2
|
+
import * as Option from "effect/Option";
|
|
3
|
+
import { pipe } from "effect/Function";
|
|
4
|
+
import * as Record from "effect/Record";
|
|
5
|
+
import * as Order from "effect/Order";
|
|
2
6
|
|
|
3
7
|
//#region src/SpecAssemblyNode.ts
|
|
4
8
|
const importBindingFromLeaf = (leaf) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpecAssemblyNode.mjs","names":[],"sources":["../src/SpecAssemblyNode.ts"],"sourcesContent":["import type { LeafModule } from \"./LeafModule\";\nimport { Array
|
|
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 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: leaf.pathSegments.join(\"_\"),\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\nexport const partitionByRuntime = (\n leaves: ReadonlyArray<LeafModule>,\n): {\n readonly convex: ReadonlyArray<LeafModule>;\n readonly node: ReadonlyArray<LeafModule>;\n} => {\n const [node, convex] = Array.partition(\n leaves,\n (leaf) => leaf.runtime === \"Convex\",\n );\n return { convex, node };\n};\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"],"mappings":";;;;;;;AAmBA,MAAM,yBAAyB,UAAyC;CACtE,YAAY,KAAK;CACjB,YAAY,KAAK;CACjB,WAAW,KAAK,aAAa,KAAK,IAAI;CACvC;AAED,MAAM,wBACJ,QACA,UAEA,KACE,MAAM,QAAQ,SAAS,SAAS,KAAK,aAAa,OAAQ,EAC1D,OAAO,WACP,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,CAAC,aAAa,QAAQ,CAAC,EAClE,MAAM,KAAK,CAAC,SAAS,iBAAiB;CACpC,MAAM,WAAW,MAAM,UACrB,cACC,SAAS,KAAK,aAAa,WAAW,QAAQ,EAChD;CACD,MAAM,cAAc,MAAM,OACxB,cACC,SAAS,KAAK,aAAa,SAAS,QAAQ,EAC9C;AACD,QAAO;EACL;EACA,eAAe,OAAO,IAAI,UAAU,sBAAsB;EAC1D,UAAU,qBAAqB,aAAa,QAAQ,EAAE;EACvD;EACD,CACH;AAEH,MAAa,2BACX,WACoC,qBAAqB,QAAQ,EAAE;AAErE,MAAa,sBACX,WAIG;CACH,MAAM,CAAC,MAAM,UAAU,MAAM,UAC3B,SACC,SAAS,KAAK,YAAY,SAC5B;AACD,QAAO;EAAE;EAAQ;EAAM;;AAGzB,MAAM,yBACJ,SAEA,KAAK,KAAK,UAAU,MAAM,QAAQ,sBAAsB,GAAG,kBACzD,OAAO,MAAM,KAAK,eAAe;CAC/B,cAAc;CACd,SAAS,YAAY,MAAM,QAAQ,eAAe,QAAQ;CAC3D,CAAC,CACH;AAEH,MAAa,yBACX,UAEA,KACE,MAAM,QAAQ,OAAO,sBAAsB,GAC1C,aACC,OAAO,eAAe,WAAW,YAAY,QAAQ,WAAW,EAClE,OAAO,WACP,MAAM,KAAK,GAAG,aAAa,QAAQ,EACnC,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,YAAY,QAAQ,UAAU,CAAC,CAC3E"}
|
package/dist/TableModule.mjs
CHANGED
|
@@ -2,9 +2,13 @@ import { fromBundlerError } from "./BuildError.mjs";
|
|
|
2
2
|
import { bundle } from "./Bundler.mjs";
|
|
3
3
|
import { DuplicateTableNameError, InvalidTableDefaultExportError, InvalidTableFilenameError } from "./CodegenError.mjs";
|
|
4
4
|
import { ConfectDirectory } from "./ConfectDirectory.mjs";
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
6
|
import { Identifier } from "@confect/core";
|
|
7
|
-
import
|
|
7
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
8
|
+
import * as Path from "@effect/platform/Path";
|
|
9
|
+
import * as Array from "effect/Array";
|
|
10
|
+
import { pipe } from "effect/Function";
|
|
11
|
+
import * as Order from "effect/Order";
|
|
8
12
|
import * as Table from "@confect/server/Table";
|
|
9
13
|
|
|
10
14
|
//#region src/TableModule.ts
|
package/dist/TableModule.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableModule.mjs","names":["Bundler.bundle"],"sources":["../src/TableModule.ts"],"sourcesContent":["import { Identifier } from \"@confect/core\";\nimport * as Table from \"@confect/server/Table\";\nimport
|
|
1
|
+
{"version":3,"file":"TableModule.mjs","names":["Bundler.bundle"],"sources":["../src/TableModule.ts"],"sourcesContent":["import { Identifier } from \"@confect/core\";\nimport * as Table from \"@confect/server/Table\";\nimport * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/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\n * binding 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 = (relativePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { name } = path.parse(relativePath);\n return name;\n });\n\nconst listTableFiles = 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* listTableFiles;\n\n const tableModules = yield* Effect.forEach(\n relativePaths,\n (relativePath) =>\n Effect.gen(function* () {\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\n * an {@link Table.UnnamedTable} (the result of `Table.make(...)` before a\n * name has been bound). Fails with {@link InvalidTableDefaultExportError} if\n * any 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 = (tableModules: ReadonlyArray<TableModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(\n tableModules,\n ({ relativePath }) =>\n Effect.gen(function* () {\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 { concurrency: \"unbounded\" },\n );\n });\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAa,iBAAiB;AAe9B,MAAM,6BAA6B,iBACjC,OAAO,IAAI,aAAa;CAEtB,MAAM,EAAE,UADK,OAAO,KAAK,MACH,MAAM,aAAa;AACzC,QAAO;EACP;AAEJ,MAAM,iBAAiB,OAAO,IAAI,aAAa;CAC7C,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,kBAAkB,KAAK,KAAK,kBAAkB,eAAe;AAEnE,KAAI,EAAE,OAAO,GAAG,OAAO,gBAAgB,EACrC,QAAO,EAAE;AAOX,QAAO,KAJU,OAAO,GAAG,cAAc,iBAAiB,EACxD,WAAW,MACZ,CAAC,EAIA,MAAM,QAAQ,MAAM,EAAE,SAAS,MAAM,IAAI,CAAC,EAAE,SAAS,WAAW,CAAC,EACjE,MAAM,KAAK,MAAM,KAAK,KAAK,gBAAgB,EAAE,CAAC,CAC/C;EACD;AAEF,MAAM,cAAc,MAAM,SACxB,MAAM,SACL,gBAA6B,YAAY,UAC3C;;;;;;;;;;;;;;;;;;;;;AAsBD,MAAa,WAAW,OAAO,IAAI,aAAa;CAC9C,MAAM,gBAAgB,OAAO;CAoB7B,MAAM,SAAS,KAlBM,OAAO,OAAO,QACjC,gBACC,iBACC,OAAO,IAAI,aAAa;EACtB,MAAM,YAAY,OAAO,0BAA0B,aAAa;AAChE,SAAO,OAAO,IAAI;GAChB,WAAW,WAAW,+BAA+B,UAAU;GAC/D,QAAQ,MACN,IAAI,0BAA0B;IAC5B,WAAW;IACX,QAAQ,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;IACnD,CAAC;GACL,CAAC;AACF,SAAO;GAAE;GAAc;GAAW;GAClC,EACJ,EAAE,aAAa,aAAa,CAC7B,EAEiC,MAAM,OAAO,YAAY,CAAC;CAE5D,MAAM,aAAa,OAAO,QACxB,MAAM,QAAQ,SAAS,gBAAgB,YAAY,UAAU,CAC9D,CACE,QAAQ,GAAG,WAAW,MAAM,SAAS,EAAE,CACvC,KAAK,CAAC,WAAW,YAAY;EAC5B;EACA,YAAY,MAAM,IAAI,QAAQ,gBAAgB,YAAY,aAAa;EACxE,EAAE;AAEL,KAAI,WAAW,SAAS,EACtB,QAAO,OAAO,IAAI,wBAAwB,EAAE,YAAY,CAAC;AAG3D,QAAO;EACP;;;;;;;;;;;AAYF,MAAa,YAAY,iBACvB,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;AAEjD,QAAO,OAAO,QACZ,eACC,EAAE,mBACD,OAAO,IAAI,aAAa;EACtB,MAAM,eAAe,KAAK,QAAQ,kBAAkB,aAAa;EACjE,MAAM,EAAE,WAAW,OAAOA,OAAe,aAAa,CAAC,KACrD,OAAO,UAAU,UAAU,iBAAiB,cAAc,MAAM,CAAC,CAClE;AAED,MAAI,CAAC,MAAM,eAAe,OAAO,QAAQ,CACvC,QAAO,OAAO,IAAI,+BAA+B,EAC/C,WAAW,cACZ,CAAC;GAEJ,EACJ,EAAE,aAAa,aAAa,CAC7B;EACD"}
|
package/dist/cliApp.mjs
CHANGED
package/dist/cliApp.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliApp.mjs","names":["packageJson.version"],"sources":["../src/cliApp.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"cliApp.mjs","names":["packageJson.version"],"sources":["../src/cliApp.ts"],"sourcesContent":["import * as Command from \"@effect/cli/Command\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport { confect } from \"./confect\";\n\nexport const cliApp = Command.run(confect, {\n name: \"Confect\",\n version: packageJson.version,\n});\n"],"mappings":";;;;;AAIA,MAAa,SAAS,QAAQ,IAAI,SAAS;CACzC,MAAM;CACGA;CACV,CAAC"}
|
package/dist/confect/codegen.mjs
CHANGED
|
@@ -9,10 +9,17 @@ import { assembledSpec, convexSchema, id, refs, registeredFunctionsForGroup, run
|
|
|
9
9
|
import { WriteTracker, generateAuthConfig, generateCrons, generateFunctions, generateHttp, removePathIfExists, toModuleImportPath, touchConvexSchema, writeFileStringAndLog } from "../utils.mjs";
|
|
10
10
|
import { discoverLeafImplFiles, discoverLeafSpecFiles, implPathForSpec, registeredFunctionsRelativePath, specPathForImpl, toLeafModule, toNodeRegistryLeaf, validateImpl, validateSpec } from "../LeafModule.mjs";
|
|
11
11
|
import { TABLES_DIRNAME, discover, validate } from "../TableModule.mjs";
|
|
12
|
-
import
|
|
13
|
-
import
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Command from "@effect/cli/Command";
|
|
14
14
|
import { Spec } from "@confect/core";
|
|
15
|
-
import
|
|
15
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
16
|
+
import * as Path from "@effect/platform/Path";
|
|
17
|
+
import * as Array from "effect/Array";
|
|
18
|
+
import * as Either from "effect/Either";
|
|
19
|
+
import * as HashSet from "effect/HashSet";
|
|
20
|
+
import * as Match from "effect/Match";
|
|
21
|
+
import * as Option from "effect/Option";
|
|
22
|
+
import * as Ref from "effect/Ref";
|
|
16
23
|
|
|
17
24
|
//#region src/confect/codegen.ts
|
|
18
25
|
const GENERATED_DIRNAME = "_generated";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","TableModule.discover","TableModule.validate","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","TableModule.TABLES_DIRNAME","templates.id","templates.tableWrapper","templates.runtimeSchema","templates.convexSchema","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec, type GroupSpec } from \"@confect/core\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Array, Effect, Either, HashSet, Match, Option, Ref } from \"effect\";\nimport * as Bundler from \"../Bundler\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n LegacySchemaFileError,\n MissingImplFileError,\n MissingSpecFileError,\n ParentChildNameCollisionError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\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 logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n logWarn,\n} from \"../log\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n type SpecAssemblyNode,\n} from \"../SpecAssemblyNode\";\nimport * as TableModule from \"../TableModule\";\nimport * as templates from \"../templates\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_DIRNAME = \"_generated\";\n\nconst GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"spec.ts\"),\n);\nconst GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"nodeSpec.ts\"),\n);\nconst GENERATED_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"schema.ts\"),\n);\nconst GENERATED_CONVEX_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"convexSchema.ts\"),\n);\nconst GENERATED_ID_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"id.ts\"),\n);\nconst GENERATED_TABLES_DIRNAME = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"tables\"),\n);\n\nconst LEGACY_PATHS = Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n path.join(GENERATED_DIRNAME, \"registeredFunctions.ts\"),\n path.join(GENERATED_DIRNAME, \"nodeRegisteredFunctions.ts\"),\n path.join(GENERATED_DIRNAME, \"impl.ts\"),\n path.join(GENERATED_DIRNAME, \"nodeImpl.ts\"),\n ];\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 // Reject a legacy `confect/schema.ts` up front so the user-facing\n // migration message surfaces before any bundler error from impl\n // validation (each impl imports `_generated/schema.ts`).\n yield* rejectLegacySchemaFile;\n // List `confect/tables/*.ts` (filename-only — no bundling yet) so the\n // `_generated/id.ts` constructor can be emitted *before* we bundle any\n // user-authored table module. Tables import from `_generated/id.ts` for\n // cross-table id refs, so it must exist on disk first.\n const tableModules = yield* TableModule.discover;\n yield* warnIfNoTables(tableModules);\n yield* generateIdConstructor(tableModules);\n // Now that `_generated/id.ts` is on disk, bundle each table module and\n // check its default export is an `UnnamedTable`. Surface diagnostics\n // here (rather than later) so they appear before impl-validation noise.\n yield* TableModule.validate(tableModules);\n yield* generateTableWrappers(tableModules);\n yield* removeObsoleteTableWrappers(tableModules);\n yield* generateRuntimeSchema(tableModules);\n const { leaves, groupSpecsByRelativePath } =\n yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);\n yield* generateAssembledSpecs(leaves);\n // `_generated/api.ts` / `nodeApi.ts` are no longer imported by generated or\n // impl code (impls take the database schema from `_generated/schema`\n // directly), so remove any copies left over from earlier versions before\n // impl validation runs.\n yield* Effect.all(\n [\n removeGeneratedApi,\n generateRefs,\n removeGeneratedNodeApi,\n generateServices,\n generateConvexSchema(tableModules),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateConvexSchemaReexport,\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 results = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n const groupSpec = 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, groupSpec };\n }),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n const leaves = Array.map(results, ({ leaf }) => leaf);\n const groupSpecsByRelativePath = new Map(\n Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]),\n );\n\n return { leaves, groupSpecsByRelativePath };\n});\n\n/**\n * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}\n * when a parent leaf declares a function or subgroup whose name matches a\n * sibling subdirectory spec's segment. Without this check the colliding\n * descendant would overwrite the parent's entry in the assembled\n * `GroupSpec.groups` map at runtime, surfacing as a confusing\n * `Refs.make` error rather than a codegen-time diagnostic.\n */\nexport const validateNoParentChildNameCollisions = (\n leaves: ReadonlyArray<LeafModule>,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n) =>\n Effect.gen(function* () {\n const { convex, node } = partitionByRuntime(leaves);\n const convexNodes = assemblyNodesFromLeaves(convex);\n const nodeNodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n yield* Effect.forEach(convexNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n yield* Effect.forEach(nodeNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n });\n\nconst checkAssemblyNodeForCollisions = (\n node: SpecAssemblyNode,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n): Effect.Effect<void, ParentChildNameCollisionError> =>\n Effect.gen(function* () {\n yield* Option.match(node.importBinding, {\n onNone: () => Effect.void,\n onSome: (binding) =>\n Effect.gen(function* () {\n if (node.children.length === 0) return;\n const parentRelativePath = bindingToRelativeSpecPath(\n binding.importPath,\n );\n const parentGroupSpec =\n groupSpecsByRelativePath.get(parentRelativePath);\n if (parentGroupSpec === undefined) return;\n yield* Effect.forEach(node.children, (child) => {\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.functions,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"function\",\n }),\n );\n }\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.groups,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"group\",\n }),\n );\n }\n return Effect.void;\n });\n }),\n });\n yield* Effect.forEach(node.children, (child) =>\n checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath),\n );\n });\n\n/**\n * `LeafModule.specImportPath` is the import path used from inside the\n * generated `_generated/spec.ts` (e.g. `\"../notes.spec\"`). Strip the\n * `../` prefix and re-add the `.ts` extension to recover the leaf's\n * confect-relative spec path used as the key in\n * `groupSpecsByRelativePath`.\n */\nconst bindingToRelativeSpecPath = (importPath: string): string => {\n const withoutDotDot = importPath.startsWith(\"../\")\n ? importPath.slice(3)\n : importPath;\n return `${withoutDotDot}.ts`;\n};\n\n/**\n * A child assembly node may itself be a parent without a leaf (when the\n * actual leaves live only in deeper subdirectories). In that case we\n * surface the first descendant leaf as a representative path so the\n * error message points at something the user actually wrote.\n */\nconst childRepresentativeSpecPath = (node: SpecAssemblyNode): string => {\n if (Option.isSome(node.importBinding)) {\n return bindingToRelativeSpecPath(node.importBinding.value.importPath);\n }\n for (const child of node.children) {\n return childRepresentativeSpecPath(child);\n }\n return node.segment;\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 const legacyPaths = yield* LEGACY_PATHS;\n\n yield* Effect.forEach(legacyPaths, (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 generatedSpecPath = yield* GENERATED_SPEC_PATH;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\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, generatedSpecPath),\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, generatedNodeSpecPath),\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 schemaImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", \"schema.ts\"),\n ),\n );\n // The group's own leaf spec (sibling of its impl), referenced\n // type-only by the registry to shape its returned record.\n const specImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, leaf.relativePath),\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 schemaImportPath,\n specImportPath,\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 const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n return path.join(confectDirectory, generatedSpecPath);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n return path.join(confectDirectory, generatedNodeSpecPath);\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\n/**\n * Remove a now-obsolete `_generated/<name>.ts` if present (and log it), for\n * projects upgrading from a version that still emitted it.\n */\nconst removeObsoleteGeneratedFile = (fileName: 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 filePath = path.join(confectDirectory, \"_generated\", fileName);\n\n if (yield* fs.exists(filePath)) {\n yield* removePathIfExists(filePath);\n yield* logFileRemoved(filePath);\n }\n });\n\n// `_generated/api.ts` is no longer imported by generated or impl code: impls\n// take the database schema (`_generated/schema`) directly, and per-group\n// registries reference the spec type-only. Remove any stale copy.\nconst removeGeneratedApi = removeObsoleteGeneratedFile(\"api.ts\");\n\n// `_generated/nodeApi.ts` is obsolete for the same reason.\nconst removeGeneratedNodeApi = removeObsoleteGeneratedFile(\"nodeApi.ts\");\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\n/**\n * The user-authored `confect/schema.ts` is no longer supported: codegen now\n * owns both `_generated/schema.ts` (runtime) and `_generated/convexSchema.ts`\n * (deploy), derived from a single scan of `confect/tables/*.ts`. Detect a\n * stray file and fail with a clear migration message — leaving it in place\n * would silently shadow the codegen-owned `_generated/schema.ts` /\n * `_generated/convexSchema.ts`.\n */\nconst rejectLegacySchemaFile = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const legacyPath = path.join(confectDirectory, \"schema.ts\");\n\n if (yield* fs.exists(legacyPath)) {\n return yield* new LegacySchemaFileError({ schemaPath: \"schema.ts\" });\n }\n});\n\n/**\n * Surface a yellow `⚠` warning when codegen sees no tables — either the\n * `confect/tables/` directory is missing or it contains no `.ts` files.\n * Generation still succeeds (emitting an empty `DatabaseSchema` and\n * `defineSchema({})`), since action-only / table-free Confect backends\n * are legal — but the warning catches the much more common case of a\n * typoed directory or files placed under the wrong root.\n */\nconst warnIfNoTables = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n tableModules.length === 0\n ? logWarn(\n `No tables discovered in \\`confect/${TableModule.TABLES_DIRNAME}/\\`. ` +\n `Generating an empty schema; add a \\`Table.make(...)\\` module under that ` +\n `directory unless this backend is intentionally tables-free.`,\n )\n : Effect.void;\n\nconst tableModuleBindings = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n generatedFilePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedDir = path.dirname(generatedFilePath);\n\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n\n return yield* Effect.forEach(tableModules, (tm) =>\n Effect.gen(function* () {\n const wrapperAbsolutePath = path.join(\n confectDirectory,\n generatedTablesDirname,\n `${tm.tableName}.ts`,\n );\n const importPath = yield* toModuleImportPath(\n path.relative(generatedDir, wrapperAbsolutePath),\n );\n return {\n importPath,\n tableName: tm.tableName,\n };\n }),\n );\n });\n\nconst generateIdConstructor = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedIdPath = yield* GENERATED_ID_PATH;\n const idPath = path.join(confectDirectory, generatedIdPath);\n\n const tableNames = tableModules.map((tm) => tm.tableName);\n const contents = yield* templates.id({ tableNames });\n\n yield* writeFileStringAndLog(idPath, contents);\n });\n\nconst generateTableWrappers = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n const wrappersDir = path.join(confectDirectory, generatedTablesDirname);\n\n if (!(yield* fs.exists(wrappersDir))) {\n yield* fs.makeDirectory(wrappersDir, { recursive: true });\n }\n\n yield* Effect.forEach(\n tableModules,\n (tm) =>\n Effect.gen(function* () {\n const wrapperPath = path.join(\n confectDirectory,\n generatedTablesDirname,\n `${tm.tableName}.ts`,\n );\n const unnamedAbsolutePath = path.join(\n confectDirectory,\n tm.relativePath,\n );\n const unnamedImportPath = yield* toModuleImportPath(\n path.relative(path.dirname(wrapperPath), unnamedAbsolutePath),\n );\n const contents = yield* templates.tableWrapper({\n tableName: tm.tableName,\n unnamedImportPath,\n });\n yield* writeFileStringAndLog(wrapperPath, contents);\n }),\n { concurrency: \"unbounded\" },\n );\n });\n\n/**\n * Remove any stale `_generated/tables/*.ts` wrapper whose source table\n * has been deleted or renamed. Mirrors `removeObsoleteRegisteredFunctions`\n * for the wrapper directory.\n */\nconst removeObsoleteTableWrappers = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n const wrappersDir = path.join(confectDirectory, generatedTablesDirname);\n\n if (!(yield* fs.exists(wrappersDir))) {\n return;\n }\n\n const expected = new Set(tableModules.map((tm) => `${tm.tableName}.ts`));\n const existing = yield* fs.readDirectory(wrappersDir, { recursive: true });\n yield* Effect.forEach(existing, (entry) => {\n if (path.extname(entry) !== \".ts\") {\n return Effect.void;\n }\n if (!expected.has(entry)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(wrappersDir, entry);\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 generateRuntimeSchema = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedSchemaPath = yield* GENERATED_SCHEMA_PATH;\n const schemaPath = path.join(confectDirectory, generatedSchemaPath);\n\n const bindings = yield* tableModuleBindings(tableModules, schemaPath);\n const contents = yield* templates.runtimeSchema({ tableModules: bindings });\n\n yield* writeFileStringAndLog(schemaPath, contents);\n });\n\nconst generateConvexSchema = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedConvexSchemaPath = yield* GENERATED_CONVEX_SCHEMA_PATH;\n const convexSchemaPath = path.join(\n confectDirectory,\n generatedConvexSchemaPath,\n );\n\n const bindings = yield* tableModuleBindings(tableModules, convexSchemaPath);\n const contents = yield* templates.convexSchema({ tableModules: bindings });\n\n yield* writeFileStringAndLog(convexSchemaPath, contents);\n });\n\nconst generateConvexSchemaReexport = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n const generatedConvexSchemaRelativePath = yield* GENERATED_CONVEX_SCHEMA_PATH;\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n const generatedConvexSchemaPath = path.join(\n confectDirectory,\n generatedConvexSchemaRelativePath,\n );\n\n const convexSchemaImportPath = yield* toModuleImportPath(\n path.relative(path.dirname(convexSchemaPath), generatedConvexSchemaPath),\n );\n\n const schemaContents = yield* templates.schema({\n convexSchemaImportPath,\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 generatedSchemaPath = yield* GENERATED_SCHEMA_PATH;\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, generatedSchemaPath),\n ),\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 const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, generatedSpecPath)),\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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"}
|
|
1
|
+
{"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","TableModule.discover","TableModule.validate","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","TableModule.TABLES_DIRNAME","templates.id","templates.tableWrapper","templates.runtimeSchema","templates.convexSchema","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec, type GroupSpec } from \"@confect/core\";\nimport * as Command from \"@effect/cli/Command\";\nimport * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/Path\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Either from \"effect/Either\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as Bundler from \"../Bundler\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n LegacySchemaFileError,\n MissingImplFileError,\n MissingSpecFileError,\n ParentChildNameCollisionError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\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 logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n logWarn,\n} from \"../log\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n type SpecAssemblyNode,\n} from \"../SpecAssemblyNode\";\nimport * as TableModule from \"../TableModule\";\nimport * as templates from \"../templates\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_DIRNAME = \"_generated\";\n\nconst GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"spec.ts\"),\n);\nconst GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"nodeSpec.ts\"),\n);\nconst GENERATED_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"schema.ts\"),\n);\nconst GENERATED_CONVEX_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"convexSchema.ts\"),\n);\nconst GENERATED_ID_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"id.ts\"),\n);\nconst GENERATED_TABLES_DIRNAME = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"tables\"),\n);\n\nconst LEGACY_PATHS = Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n path.join(GENERATED_DIRNAME, \"registeredFunctions.ts\"),\n path.join(GENERATED_DIRNAME, \"nodeRegisteredFunctions.ts\"),\n path.join(GENERATED_DIRNAME, \"impl.ts\"),\n path.join(GENERATED_DIRNAME, \"nodeImpl.ts\"),\n ];\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 // Reject a legacy `confect/schema.ts` up front so the user-facing\n // migration message surfaces before any bundler error from impl\n // validation (each impl imports `_generated/schema.ts`).\n yield* rejectLegacySchemaFile;\n // List `confect/tables/*.ts` (filename-only — no bundling yet) so the\n // `_generated/id.ts` constructor can be emitted *before* we bundle any\n // user-authored table module. Tables import from `_generated/id.ts` for\n // cross-table id refs, so it must exist on disk first.\n const tableModules = yield* TableModule.discover;\n yield* warnIfNoTables(tableModules);\n yield* generateIdConstructor(tableModules);\n // Now that `_generated/id.ts` is on disk, bundle each table module and\n // check its default export is an `UnnamedTable`. Surface diagnostics\n // here (rather than later) so they appear before impl-validation noise.\n yield* TableModule.validate(tableModules);\n yield* generateTableWrappers(tableModules);\n yield* removeObsoleteTableWrappers(tableModules);\n yield* generateRuntimeSchema(tableModules);\n const { leaves, groupSpecsByRelativePath } =\n yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);\n yield* generateAssembledSpecs(leaves);\n // `_generated/api.ts` / `nodeApi.ts` are no longer imported by generated or\n // impl code (impls take the database schema from `_generated/schema`\n // directly), so remove any copies left over from earlier versions before\n // impl validation runs.\n yield* Effect.all(\n [\n removeGeneratedApi,\n generateRefs,\n removeGeneratedNodeApi,\n generateServices,\n generateConvexSchema(tableModules),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateConvexSchemaReexport,\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 results = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n const groupSpec = 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, groupSpec };\n }),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n const leaves = Array.map(results, ({ leaf }) => leaf);\n const groupSpecsByRelativePath = new Map(\n Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]),\n );\n\n return { leaves, groupSpecsByRelativePath };\n});\n\n/**\n * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}\n * when a parent leaf declares a function or subgroup whose name matches a\n * sibling subdirectory spec's segment. Without this check the colliding\n * descendant would overwrite the parent's entry in the assembled\n * `GroupSpec.groups` map at runtime, surfacing as a confusing\n * `Refs.make` error rather than a codegen-time diagnostic.\n */\nexport const validateNoParentChildNameCollisions = (\n leaves: ReadonlyArray<LeafModule>,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n) =>\n Effect.gen(function* () {\n const { convex, node } = partitionByRuntime(leaves);\n const convexNodes = assemblyNodesFromLeaves(convex);\n const nodeNodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n yield* Effect.forEach(convexNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n yield* Effect.forEach(nodeNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n });\n\nconst checkAssemblyNodeForCollisions = (\n node: SpecAssemblyNode,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n): Effect.Effect<void, ParentChildNameCollisionError> =>\n Effect.gen(function* () {\n yield* Option.match(node.importBinding, {\n onNone: () => Effect.void,\n onSome: (binding) =>\n Effect.gen(function* () {\n if (node.children.length === 0) return;\n const parentRelativePath = bindingToRelativeSpecPath(\n binding.importPath,\n );\n const parentGroupSpec =\n groupSpecsByRelativePath.get(parentRelativePath);\n if (parentGroupSpec === undefined) return;\n yield* Effect.forEach(node.children, (child) => {\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.functions,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"function\",\n }),\n );\n }\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.groups,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"group\",\n }),\n );\n }\n return Effect.void;\n });\n }),\n });\n yield* Effect.forEach(node.children, (child) =>\n checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath),\n );\n });\n\n/**\n * `LeafModule.specImportPath` is the import path used from inside the\n * generated `_generated/spec.ts` (e.g. `\"../notes.spec\"`). Strip the\n * `../` prefix and re-add the `.ts` extension to recover the leaf's\n * confect-relative spec path used as the key in\n * `groupSpecsByRelativePath`.\n */\nconst bindingToRelativeSpecPath = (importPath: string): string => {\n const withoutDotDot = importPath.startsWith(\"../\")\n ? importPath.slice(3)\n : importPath;\n return `${withoutDotDot}.ts`;\n};\n\n/**\n * A child assembly node may itself be a parent without a leaf (when the\n * actual leaves live only in deeper subdirectories). In that case we\n * surface the first descendant leaf as a representative path so the\n * error message points at something the user actually wrote.\n */\nconst childRepresentativeSpecPath = (node: SpecAssemblyNode): string => {\n if (Option.isSome(node.importBinding)) {\n return bindingToRelativeSpecPath(node.importBinding.value.importPath);\n }\n for (const child of node.children) {\n return childRepresentativeSpecPath(child);\n }\n return node.segment;\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 const legacyPaths = yield* LEGACY_PATHS;\n\n yield* Effect.forEach(legacyPaths, (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 generatedSpecPath = yield* GENERATED_SPEC_PATH;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\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, generatedSpecPath),\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, generatedNodeSpecPath),\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 schemaImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", \"schema.ts\"),\n ),\n );\n // The group's own leaf spec (sibling of its impl), referenced\n // type-only by the registry to shape its returned record.\n const specImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, leaf.relativePath),\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 schemaImportPath,\n specImportPath,\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 const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n return path.join(confectDirectory, generatedSpecPath);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n return path.join(confectDirectory, generatedNodeSpecPath);\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\n/**\n * Remove a now-obsolete `_generated/<name>.ts` if present (and log it), for\n * projects upgrading from a version that still emitted it.\n */\nconst removeObsoleteGeneratedFile = (fileName: 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 filePath = path.join(confectDirectory, \"_generated\", fileName);\n\n if (yield* fs.exists(filePath)) {\n yield* removePathIfExists(filePath);\n yield* logFileRemoved(filePath);\n }\n });\n\n// `_generated/api.ts` is no longer imported by generated or impl code: impls\n// take the database schema (`_generated/schema`) directly, and per-group\n// registries reference the spec type-only. Remove any stale copy.\nconst removeGeneratedApi = removeObsoleteGeneratedFile(\"api.ts\");\n\n// `_generated/nodeApi.ts` is obsolete for the same reason.\nconst removeGeneratedNodeApi = removeObsoleteGeneratedFile(\"nodeApi.ts\");\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\n/**\n * The user-authored `confect/schema.ts` is no longer supported: codegen now\n * owns both `_generated/schema.ts` (runtime) and `_generated/convexSchema.ts`\n * (deploy), derived from a single scan of `confect/tables/*.ts`. Detect a\n * stray file and fail with a clear migration message — leaving it in place\n * would silently shadow the codegen-owned `_generated/schema.ts` /\n * `_generated/convexSchema.ts`.\n */\nconst rejectLegacySchemaFile = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const legacyPath = path.join(confectDirectory, \"schema.ts\");\n\n if (yield* fs.exists(legacyPath)) {\n return yield* new LegacySchemaFileError({ schemaPath: \"schema.ts\" });\n }\n});\n\n/**\n * Surface a yellow `⚠` warning when codegen sees no tables — either the\n * `confect/tables/` directory is missing or it contains no `.ts` files.\n * Generation still succeeds (emitting an empty `DatabaseSchema` and\n * `defineSchema({})`), since action-only / table-free Confect backends\n * are legal — but the warning catches the much more common case of a\n * typoed directory or files placed under the wrong root.\n */\nconst warnIfNoTables = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n tableModules.length === 0\n ? logWarn(\n `No tables discovered in \\`confect/${TableModule.TABLES_DIRNAME}/\\`. ` +\n `Generating an empty schema; add a \\`Table.make(...)\\` module under that ` +\n `directory unless this backend is intentionally tables-free.`,\n )\n : Effect.void;\n\nconst tableModuleBindings = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n generatedFilePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedDir = path.dirname(generatedFilePath);\n\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n\n return yield* Effect.forEach(tableModules, (tm) =>\n Effect.gen(function* () {\n const wrapperAbsolutePath = path.join(\n confectDirectory,\n generatedTablesDirname,\n `${tm.tableName}.ts`,\n );\n const importPath = yield* toModuleImportPath(\n path.relative(generatedDir, wrapperAbsolutePath),\n );\n return {\n importPath,\n tableName: tm.tableName,\n };\n }),\n );\n });\n\nconst generateIdConstructor = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedIdPath = yield* GENERATED_ID_PATH;\n const idPath = path.join(confectDirectory, generatedIdPath);\n\n const tableNames = tableModules.map((tm) => tm.tableName);\n const contents = yield* templates.id({ tableNames });\n\n yield* writeFileStringAndLog(idPath, contents);\n });\n\nconst generateTableWrappers = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n const wrappersDir = path.join(confectDirectory, generatedTablesDirname);\n\n if (!(yield* fs.exists(wrappersDir))) {\n yield* fs.makeDirectory(wrappersDir, { recursive: true });\n }\n\n yield* Effect.forEach(\n tableModules,\n (tm) =>\n Effect.gen(function* () {\n const wrapperPath = path.join(\n confectDirectory,\n generatedTablesDirname,\n `${tm.tableName}.ts`,\n );\n const unnamedAbsolutePath = path.join(\n confectDirectory,\n tm.relativePath,\n );\n const unnamedImportPath = yield* toModuleImportPath(\n path.relative(path.dirname(wrapperPath), unnamedAbsolutePath),\n );\n const contents = yield* templates.tableWrapper({\n tableName: tm.tableName,\n unnamedImportPath,\n });\n yield* writeFileStringAndLog(wrapperPath, contents);\n }),\n { concurrency: \"unbounded\" },\n );\n });\n\n/**\n * Remove any stale `_generated/tables/*.ts` wrapper whose source table\n * has been deleted or renamed. Mirrors `removeObsoleteRegisteredFunctions`\n * for the wrapper directory.\n */\nconst removeObsoleteTableWrappers = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n const wrappersDir = path.join(confectDirectory, generatedTablesDirname);\n\n if (!(yield* fs.exists(wrappersDir))) {\n return;\n }\n\n const expected = new Set(tableModules.map((tm) => `${tm.tableName}.ts`));\n const existing = yield* fs.readDirectory(wrappersDir, { recursive: true });\n yield* Effect.forEach(existing, (entry) => {\n if (path.extname(entry) !== \".ts\") {\n return Effect.void;\n }\n if (!expected.has(entry)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(wrappersDir, entry);\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 generateRuntimeSchema = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedSchemaPath = yield* GENERATED_SCHEMA_PATH;\n const schemaPath = path.join(confectDirectory, generatedSchemaPath);\n\n const bindings = yield* tableModuleBindings(tableModules, schemaPath);\n const contents = yield* templates.runtimeSchema({ tableModules: bindings });\n\n yield* writeFileStringAndLog(schemaPath, contents);\n });\n\nconst generateConvexSchema = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedConvexSchemaPath = yield* GENERATED_CONVEX_SCHEMA_PATH;\n const convexSchemaPath = path.join(\n confectDirectory,\n generatedConvexSchemaPath,\n );\n\n const bindings = yield* tableModuleBindings(tableModules, convexSchemaPath);\n const contents = yield* templates.convexSchema({ tableModules: bindings });\n\n yield* writeFileStringAndLog(convexSchemaPath, contents);\n });\n\nconst generateConvexSchemaReexport = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n const generatedConvexSchemaRelativePath = yield* GENERATED_CONVEX_SCHEMA_PATH;\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n const generatedConvexSchemaPath = path.join(\n confectDirectory,\n generatedConvexSchemaRelativePath,\n );\n\n const convexSchemaImportPath = yield* toModuleImportPath(\n path.relative(path.dirname(convexSchemaPath), generatedConvexSchemaPath),\n );\n\n const schemaContents = yield* templates.schema({\n convexSchemaImportPath,\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 generatedSchemaPath = yield* GENERATED_SCHEMA_PATH;\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, generatedSchemaPath),\n ),\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 const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, generatedSpecPath)),\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
|
@@ -8,12 +8,32 @@ import { FunctionPaths, diff } from "../FunctionPaths.mjs";
|
|
|
8
8
|
import { generateAuthConfig, generateCrons, generateHttp } from "../utils.mjs";
|
|
9
9
|
import { discoverLeafImplFiles, isLeafImplPath, isLeafSpecPath } from "../LeafModule.mjs";
|
|
10
10
|
import { codegenHandler, loadPreviousFunctionPaths } from "./codegen.mjs";
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Command from "@effect/cli/Command";
|
|
13
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
14
|
+
import * as Path from "@effect/platform/Path";
|
|
15
|
+
import * as Array from "effect/Array";
|
|
16
|
+
import * as HashSet from "effect/HashSet";
|
|
17
|
+
import * as Match from "effect/Match";
|
|
18
|
+
import * as Option from "effect/Option";
|
|
19
|
+
import * as Ref from "effect/Ref";
|
|
14
20
|
import { externalPlugin, loadTsConfig, tsconfigPathsToRegExp } from "bundle-require";
|
|
15
|
-
import {
|
|
21
|
+
import { pipe } from "effect/Function";
|
|
22
|
+
import * as Ansi from "@effect/printer-ansi/Ansi";
|
|
23
|
+
import * as AnsiDoc from "@effect/printer-ansi/AnsiDoc";
|
|
24
|
+
import * as String from "effect/String";
|
|
16
25
|
import * as esbuild from "esbuild";
|
|
26
|
+
import * as Console from "effect/Console";
|
|
27
|
+
import * as Order from "effect/Order";
|
|
28
|
+
import * as Chunk from "effect/Chunk";
|
|
29
|
+
import * as Clock from "effect/Clock";
|
|
30
|
+
import * as Duration from "effect/Duration";
|
|
31
|
+
import * as Equal from "effect/Equal";
|
|
32
|
+
import * as ExecutionStrategy from "effect/ExecutionStrategy";
|
|
33
|
+
import * as Exit from "effect/Exit";
|
|
34
|
+
import * as Queue from "effect/Queue";
|
|
35
|
+
import * as Scope from "effect/Scope";
|
|
36
|
+
import * as Stream from "effect/Stream";
|
|
17
37
|
|
|
18
38
|
//#region src/confect/dev.ts
|
|
19
39
|
const GENERATED_DIRNAME = "_generated";
|
package/dist/confect/dev.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.mjs","names":["FunctionPaths.diff","CodegenError.catchAndLog"],"sources":["../../src/confect/dev.ts"],"sourcesContent":["import { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport {\n Array,\n Chunk,\n Clock,\n Console,\n Duration,\n Effect,\n Equal,\n ExecutionStrategy,\n Exit,\n HashSet,\n Match,\n Option,\n Order,\n pipe,\n Queue,\n Ref,\n Scope,\n Stream,\n String,\n} from \"effect\";\nimport {\n externalPlugin,\n loadTsConfig,\n tsconfigPathsToRegExp,\n} from \"bundle-require\";\nimport * as esbuild from \"esbuild\";\nimport { logCoalescedBuildErrors } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport type * as GroupPaths from \"../GroupPaths\";\nimport {\n discoverLeafImplFiles,\n isLeafImplPath,\n isLeafSpecPath,\n} from \"../LeafModule\";\nimport {\n logFunctionAdded,\n logFunctionRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ProjectRoot } from \"../ProjectRoot\";\nimport { generateAuthConfig, generateCrons, generateHttp } from \"../utils\";\nimport { codegenHandler, loadPreviousFunctionPaths } from \"./codegen\";\n\nconst GENERATED_DIRNAME = \"_generated\";\n\nconst GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"spec.ts\"),\n);\nconst GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"nodeSpec.ts\"),\n);\n\n// Quiescence window: the sync loop waits this long for further signals\n// after each batch. One user edit fires `onEnd` on every esbuild\n// watcher that touches the file, and rebuild times vary across entry\n// points so the onEnds can be spread over hundreds of milliseconds.\n// The drain keeps extending its wait (bounded by `COALESCE_MAX_WAIT`)\n// until no new signals arrive within the window, collapsing the whole\n// burst into a single codegen cycle.\nconst COALESCE_QUIESCENCE = Duration.millis(300);\n\n// Upper bound on `drainUntilQuiescent` so a pathological infinite\n// signal stream can't pin the sync loop forever.\nconst COALESCE_MAX_WAIT = Duration.seconds(5);\n\n// How long to wait for esbuild watchers to react to codegen's own\n// writes (e.g. an updated `_generated/spec.ts`). Added on top of the\n// quiescence drain when codegen reported writes happened.\nconst ECHO_COOLDOWN = Duration.millis(500);\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\ntype Pending = {\n readonly specDirty: boolean;\n readonly httpDirty: boolean;\n readonly cronsDirty: boolean;\n readonly authDirty: boolean;\n};\n\ntype PendingKey = keyof Pending;\n\nconst pendingInit: Pending = {\n specDirty: false,\n httpDirty: false,\n cronsDirty: false,\n authDirty: false,\n};\n\nconst isPendingDirty = (p: Pending): boolean =>\n p.specDirty || p.httpDirty || p.cronsDirty || p.authDirty;\n\ntype WatcherErrors = ReadonlyMap<string, readonly esbuild.Message[]>;\n\nconst emptyWatcherErrors: WatcherErrors = new Map();\n\nconst changeChar = (change: \"Added\" | \"Removed\" | \"Modified\") =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => ({ char: \"+\", color: Ansi.green })),\n Match.when(\"Removed\", () => ({ char: \"-\", color: Ansi.red })),\n Match.when(\"Modified\", () => ({ char: \"~\", color: Ansi.magenta })),\n Match.exhaustive,\n );\n\nconst logFileChangeIndented = (\n change: \"Added\" | \"Removed\" | \"Modified\",\n fullPath: string,\n) =>\n Effect.gen(function* () {\n const projectRoot = yield* ProjectRoot.get;\n const path = yield* Path.Path;\n\n const prefix = projectRoot + path.sep;\n const suffix = pipe(fullPath, String.startsWith(prefix))\n ? pipe(fullPath, String.slice(prefix.length))\n : fullPath;\n\n const { char, color } = changeChar(change);\n\n yield* Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(color),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)),\n pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n });\n\nconst logFunctionPathDiff = (\n previous: FunctionPaths.FunctionPaths,\n current: FunctionPaths.FunctionPaths,\n) =>\n Effect.gen(function* () {\n const {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n } = FunctionPaths.diff(previous, current);\n\n const logForGroups = (\n groupPaths: GroupPaths.GroupPaths,\n fnPaths: FunctionPaths.FunctionPaths,\n logFn: typeof logFunctionAdded,\n ) =>\n Effect.forEach(groupPaths, (gp) =>\n Effect.forEach(\n Array.fromIterable(\n HashSet.filter(fnPaths, (fp) => Equal.equals(fp.groupPath, gp)),\n ),\n logFn,\n ),\n );\n\n yield* logForGroups(groupsRemoved, functionsRemoved, logFunctionRemoved);\n yield* logForGroups(groupsAdded, functionsAdded, logFunctionAdded);\n yield* Effect.forEach(groupsChanged, (gp) =>\n Effect.gen(function* () {\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAdded,\n );\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemoved,\n );\n }),\n );\n });\n\nexport const dev = Command.make(\"dev\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n const previousFunctionPaths = yield* loadPreviousFunctionPaths;\n const initialResult = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths }) =>\n logFunctionPathDiff(previousFunctionPaths, functionPaths),\n ),\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.catchAndLog,\n );\n const initialFunctionPaths = Option.match(initialResult, {\n onNone: () => emptyFunctionPaths,\n onSome: ({ functionPaths }) => functionPaths,\n });\n\n const pendingRef = yield* Ref.make<Pending>(pendingInit);\n const signal = yield* Queue.sliding<void>(1);\n const restartQueue = yield* Queue.sliding<void>(1);\n const watcherErrorsRef = yield* Ref.make<WatcherErrors>(emptyWatcherErrors);\n\n yield* Effect.all(\n [\n Effect.scoped(\n entryPointsWatcher(\n signal,\n pendingRef,\n restartQueue,\n watcherErrorsRef,\n ),\n ),\n confectStructureWatcher(signal, pendingRef, restartQueue),\n syncLoop(signal, pendingRef, initialFunctionPaths, watcherErrorsRef),\n ],\n { concurrency: \"unbounded\" },\n );\n }),\n).pipe(Command.withDescription(\"Start the Confect development server\"));\n\nconst esbuildMessageKey = (m: esbuild.Message): string =>\n `${m.location?.file ?? \"\"}:${m.location?.line ?? \"\"}:${m.location?.column ?? \"\"}:${m.text}`;\n\nconst allMessages = (errors: WatcherErrors): ReadonlyArray<esbuild.Message> =>\n pipe(Array.fromIterable(errors.values()), Array.flatten);\n\nconst dedupeWatcherErrors = (\n errors: WatcherErrors,\n): ReadonlyArray<esbuild.Message> =>\n pipe(\n allMessages(errors),\n Array.dedupeWith(\n (messageA, messageB) =>\n esbuildMessageKey(messageA) === esbuildMessageKey(messageB),\n ),\n );\n\nconst watcherErrorsSignature = (errors: WatcherErrors): string =>\n pipe(\n allMessages(errors),\n Array.map(esbuildMessageKey),\n Array.dedupe,\n Array.sort(Order.string),\n Array.join(\"\\n\"),\n );\n\n/**\n * Log any watcher errors that haven't already been logged at their\n * current signature. Suppresses the per-watcher fanout that happens\n * when one root cause (e.g. a missing import) breaks every entry\n * point's build at the same source location.\n */\nconst logChangedWatcherErrors = (\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n lastLoggedSignatureRef: Ref.Ref<string>,\n) =>\n Effect.gen(function* () {\n const errors = yield* Ref.get(watcherErrorsRef);\n const signature = watcherErrorsSignature(errors);\n const previous = yield* Ref.get(lastLoggedSignatureRef);\n if (signature === previous) return;\n yield* Ref.set(lastLoggedSignatureRef, signature);\n if (errors.size === 0) return;\n yield* logCoalescedBuildErrors(dedupeWatcherErrors(errors));\n });\n\n/**\n * Block until the signal queue has been quiet for `quiescence`. esbuild\n * watchers' `onEnd` events for a single user edit can be spread across\n * hundreds of milliseconds, so a fixed window misses late arrivals.\n * Bounded by `maxWait` so pathological signal floods can't pin the\n * loop forever.\n */\nconst drainUntilQuiescent = (\n signal: Queue.Queue<void>,\n quiescence: Duration.Duration,\n maxWait: Duration.Duration,\n) =>\n Effect.gen(function* () {\n const start = yield* Clock.currentTimeMillis;\n const maxMillis = Duration.toMillis(maxWait);\n yield* Effect.iterate(true as boolean, {\n while: (keepGoing) => keepGoing,\n body: () =>\n Effect.gen(function* () {\n yield* Effect.sleep(quiescence);\n const drained = yield* Queue.takeAll(signal);\n if (Chunk.isEmpty(drained)) return false;\n const now = yield* Clock.currentTimeMillis;\n return now - start < maxMillis;\n }),\n });\n });\n\nconst syncLoop = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n initialFunctionPaths: FunctionPaths.FunctionPaths,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const functionPathsRef = yield* Ref.make(initialFunctionPaths);\n const lastLoggedErrorsRef = yield* Ref.make<string>(\"\");\n\n return yield* Effect.forever(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Running sync loop…\");\n // Wait for the first signal of a burst, then keep absorbing\n // follow-up signals from other watchers' onEnds until the queue\n // stays quiet for `COALESCE_QUIESCENCE`.\n yield* Queue.take(signal);\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n\n yield* logChangedWatcherErrors(watcherErrorsRef, lastLoggedErrorsRef);\n\n const pending = yield* Ref.getAndSet(pendingRef, pendingInit);\n\n if (!isPendingDirty(pending)) {\n // No-op signal (e.g. a late echo after a previous cycle\n // already drained). Stay silent.\n return;\n }\n\n yield* logPending(\"Dependencies may have changed, reloading…\");\n\n if (pending.specDirty) {\n const current = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths: nextFunctionPaths }) =>\n Effect.gen(function* () {\n const previous = yield* Ref.get(functionPathsRef);\n yield* logFunctionPathDiff(previous, nextFunctionPaths);\n yield* Ref.set(functionPathsRef, nextFunctionPaths);\n }),\n ),\n CodegenError.catchAndLog,\n );\n if (Option.isNone(current)) {\n return;\n }\n // Drain any stragglers from this cycle's burst (slow watchers\n // whose onEnd fired after the first quiescence) plus, when\n // codegen wrote, the echo signals esbuild emits in response\n // to our writes. Reset `pendingRef` so those drained signals\n // don't carry a dirty flag into the next cycle.\n if (current.value.anyWritesHappened) {\n yield* Effect.sleep(ECHO_COOLDOWN);\n }\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n yield* Ref.set(pendingRef, pendingInit);\n }\n\n const dirtyOptionalFiles = [\n ...(pending.httpDirty\n ? [syncOptionalFile(generateHttp, \"http.ts\")]\n : []),\n ...(pending.cronsDirty\n ? [syncOptionalFile(generateCrons, \"crons.ts\")]\n : []),\n ...(pending.authDirty\n ? [syncOptionalFile(generateAuthConfig, \"auth.config.ts\")]\n : []),\n ];\n\n yield* Array.isNonEmptyReadonlyArray(dirtyOptionalFiles)\n ? Effect.all(dirtyOptionalFiles, { concurrency: \"unbounded\" })\n : Effect.void;\n\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n );\n });\n\ninterface EntryPoint {\n readonly absolutePath: string;\n readonly displayPath: string;\n readonly pendingKey: PendingKey;\n}\n\n/**\n * Every file whose import graph codegen should react to. Each one becomes\n * its own scoped esbuild watcher; the union of their watches gives us\n * dependency-aware tracking of anything reachable from `confect/`,\n * including files outside `confect/`.\n */\nconst discoverEntryPoints = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const projectRoot = yield* ProjectRoot.get;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const tryEntry = (relativePath: string, pendingKey: PendingKey) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (!(yield* fs.exists(absolutePath))) {\n return Option.none<EntryPoint>();\n }\n return Option.some<EntryPoint>({\n absolutePath,\n displayPath: path.relative(projectRoot, absolutePath),\n pendingKey,\n });\n });\n\n const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n\n const fixedEntryOptions = yield* Effect.all([\n tryEntry(generatedSpecPath, \"specDirty\"),\n tryEntry(generatedNodeSpecPath, \"specDirty\"),\n // `confect/schema.ts` is no longer user-authored; the runtime\n // `DatabaseSchema` lives at `_generated/schema.ts` (codegen-written,\n // so not an entry point — wiring it through esbuild would form a\n // codegen→write→onEnd→codegen loop). Updates to `confect/tables/*.ts`\n // still reach this dev loop via the impl entry points' import graphs;\n // brand-new tables are caught by the Create-event safety net below.\n tryEntry(\"http.ts\", \"httpDirty\"),\n tryEntry(\"crons.ts\", \"cronsDirty\"),\n tryEntry(\"auth.ts\", \"authDirty\"),\n ]);\n\n const implRelativePaths = yield* discoverLeafImplFiles;\n const implEntryOptions = yield* Effect.forEach(\n implRelativePaths,\n (relativePath) => tryEntry(relativePath, \"specDirty\"),\n );\n\n return Array.getSomes([...fixedEntryOptions, ...implEntryOptions]);\n});\n\nconst esbuildOptions = (\n entry: EntryPoint,\n notExternal: ReadonlyArray<RegExp>,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) => {\n // First `onEnd` fires when esbuild finishes the watcher's initial\n // build. At startup that's an echo of the just-completed initial\n // codegen pass; for a watcher spawned mid-session (e.g. a newly\n // added impl) it's an echo of the codegen run that triggered the\n // restart. Either way, the entry's contents were already accounted\n // for, so we record any errors but don't flip dirty or push a\n // signal — only genuine subsequent rebuilds should do that.\n const initialBuildSeenRef = Ref.unsafeMake(false);\n return {\n entryPoints: [entry.absolutePath],\n bundle: true,\n write: false,\n metafile: true,\n platform: \"node\" as const,\n format: \"esm\" as const,\n logLevel: \"silent\" as const,\n plugins: [\n externalPlugin({ notExternal: [...notExternal] }),\n {\n name: \"notify-rebuild\",\n setup(build: esbuild.PluginBuild) {\n build.onEnd((result) => {\n Effect.runPromise(\n Effect.gen(function* () {\n const wasInitial = yield* Ref.getAndSet(\n initialBuildSeenRef,\n true,\n );\n const isInitial = !wasInitial;\n yield* Ref.update(watcherErrorsRef, (current) => {\n const next = new Map(current);\n if (result.errors.length > 0) {\n next.set(entry.absolutePath, result.errors);\n } else {\n next.delete(entry.absolutePath);\n }\n return next;\n });\n if (isInitial && result.errors.length === 0) return;\n yield* Ref.update(pendingRef, (p) => ({\n ...p,\n [entry.pendingKey]: true,\n }));\n yield* Queue.offer(signal, undefined);\n }),\n );\n });\n },\n },\n ],\n };\n};\n\nconst createEntryPointWatcher = (\n entry: EntryPoint,\n notExternal: ReadonlyArray<RegExp>,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.acquireRelease(\n Effect.promise(async () => {\n const ctx = await esbuild.context(\n esbuildOptions(\n entry,\n notExternal,\n signal,\n pendingRef,\n watcherErrorsRef,\n ),\n );\n await ctx.watch();\n return ctx;\n }),\n (ctx) =>\n Effect.gen(function* () {\n yield* Effect.promise(() => ctx.dispose());\n // Clear any errors recorded by this watcher so a disposed\n // watcher can't leave stale errors visible to the sync loop.\n yield* Ref.update(watcherErrorsRef, (current) => {\n if (!current.has(entry.absolutePath)) return current;\n const next = new Map(current);\n next.delete(entry.absolutePath);\n return next;\n });\n yield* Effect.logDebug(\n `esbuild watcher disposed: ${entry.displayPath}`,\n );\n }),\n );\n\n/**\n * Holds one scoped esbuild watcher per entry point and reconciles the set\n * whenever something offers to `restartQueue`. Adding or removing an entry\n * point only spawns/disposes the affected watcher; unchanged entries keep\n * their existing context, so a structural change doesn't churn watchers\n * for unrelated files.\n */\nconst entryPointsWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const parentScope = yield* Effect.scope;\n const scopesRef = yield* Ref.make(new Map<string, Scope.CloseableScope>());\n const projectRoot = yield* ProjectRoot.get;\n // Discover the user's `tsconfig.json#paths` once at watcher startup so\n // `~/...`-style aliases pointing into the user's source tree get bundled\n // by esbuild instead of externalized via `bundle-require`'s `node_modules`\n // heuristic. `loadTsConfig` walks up from `projectRoot` to find a\n // `tsconfig.json`; if none exists, `paths` is empty and `notExternal` is\n // `[]`, leaving the externalization rule unchanged.\n const tsconfig = loadTsConfig(projectRoot);\n const notExternal = tsconfigPathsToRegExp(\n tsconfig?.data.compilerOptions?.paths ?? {},\n );\n\n const sync = Effect.gen(function* () {\n const desired = yield* discoverEntryPoints;\n const desiredByPath = new Map(\n desired.map((entryPoint) => [entryPoint.absolutePath, entryPoint]),\n );\n const current = yield* Ref.get(scopesRef);\n\n yield* Effect.forEach(\n Array.fromIterable(current),\n ([absolutePath, childScope]) =>\n desiredByPath.has(absolutePath)\n ? Effect.void\n : Scope.close(childScope, Exit.void).pipe(\n Effect.andThen(\n Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.delete(absolutePath);\n return updated;\n }),\n ),\n ),\n );\n\n yield* Effect.forEach(desired, (entry) =>\n Effect.gen(function* () {\n const existing = yield* Ref.get(scopesRef);\n if (existing.has(entry.absolutePath)) return;\n\n const childScope = yield* Scope.fork(\n parentScope,\n ExecutionStrategy.sequential,\n );\n yield* createEntryPointWatcher(\n entry,\n notExternal,\n signal,\n pendingRef,\n watcherErrorsRef,\n ).pipe(Scope.extend(childScope));\n yield* Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.set(entry.absolutePath, childScope);\n return updated;\n });\n }),\n );\n });\n\n yield* sync;\n\n return yield* Effect.forever(\n Queue.take(restartQueue).pipe(Effect.andThen(sync)),\n );\n });\n\n/**\n * Single recursive `fs.watch` on `confect/`. Flips the matching dirty flag\n * for any change to an entry-point-shaped file (so codegen runs without\n * waiting on a newly spawned esbuild watcher), and offers to\n * `restartQueue` when an entry point is created or removed so the watcher\n * manager picks up the new set.\n */\nconst confectStructureWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* pipe(\n fs.watch(confectDirectory, { recursive: true }),\n Stream.debounce(Duration.millis(200)),\n Stream.runForEach((event) =>\n handleConfectChange({\n relativePath: path.relative(confectDirectory, event.path),\n eventTag: event._tag,\n signal,\n pendingRef,\n restartQueue,\n }),\n ),\n );\n });\n\nconst TOP_LEVEL_OPTIONAL_KEYS: ReadonlyMap<string, PendingKey> = new Map([\n [\"http.ts\", \"httpDirty\"],\n [\"crons.ts\", \"cronsDirty\"],\n [\"auth.ts\", \"authDirty\"],\n]);\n\nconst flipDirtyAndSignal = (\n pendingRef: Ref.Ref<Pending>,\n signal: Queue.Queue<void>,\n key: PendingKey,\n restartQueue: Queue.Queue<void>,\n restart: boolean,\n) =>\n pipe(\n Ref.update(pendingRef, (p) => ({ ...p, [key]: true })),\n Effect.andThen(Queue.offer(signal, undefined)),\n Effect.andThen(\n restart ? Queue.offer(restartQueue, undefined) : Effect.void,\n ),\n );\n\nconst handleConfectChange = ({\n relativePath,\n eventTag,\n signal,\n pendingRef,\n restartQueue,\n}: {\n relativePath: string;\n eventTag: \"Create\" | \"Update\" | \"Remove\";\n signal: Queue.Queue<void>;\n pendingRef: Ref.Ref<Pending>;\n restartQueue: Queue.Queue<void>;\n}) => {\n // _generated/ files are written by codegen itself; reacting to them here\n // would form a loop. The esbuild watchers track the generated specs as\n // entry points, so changes there flow back through `notify-rebuild`.\n if (relativePath.split(/[/\\\\]/).includes(\"_generated\")) {\n return Effect.void;\n }\n\n if (!relativePath.endsWith(\".ts\")) {\n return Effect.void;\n }\n\n const isLifecycleChange = eventTag !== \"Update\";\n\n const topLevelKey = TOP_LEVEL_OPTIONAL_KEYS.get(relativePath);\n if (topLevelKey !== undefined) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n topLevelKey,\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // A stray `confect/schema.ts` (now codegen-owned at\n // `_generated/schema.ts`) shouldn't exist; flagging it here ensures the\n // next codegen pass surfaces the migration error\n // (`LegacySchemaFileError`) instead of silently ignoring the file.\n if (relativePath === \"schema.ts\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n if (isLeafSpecPath(relativePath) || isLeafImplPath(relativePath)) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // Any other `.ts` under `confect/` (helpers like `tables/notes.ts`).\n // Updates to such files are handled by the esbuild watcher for whichever\n // entry point imports them — its onEnd flips the right dirty flag.\n // Creates are our safety net: when a previously-missing import is added,\n // esbuild may not have its parent directory on a poll path, so we\n // re-run codegen on Create here.\n if (eventTag === \"Create\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n false,\n );\n }\n\n return Effect.void;\n};\n\nconst syncOptionalFile = (generate: typeof generateHttp, convexFile: string) =>\n pipe(\n generate,\n Effect.andThen(\n Option.match({\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Unchanged\", () => Effect.void),\n Match.whenOr(\"Added\", \"Modified\", (addedOrModified) =>\n logFileChangeIndented(addedOrModified, convexFilePath),\n ),\n Match.exhaustive,\n ),\n onNone: () =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const convexFilePath = path.join(convexDirectory, convexFile);\n\n if (yield* fs.exists(convexFilePath)) {\n yield* fs.remove(convexFilePath);\n yield* logFileChangeIndented(\"Removed\", convexFilePath);\n }\n }),\n }),\n ),\n );\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dev.mjs","names":["FunctionPaths.diff","CodegenError.catchAndLog"],"sources":["../../src/confect/dev.ts"],"sourcesContent":["import * as Command from \"@effect/cli/Command\";\nimport * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/Path\";\nimport * as Ansi from \"@effect/printer-ansi/Ansi\";\nimport * as AnsiDoc from \"@effect/printer-ansi/AnsiDoc\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Chunk from \"effect/Chunk\";\nimport * as Clock from \"effect/Clock\";\nimport * as Console from \"effect/Console\";\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport * as Equal from \"effect/Equal\";\nimport * as ExecutionStrategy from \"effect/ExecutionStrategy\";\nimport * as Exit from \"effect/Exit\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Order from \"effect/Order\";\nimport * as Queue from \"effect/Queue\";\nimport * as Ref from \"effect/Ref\";\nimport * as Scope from \"effect/Scope\";\nimport * as Stream from \"effect/Stream\";\nimport * as String from \"effect/String\";\nimport {\n externalPlugin,\n loadTsConfig,\n tsconfigPathsToRegExp,\n} from \"bundle-require\";\nimport * as esbuild from \"esbuild\";\nimport { logCoalescedBuildErrors } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport type * as GroupPaths from \"../GroupPaths\";\nimport {\n discoverLeafImplFiles,\n isLeafImplPath,\n isLeafSpecPath,\n} from \"../LeafModule\";\nimport {\n logFunctionAdded,\n logFunctionRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ProjectRoot } from \"../ProjectRoot\";\nimport { generateAuthConfig, generateCrons, generateHttp } from \"../utils\";\nimport { codegenHandler, loadPreviousFunctionPaths } from \"./codegen\";\n\nconst GENERATED_DIRNAME = \"_generated\";\n\nconst GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"spec.ts\"),\n);\nconst GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"nodeSpec.ts\"),\n);\n\n// Quiescence window: the sync loop waits this long for further signals\n// after each batch. One user edit fires `onEnd` on every esbuild\n// watcher that touches the file, and rebuild times vary across entry\n// points so the onEnds can be spread over hundreds of milliseconds.\n// The drain keeps extending its wait (bounded by `COALESCE_MAX_WAIT`)\n// until no new signals arrive within the window, collapsing the whole\n// burst into a single codegen cycle.\nconst COALESCE_QUIESCENCE = Duration.millis(300);\n\n// Upper bound on `drainUntilQuiescent` so a pathological infinite\n// signal stream can't pin the sync loop forever.\nconst COALESCE_MAX_WAIT = Duration.seconds(5);\n\n// How long to wait for esbuild watchers to react to codegen's own\n// writes (e.g. an updated `_generated/spec.ts`). Added on top of the\n// quiescence drain when codegen reported writes happened.\nconst ECHO_COOLDOWN = Duration.millis(500);\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\ntype Pending = {\n readonly specDirty: boolean;\n readonly httpDirty: boolean;\n readonly cronsDirty: boolean;\n readonly authDirty: boolean;\n};\n\ntype PendingKey = keyof Pending;\n\nconst pendingInit: Pending = {\n specDirty: false,\n httpDirty: false,\n cronsDirty: false,\n authDirty: false,\n};\n\nconst isPendingDirty = (p: Pending): boolean =>\n p.specDirty || p.httpDirty || p.cronsDirty || p.authDirty;\n\ntype WatcherErrors = ReadonlyMap<string, readonly esbuild.Message[]>;\n\nconst emptyWatcherErrors: WatcherErrors = new Map();\n\nconst changeChar = (change: \"Added\" | \"Removed\" | \"Modified\") =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => ({ char: \"+\", color: Ansi.green })),\n Match.when(\"Removed\", () => ({ char: \"-\", color: Ansi.red })),\n Match.when(\"Modified\", () => ({ char: \"~\", color: Ansi.magenta })),\n Match.exhaustive,\n );\n\nconst logFileChangeIndented = (\n change: \"Added\" | \"Removed\" | \"Modified\",\n fullPath: string,\n) =>\n Effect.gen(function* () {\n const projectRoot = yield* ProjectRoot.get;\n const path = yield* Path.Path;\n\n const prefix = projectRoot + path.sep;\n const suffix = pipe(fullPath, String.startsWith(prefix))\n ? pipe(fullPath, String.slice(prefix.length))\n : fullPath;\n\n const { char, color } = changeChar(change);\n\n yield* Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(color),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)),\n pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n });\n\nconst logFunctionPathDiff = (\n previous: FunctionPaths.FunctionPaths,\n current: FunctionPaths.FunctionPaths,\n) =>\n Effect.gen(function* () {\n const {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n } = FunctionPaths.diff(previous, current);\n\n const logForGroups = (\n groupPaths: GroupPaths.GroupPaths,\n fnPaths: FunctionPaths.FunctionPaths,\n logFn: typeof logFunctionAdded,\n ) =>\n Effect.forEach(groupPaths, (gp) =>\n Effect.forEach(\n Array.fromIterable(\n HashSet.filter(fnPaths, (fp) => Equal.equals(fp.groupPath, gp)),\n ),\n logFn,\n ),\n );\n\n yield* logForGroups(groupsRemoved, functionsRemoved, logFunctionRemoved);\n yield* logForGroups(groupsAdded, functionsAdded, logFunctionAdded);\n yield* Effect.forEach(groupsChanged, (gp) =>\n Effect.gen(function* () {\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAdded,\n );\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemoved,\n );\n }),\n );\n });\n\nexport const dev = Command.make(\"dev\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n const previousFunctionPaths = yield* loadPreviousFunctionPaths;\n const initialResult = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths }) =>\n logFunctionPathDiff(previousFunctionPaths, functionPaths),\n ),\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.catchAndLog,\n );\n const initialFunctionPaths = Option.match(initialResult, {\n onNone: () => emptyFunctionPaths,\n onSome: ({ functionPaths }) => functionPaths,\n });\n\n const pendingRef = yield* Ref.make<Pending>(pendingInit);\n const signal = yield* Queue.sliding<void>(1);\n const restartQueue = yield* Queue.sliding<void>(1);\n const watcherErrorsRef = yield* Ref.make<WatcherErrors>(emptyWatcherErrors);\n\n yield* Effect.all(\n [\n Effect.scoped(\n entryPointsWatcher(\n signal,\n pendingRef,\n restartQueue,\n watcherErrorsRef,\n ),\n ),\n confectStructureWatcher(signal, pendingRef, restartQueue),\n syncLoop(signal, pendingRef, initialFunctionPaths, watcherErrorsRef),\n ],\n { concurrency: \"unbounded\" },\n );\n }),\n).pipe(Command.withDescription(\"Start the Confect development server\"));\n\nconst esbuildMessageKey = (m: esbuild.Message): string =>\n `${m.location?.file ?? \"\"}:${m.location?.line ?? \"\"}:${m.location?.column ?? \"\"}:${m.text}`;\n\nconst allMessages = (errors: WatcherErrors): ReadonlyArray<esbuild.Message> =>\n pipe(Array.fromIterable(errors.values()), Array.flatten);\n\nconst dedupeWatcherErrors = (\n errors: WatcherErrors,\n): ReadonlyArray<esbuild.Message> =>\n pipe(\n allMessages(errors),\n Array.dedupeWith(\n (messageA, messageB) =>\n esbuildMessageKey(messageA) === esbuildMessageKey(messageB),\n ),\n );\n\nconst watcherErrorsSignature = (errors: WatcherErrors): string =>\n pipe(\n allMessages(errors),\n Array.map(esbuildMessageKey),\n Array.dedupe,\n Array.sort(Order.string),\n Array.join(\"\\n\"),\n );\n\n/**\n * Log any watcher errors that haven't already been logged at their\n * current signature. Suppresses the per-watcher fanout that happens\n * when one root cause (e.g. a missing import) breaks every entry\n * point's build at the same source location.\n */\nconst logChangedWatcherErrors = (\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n lastLoggedSignatureRef: Ref.Ref<string>,\n) =>\n Effect.gen(function* () {\n const errors = yield* Ref.get(watcherErrorsRef);\n const signature = watcherErrorsSignature(errors);\n const previous = yield* Ref.get(lastLoggedSignatureRef);\n if (signature === previous) return;\n yield* Ref.set(lastLoggedSignatureRef, signature);\n if (errors.size === 0) return;\n yield* logCoalescedBuildErrors(dedupeWatcherErrors(errors));\n });\n\n/**\n * Block until the signal queue has been quiet for `quiescence`. esbuild\n * watchers' `onEnd` events for a single user edit can be spread across\n * hundreds of milliseconds, so a fixed window misses late arrivals.\n * Bounded by `maxWait` so pathological signal floods can't pin the\n * loop forever.\n */\nconst drainUntilQuiescent = (\n signal: Queue.Queue<void>,\n quiescence: Duration.Duration,\n maxWait: Duration.Duration,\n) =>\n Effect.gen(function* () {\n const start = yield* Clock.currentTimeMillis;\n const maxMillis = Duration.toMillis(maxWait);\n yield* Effect.iterate(true as boolean, {\n while: (keepGoing) => keepGoing,\n body: () =>\n Effect.gen(function* () {\n yield* Effect.sleep(quiescence);\n const drained = yield* Queue.takeAll(signal);\n if (Chunk.isEmpty(drained)) return false;\n const now = yield* Clock.currentTimeMillis;\n return now - start < maxMillis;\n }),\n });\n });\n\nconst syncLoop = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n initialFunctionPaths: FunctionPaths.FunctionPaths,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const functionPathsRef = yield* Ref.make(initialFunctionPaths);\n const lastLoggedErrorsRef = yield* Ref.make<string>(\"\");\n\n return yield* Effect.forever(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Running sync loop…\");\n // Wait for the first signal of a burst, then keep absorbing\n // follow-up signals from other watchers' onEnds until the queue\n // stays quiet for `COALESCE_QUIESCENCE`.\n yield* Queue.take(signal);\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n\n yield* logChangedWatcherErrors(watcherErrorsRef, lastLoggedErrorsRef);\n\n const pending = yield* Ref.getAndSet(pendingRef, pendingInit);\n\n if (!isPendingDirty(pending)) {\n // No-op signal (e.g. a late echo after a previous cycle\n // already drained). Stay silent.\n return;\n }\n\n yield* logPending(\"Dependencies may have changed, reloading…\");\n\n if (pending.specDirty) {\n const current = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths: nextFunctionPaths }) =>\n Effect.gen(function* () {\n const previous = yield* Ref.get(functionPathsRef);\n yield* logFunctionPathDiff(previous, nextFunctionPaths);\n yield* Ref.set(functionPathsRef, nextFunctionPaths);\n }),\n ),\n CodegenError.catchAndLog,\n );\n if (Option.isNone(current)) {\n return;\n }\n // Drain any stragglers from this cycle's burst (slow watchers\n // whose onEnd fired after the first quiescence) plus, when\n // codegen wrote, the echo signals esbuild emits in response\n // to our writes. Reset `pendingRef` so those drained signals\n // don't carry a dirty flag into the next cycle.\n if (current.value.anyWritesHappened) {\n yield* Effect.sleep(ECHO_COOLDOWN);\n }\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n yield* Ref.set(pendingRef, pendingInit);\n }\n\n const dirtyOptionalFiles = [\n ...(pending.httpDirty\n ? [syncOptionalFile(generateHttp, \"http.ts\")]\n : []),\n ...(pending.cronsDirty\n ? [syncOptionalFile(generateCrons, \"crons.ts\")]\n : []),\n ...(pending.authDirty\n ? [syncOptionalFile(generateAuthConfig, \"auth.config.ts\")]\n : []),\n ];\n\n yield* Array.isNonEmptyReadonlyArray(dirtyOptionalFiles)\n ? Effect.all(dirtyOptionalFiles, { concurrency: \"unbounded\" })\n : Effect.void;\n\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n );\n });\n\ninterface EntryPoint {\n readonly absolutePath: string;\n readonly displayPath: string;\n readonly pendingKey: PendingKey;\n}\n\n/**\n * Every file whose import graph codegen should react to. Each one becomes\n * its own scoped esbuild watcher; the union of their watches gives us\n * dependency-aware tracking of anything reachable from `confect/`,\n * including files outside `confect/`.\n */\nconst discoverEntryPoints = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const projectRoot = yield* ProjectRoot.get;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const tryEntry = (relativePath: string, pendingKey: PendingKey) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (!(yield* fs.exists(absolutePath))) {\n return Option.none<EntryPoint>();\n }\n return Option.some<EntryPoint>({\n absolutePath,\n displayPath: path.relative(projectRoot, absolutePath),\n pendingKey,\n });\n });\n\n const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n\n const fixedEntryOptions = yield* Effect.all([\n tryEntry(generatedSpecPath, \"specDirty\"),\n tryEntry(generatedNodeSpecPath, \"specDirty\"),\n // `confect/schema.ts` is no longer user-authored; the runtime\n // `DatabaseSchema` lives at `_generated/schema.ts` (codegen-written,\n // so not an entry point — wiring it through esbuild would form a\n // codegen→write→onEnd→codegen loop). Updates to `confect/tables/*.ts`\n // still reach this dev loop via the impl entry points' import graphs;\n // brand-new tables are caught by the Create-event safety net below.\n tryEntry(\"http.ts\", \"httpDirty\"),\n tryEntry(\"crons.ts\", \"cronsDirty\"),\n tryEntry(\"auth.ts\", \"authDirty\"),\n ]);\n\n const implRelativePaths = yield* discoverLeafImplFiles;\n const implEntryOptions = yield* Effect.forEach(\n implRelativePaths,\n (relativePath) => tryEntry(relativePath, \"specDirty\"),\n );\n\n return Array.getSomes([...fixedEntryOptions, ...implEntryOptions]);\n});\n\nconst esbuildOptions = (\n entry: EntryPoint,\n notExternal: ReadonlyArray<RegExp>,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) => {\n // First `onEnd` fires when esbuild finishes the watcher's initial\n // build. At startup that's an echo of the just-completed initial\n // codegen pass; for a watcher spawned mid-session (e.g. a newly\n // added impl) it's an echo of the codegen run that triggered the\n // restart. Either way, the entry's contents were already accounted\n // for, so we record any errors but don't flip dirty or push a\n // signal — only genuine subsequent rebuilds should do that.\n const initialBuildSeenRef = Ref.unsafeMake(false);\n return {\n entryPoints: [entry.absolutePath],\n bundle: true,\n write: false,\n metafile: true,\n platform: \"node\" as const,\n format: \"esm\" as const,\n logLevel: \"silent\" as const,\n plugins: [\n externalPlugin({ notExternal: [...notExternal] }),\n {\n name: \"notify-rebuild\",\n setup(build: esbuild.PluginBuild) {\n build.onEnd((result) => {\n Effect.runPromise(\n Effect.gen(function* () {\n const wasInitial = yield* Ref.getAndSet(\n initialBuildSeenRef,\n true,\n );\n const isInitial = !wasInitial;\n yield* Ref.update(watcherErrorsRef, (current) => {\n const next = new Map(current);\n if (result.errors.length > 0) {\n next.set(entry.absolutePath, result.errors);\n } else {\n next.delete(entry.absolutePath);\n }\n return next;\n });\n if (isInitial && result.errors.length === 0) return;\n yield* Ref.update(pendingRef, (p) => ({\n ...p,\n [entry.pendingKey]: true,\n }));\n yield* Queue.offer(signal, undefined);\n }),\n );\n });\n },\n },\n ],\n };\n};\n\nconst createEntryPointWatcher = (\n entry: EntryPoint,\n notExternal: ReadonlyArray<RegExp>,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.acquireRelease(\n Effect.promise(async () => {\n const ctx = await esbuild.context(\n esbuildOptions(\n entry,\n notExternal,\n signal,\n pendingRef,\n watcherErrorsRef,\n ),\n );\n await ctx.watch();\n return ctx;\n }),\n (ctx) =>\n Effect.gen(function* () {\n yield* Effect.promise(() => ctx.dispose());\n // Clear any errors recorded by this watcher so a disposed\n // watcher can't leave stale errors visible to the sync loop.\n yield* Ref.update(watcherErrorsRef, (current) => {\n if (!current.has(entry.absolutePath)) return current;\n const next = new Map(current);\n next.delete(entry.absolutePath);\n return next;\n });\n yield* Effect.logDebug(\n `esbuild watcher disposed: ${entry.displayPath}`,\n );\n }),\n );\n\n/**\n * Holds one scoped esbuild watcher per entry point and reconciles the set\n * whenever something offers to `restartQueue`. Adding or removing an entry\n * point only spawns/disposes the affected watcher; unchanged entries keep\n * their existing context, so a structural change doesn't churn watchers\n * for unrelated files.\n */\nconst entryPointsWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const parentScope = yield* Effect.scope;\n const scopesRef = yield* Ref.make(new Map<string, Scope.CloseableScope>());\n const projectRoot = yield* ProjectRoot.get;\n // Discover the user's `tsconfig.json#paths` once at watcher startup so\n // `~/...`-style aliases pointing into the user's source tree get bundled\n // by esbuild instead of externalized via `bundle-require`'s `node_modules`\n // heuristic. `loadTsConfig` walks up from `projectRoot` to find a\n // `tsconfig.json`; if none exists, `paths` is empty and `notExternal` is\n // `[]`, leaving the externalization rule unchanged.\n const tsconfig = loadTsConfig(projectRoot);\n const notExternal = tsconfigPathsToRegExp(\n tsconfig?.data.compilerOptions?.paths ?? {},\n );\n\n const sync = Effect.gen(function* () {\n const desired = yield* discoverEntryPoints;\n const desiredByPath = new Map(\n desired.map((entryPoint) => [entryPoint.absolutePath, entryPoint]),\n );\n const current = yield* Ref.get(scopesRef);\n\n yield* Effect.forEach(\n Array.fromIterable(current),\n ([absolutePath, childScope]) =>\n desiredByPath.has(absolutePath)\n ? Effect.void\n : Scope.close(childScope, Exit.void).pipe(\n Effect.andThen(\n Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.delete(absolutePath);\n return updated;\n }),\n ),\n ),\n );\n\n yield* Effect.forEach(desired, (entry) =>\n Effect.gen(function* () {\n const existing = yield* Ref.get(scopesRef);\n if (existing.has(entry.absolutePath)) return;\n\n const childScope = yield* Scope.fork(\n parentScope,\n ExecutionStrategy.sequential,\n );\n yield* createEntryPointWatcher(\n entry,\n notExternal,\n signal,\n pendingRef,\n watcherErrorsRef,\n ).pipe(Scope.extend(childScope));\n yield* Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.set(entry.absolutePath, childScope);\n return updated;\n });\n }),\n );\n });\n\n yield* sync;\n\n return yield* Effect.forever(\n Queue.take(restartQueue).pipe(Effect.andThen(sync)),\n );\n });\n\n/**\n * Single recursive `fs.watch` on `confect/`. Flips the matching dirty flag\n * for any change to an entry-point-shaped file (so codegen runs without\n * waiting on a newly spawned esbuild watcher), and offers to\n * `restartQueue` when an entry point is created or removed so the watcher\n * manager picks up the new set.\n */\nconst confectStructureWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* pipe(\n fs.watch(confectDirectory, { recursive: true }),\n Stream.debounce(Duration.millis(200)),\n Stream.runForEach((event) =>\n handleConfectChange({\n relativePath: path.relative(confectDirectory, event.path),\n eventTag: event._tag,\n signal,\n pendingRef,\n restartQueue,\n }),\n ),\n );\n });\n\nconst TOP_LEVEL_OPTIONAL_KEYS: ReadonlyMap<string, PendingKey> = new Map([\n [\"http.ts\", \"httpDirty\"],\n [\"crons.ts\", \"cronsDirty\"],\n [\"auth.ts\", \"authDirty\"],\n]);\n\nconst flipDirtyAndSignal = (\n pendingRef: Ref.Ref<Pending>,\n signal: Queue.Queue<void>,\n key: PendingKey,\n restartQueue: Queue.Queue<void>,\n restart: boolean,\n) =>\n pipe(\n Ref.update(pendingRef, (p) => ({ ...p, [key]: true })),\n Effect.andThen(Queue.offer(signal, undefined)),\n Effect.andThen(\n restart ? Queue.offer(restartQueue, undefined) : Effect.void,\n ),\n );\n\nconst handleConfectChange = ({\n relativePath,\n eventTag,\n signal,\n pendingRef,\n restartQueue,\n}: {\n relativePath: string;\n eventTag: \"Create\" | \"Update\" | \"Remove\";\n signal: Queue.Queue<void>;\n pendingRef: Ref.Ref<Pending>;\n restartQueue: Queue.Queue<void>;\n}) => {\n // _generated/ files are written by codegen itself; reacting to them here\n // would form a loop. The esbuild watchers track the generated specs as\n // entry points, so changes there flow back through `notify-rebuild`.\n if (relativePath.split(/[/\\\\]/).includes(\"_generated\")) {\n return Effect.void;\n }\n\n if (!relativePath.endsWith(\".ts\")) {\n return Effect.void;\n }\n\n const isLifecycleChange = eventTag !== \"Update\";\n\n const topLevelKey = TOP_LEVEL_OPTIONAL_KEYS.get(relativePath);\n if (topLevelKey !== undefined) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n topLevelKey,\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // A stray `confect/schema.ts` (now codegen-owned at\n // `_generated/schema.ts`) shouldn't exist; flagging it here ensures the\n // next codegen pass surfaces the migration error\n // (`LegacySchemaFileError`) instead of silently ignoring the file.\n if (relativePath === \"schema.ts\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n if (isLeafSpecPath(relativePath) || isLeafImplPath(relativePath)) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // Any other `.ts` under `confect/` (helpers like `tables/notes.ts`).\n // Updates to such files are handled by the esbuild watcher for whichever\n // entry point imports them — its onEnd flips the right dirty flag.\n // Creates are our safety net: when a previously-missing import is added,\n // esbuild may not have its parent directory on a poll path, so we\n // re-run codegen on Create here.\n if (eventTag === \"Create\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n false,\n );\n }\n\n return Effect.void;\n};\n\nconst syncOptionalFile = (generate: typeof generateHttp, convexFile: string) =>\n pipe(\n generate,\n Effect.andThen(\n Option.match({\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Unchanged\", () => Effect.void),\n Match.whenOr(\"Added\", \"Modified\", (addedOrModified) =>\n logFileChangeIndented(addedOrModified, convexFilePath),\n ),\n Match.exhaustive,\n ),\n onNone: () =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const convexFilePath = path.join(convexDirectory, convexFile);\n\n if (yield* fs.exists(convexFilePath)) {\n yield* fs.remove(convexFilePath);\n yield* logFileChangeIndented(\"Removed\", convexFilePath);\n }\n }),\n }),\n ),\n );\n"],"mappings":"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"}
|
package/dist/confect.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import { ConvexDirectory } from "./ConvexDirectory.mjs";
|
|
|
3
3
|
import { ConfectDirectory } from "./ConfectDirectory.mjs";
|
|
4
4
|
import { codegen } from "./confect/codegen.mjs";
|
|
5
5
|
import { dev } from "./confect/dev.mjs";
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import * as Command from "@effect/cli/Command";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
8
|
|
|
9
9
|
//#region src/confect.ts
|
|
10
10
|
const confect = Command.make("confect").pipe(Command.withDescription("Generate and sync Confect files with Convex"), Command.withSubcommands([codegen, dev]), Command.provide(Layer.mergeAll(ConfectDirectory.Default, ProjectRoot.Default, ConvexDirectory.Default)));
|