@confect/cli 1.0.0 → 1.0.2
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 +17 -0
- package/README.md +11 -0
- package/dist/confect/codegen.mjs +4 -10
- package/dist/confect/codegen.mjs.map +1 -1
- package/dist/confect/dev.mjs +4 -19
- package/dist/confect/dev.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/utils.mjs +43 -1
- package/dist/utils.mjs.map +1 -1
- package/package.json +4 -5
- package/src/confect/codegen.ts +4 -14
- package/src/confect/dev.ts +10 -13
- package/src/utils.ts +56 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @confect/cli
|
|
2
2
|
|
|
3
|
+
## 1.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [c4f9d67]
|
|
8
|
+
- @confect/server@1.0.2
|
|
9
|
+
- @confect/core@1.0.2
|
|
10
|
+
|
|
11
|
+
## 1.0.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- d3ecdc7: Fix codegen failure in projects without `"type": "module"` in their `package.json`. Also dramatically improve codegen performance.
|
|
16
|
+
- Updated dependencies [00b12a0]
|
|
17
|
+
- @confect/core@1.0.1
|
|
18
|
+
- @confect/server@1.0.1
|
|
19
|
+
|
|
3
20
|
## 1.0.0
|
|
4
21
|
|
|
5
22
|
### Major Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Confect 🧁
|
|
2
|
+
|
|
3
|
+
Confect is a framework that deeply integrates Effect with Convex. It's more than just Effect bindings! Confect allows you to:
|
|
4
|
+
|
|
5
|
+
- Define your Convex database schema using Effect schemas.
|
|
6
|
+
- Write Convex function args and returns validators using Effect's schema library.
|
|
7
|
+
- Use Confect functions to automatically decode and encode your data according to your Effect schema definitions for end-to-end rich types, from client to function to database (and back).
|
|
8
|
+
- Use Effect's HTTP API modules to define your HTTP API(s). Includes interactive OpenAPI documentation powered by [Scalar](https://github.com/scalar/scalar).
|
|
9
|
+
- Access Convex platform capabilities via Effect services.
|
|
10
|
+
|
|
11
|
+
Want to learn more? Read the [docs](https://confect.dev)!
|
package/dist/confect/codegen.mjs
CHANGED
|
@@ -2,13 +2,12 @@ import { logFileAdded, logFileModified, logFileRemoved, logPending, logSuccess }
|
|
|
2
2
|
import { ConvexDirectory } from "../services/ConvexDirectory.mjs";
|
|
3
3
|
import { ConfectDirectory } from "../services/ConfectDirectory.mjs";
|
|
4
4
|
import { api, nodeApi, nodeRegisteredFunctions, refs, registeredFunctions, schema, services } from "../templates.mjs";
|
|
5
|
-
import { generateAuthConfig, generateConvexConfig, generateCrons, generateFunctions, generateHttp, removePathExtension, writeFileStringAndLog } from "../utils.mjs";
|
|
5
|
+
import { bundleAndImport, generateAuthConfig, generateConvexConfig, generateCrons, generateFunctions, generateHttp, removePathExtension, writeFileStringAndLog } from "../utils.mjs";
|
|
6
6
|
import { Effect, Match, Option } from "effect";
|
|
7
7
|
import { Command } from "@effect/cli";
|
|
8
8
|
import { Spec } from "@confect/core";
|
|
9
9
|
import { DatabaseSchema } from "@confect/server";
|
|
10
10
|
import { FileSystem, Path } from "@effect/platform";
|
|
11
|
-
import * as tsx from "tsx/esm/api";
|
|
12
11
|
|
|
13
12
|
//#region src/confect/codegen.ts
|
|
14
13
|
const getNodeSpecPath = Effect.gen(function* () {
|
|
@@ -18,11 +17,9 @@ const getNodeSpecPath = Effect.gen(function* () {
|
|
|
18
17
|
});
|
|
19
18
|
const loadNodeSpec = Effect.gen(function* () {
|
|
20
19
|
const fs = yield* FileSystem.FileSystem;
|
|
21
|
-
const path = yield* Path.Path;
|
|
22
20
|
const nodeSpecPath = yield* getNodeSpecPath;
|
|
23
21
|
if (!(yield* fs.exists(nodeSpecPath))) return Option.none();
|
|
24
|
-
const
|
|
25
|
-
const nodeSpec = (yield* Effect.promise(() => tsx.tsImport(nodeSpecPathUrl.href, import.meta.url))).default;
|
|
22
|
+
const nodeSpec = (yield* bundleAndImport(nodeSpecPath)).default;
|
|
26
23
|
if (!Spec.isNodeSpec(nodeSpec)) return yield* Effect.die("nodeSpec.ts does not export a valid Node Spec");
|
|
27
24
|
return Option.some(nodeSpec);
|
|
28
25
|
});
|
|
@@ -97,9 +94,7 @@ const generateFunctionModules = Effect.gen(function* () {
|
|
|
97
94
|
const fs = yield* FileSystem.FileSystem;
|
|
98
95
|
const path = yield* Path.Path;
|
|
99
96
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
100
|
-
const
|
|
101
|
-
const specPathUrl = yield* path.toFileUrl(specPath);
|
|
102
|
-
const spec = (yield* Effect.promise(() => tsx.tsImport(specPathUrl.href, import.meta.url))).default;
|
|
97
|
+
const spec = (yield* bundleAndImport(path.join(confectDirectory, "spec.ts"))).default;
|
|
103
98
|
if (!Spec.isConvexSpec(spec)) return yield* Effect.die("spec.ts does not export a valid Convex Spec");
|
|
104
99
|
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
105
100
|
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
@@ -114,8 +109,7 @@ const generateSchema = Effect.gen(function* () {
|
|
|
114
109
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
115
110
|
const convexDirectory = yield* ConvexDirectory.get;
|
|
116
111
|
const confectSchemaPath = path.join(confectDirectory, "schema.ts");
|
|
117
|
-
|
|
118
|
-
yield* Effect.promise(() => tsx.tsImport(confectSchemaUrl.href, import.meta.url)).pipe(Effect.andThen((schemaModule) => {
|
|
112
|
+
yield* bundleAndImport(confectSchemaPath).pipe(Effect.andThen((schemaModule) => {
|
|
119
113
|
const defaultExport = schemaModule.default;
|
|
120
114
|
return DatabaseSchema.isSchema(defaultExport) ? Effect.succeed(defaultExport) : Effect.die("Invalid schema module");
|
|
121
115
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.mjs","names":["templates.api","templates.nodeApi","templates.schema","templates.services","templates.registeredFunctions","templates.nodeRegisteredFunctions","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport { DatabaseSchema } from \"@confect/server\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Match, Option } from \"effect\";\nimport * as tsx from \"tsx/esm/api\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ConfectDirectory } from \"../services/ConfectDirectory\";\nimport { ConvexDirectory } from \"../services/ConvexDirectory\";\nimport * as templates from \"../templates\";\nimport {\n generateAuthConfig,\n generateConvexConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n writeFileStringAndLog,\n} from \"../utils\";\n\nconst getNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, \"nodeSpec.ts\");\n});\n\nconst loadNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const nodeSpecPath = yield* getNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const nodeSpecPathUrl = yield* path.toFileUrl(nodeSpecPath);\n const nodeSpecModule = yield* Effect.promise(() =>\n tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),\n );\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.die(\"nodeSpec.ts does not export a valid Node Spec\");\n }\n\n return Option.some(nodeSpec);\n});\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler;\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n yield* Effect.all(\n [\n generateApi,\n generateRefs,\n generateRegisteredFunctions,\n generateNodeApi,\n generateNodeRegisteredFunctions,\n generateServices,\n ],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateConvexConfig),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* fs.remove(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const specPath = path.join(confectDirectory, \"spec.ts\");\n const specPathUrl = yield* path.toFileUrl(specPath);\n\n const specModule = yield* Effect.promise(() =>\n tsx.tsImport(specPathUrl.href, import.meta.url),\n );\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.die(\"spec.ts does not export a valid Convex Spec\");\n }\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecOption = yield* loadNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n const confectSchemaUrl = yield* path.toFileUrl(confectSchemaPath);\n\n yield* Effect.promise(() =>\n tsx.tsImport(confectSchemaUrl.href, import.meta.url),\n ).pipe(\n Effect.andThen((schemaModule) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.die(\"Invalid schema module\");\n }),\n );\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRegisteredFunctions = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const registeredFunctionsPath = path.join(\n confectGeneratedDirectory,\n \"registeredFunctions.ts\",\n );\n const implImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(registeredFunctionsPath),\n path.join(confectDirectory, \"impl.ts\"),\n ),\n );\n\n const registeredFunctionsContents = yield* templates.registeredFunctions({\n implImportPath,\n });\n\n yield* writeFileStringAndLog(\n registeredFunctionsPath,\n registeredFunctionsContents,\n );\n});\n\nexport const generateNodeRegisteredFunctions = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeRegisteredFunctionsPath = path.join(\n confectDirectory,\n \"_generated\",\n \"nodeRegisteredFunctions.ts\",\n );\n\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n\n if (!nodeImplExists || !nodeSpecExists) {\n if (yield* fs.exists(nodeRegisteredFunctionsPath)) {\n yield* fs.remove(nodeRegisteredFunctionsPath);\n yield* logFileRemoved(nodeRegisteredFunctionsPath);\n }\n return;\n }\n\n const nodeImplImportPath = yield* removePathExtension(\n path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),\n );\n\n const nodeRegisteredFunctionsContents =\n yield* templates.nodeRegisteredFunctions({\n nodeImplImportPath,\n });\n\n yield* writeFileStringAndLog(\n nodeRegisteredFunctionsPath,\n nodeRegisteredFunctionsContents,\n );\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* removePathExtension(\n path.relative(refsDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath))\n : null;\n\n const refsContents = yield* templates.refs({\n specImportPath,\n ...(nodeSpecImportPath === null ? {} : { nodeSpecImportPath }),\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"codegen.mjs","names":["templates.api","templates.nodeApi","templates.schema","templates.services","templates.registeredFunctions","templates.nodeRegisteredFunctions","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport { DatabaseSchema } from \"@confect/server\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Match, Option } from \"effect\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ConfectDirectory } from \"../services/ConfectDirectory\";\nimport { ConvexDirectory } from \"../services/ConvexDirectory\";\nimport * as templates from \"../templates\";\nimport {\n bundleAndImport,\n generateAuthConfig,\n generateConvexConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n writeFileStringAndLog,\n} from \"../utils\";\n\nconst getNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, \"nodeSpec.ts\");\n});\n\nconst loadNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const nodeSpecModule = yield* bundleAndImport(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.die(\"nodeSpec.ts does not export a valid Node Spec\");\n }\n\n return Option.some(nodeSpec);\n});\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler;\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n yield* Effect.all(\n [\n generateApi,\n generateRefs,\n generateRegisteredFunctions,\n generateNodeApi,\n generateNodeRegisteredFunctions,\n generateServices,\n ],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateConvexConfig),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* fs.remove(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const specPath = path.join(confectDirectory, \"spec.ts\");\n\n const specModule = yield* bundleAndImport(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.die(\"spec.ts does not export a valid Convex Spec\");\n }\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecOption = yield* loadNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n yield* bundleAndImport(confectSchemaPath).pipe(\n Effect.andThen((schemaModule) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.die(\"Invalid schema module\");\n }),\n );\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRegisteredFunctions = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const registeredFunctionsPath = path.join(\n confectGeneratedDirectory,\n \"registeredFunctions.ts\",\n );\n const implImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(registeredFunctionsPath),\n path.join(confectDirectory, \"impl.ts\"),\n ),\n );\n\n const registeredFunctionsContents = yield* templates.registeredFunctions({\n implImportPath,\n });\n\n yield* writeFileStringAndLog(\n registeredFunctionsPath,\n registeredFunctionsContents,\n );\n});\n\nexport const generateNodeRegisteredFunctions = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeRegisteredFunctionsPath = path.join(\n confectDirectory,\n \"_generated\",\n \"nodeRegisteredFunctions.ts\",\n );\n\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n\n if (!nodeImplExists || !nodeSpecExists) {\n if (yield* fs.exists(nodeRegisteredFunctionsPath)) {\n yield* fs.remove(nodeRegisteredFunctionsPath);\n yield* logFileRemoved(nodeRegisteredFunctionsPath);\n }\n return;\n }\n\n const nodeImplImportPath = yield* removePathExtension(\n path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),\n );\n\n const nodeRegisteredFunctionsContents =\n yield* templates.nodeRegisteredFunctions({\n nodeImplImportPath,\n });\n\n yield* writeFileStringAndLog(\n nodeRegisteredFunctionsPath,\n nodeRegisteredFunctionsContents,\n );\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* removePathExtension(\n path.relative(refsDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath))\n : null;\n\n const refsContents = yield* templates.refs({\n specImportPath,\n ...(nodeSpecImportPath === null ? {} : { nodeSpecImportPath }),\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
|
package/dist/confect/dev.mjs
CHANGED
|
@@ -4,13 +4,12 @@ import { logFailure, logPending, logSuccess } from "../log.mjs";
|
|
|
4
4
|
import { ConvexDirectory } from "../services/ConvexDirectory.mjs";
|
|
5
5
|
import { ConfectDirectory } from "../services/ConfectDirectory.mjs";
|
|
6
6
|
import { diff, make } from "../FunctionPaths.mjs";
|
|
7
|
-
import { generateAuthConfig, generateConvexConfig, generateCrons, generateHttp, removeGroups, writeGroups } from "../utils.mjs";
|
|
7
|
+
import { EXTERNAL_PACKAGES, bundleAndImport, generateAuthConfig, generateConvexConfig, generateCrons, generateHttp, removeGroups, writeGroups } from "../utils.mjs";
|
|
8
8
|
import { codegenHandler, generateNodeApi, generateNodeRegisteredFunctions } from "./codegen.mjs";
|
|
9
9
|
import { Array, Console, Deferred, Duration, Effect, Equal, HashSet, Match, Option, Queue, Ref, Schema, Stream, String, pipe } from "effect";
|
|
10
10
|
import { Command } from "@effect/cli";
|
|
11
11
|
import { Spec } from "@confect/core";
|
|
12
12
|
import { FileSystem, Path } from "@effect/platform";
|
|
13
|
-
import * as tsx from "tsx/esm/api";
|
|
14
13
|
import { Ansi, AnsiDoc } from "@effect/printer-ansi";
|
|
15
14
|
import * as esbuild from "esbuild";
|
|
16
15
|
|
|
@@ -116,11 +115,7 @@ const loadSpec = Effect.gen(function* () {
|
|
|
116
115
|
const fs = yield* FileSystem.FileSystem;
|
|
117
116
|
const path = yield* Path.Path;
|
|
118
117
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
119
|
-
const
|
|
120
|
-
const spec = (yield* Effect.tryPromise({
|
|
121
|
-
try: () => tsx.tsImport(specPathUrl.href, import.meta.url),
|
|
122
|
-
catch: (error) => new SpecImportFailedError({ error })
|
|
123
|
-
})).default;
|
|
118
|
+
const spec = (yield* bundleAndImport(yield* getSpecPath).pipe(Effect.mapError((error) => new SpecImportFailedError({ error })))).default;
|
|
124
119
|
if (!Spec.isConvexSpec(spec)) return yield* new SpecFileDoesNotExportSpecError();
|
|
125
120
|
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
126
121
|
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
@@ -142,14 +137,9 @@ const getNodeSpecPath = Effect.gen(function* () {
|
|
|
142
137
|
});
|
|
143
138
|
const loadNodeSpec = Effect.gen(function* () {
|
|
144
139
|
const fs = yield* FileSystem.FileSystem;
|
|
145
|
-
const path = yield* Path.Path;
|
|
146
140
|
const nodeSpecPath = yield* getNodeSpecPath;
|
|
147
141
|
if (!(yield* fs.exists(nodeSpecPath))) return Option.none();
|
|
148
|
-
const
|
|
149
|
-
const nodeSpec = (yield* Effect.tryPromise({
|
|
150
|
-
try: () => tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),
|
|
151
|
-
catch: (error) => new SpecImportFailedError({ error })
|
|
152
|
-
})).default;
|
|
142
|
+
const nodeSpec = (yield* bundleAndImport(nodeSpecPath).pipe(Effect.mapError((error) => new SpecImportFailedError({ error })))).default;
|
|
153
143
|
if (!Spec.isNodeSpec(nodeSpec)) return yield* new NodeSpecFileDoesNotExportSpecError();
|
|
154
144
|
return Option.some(nodeSpec);
|
|
155
145
|
});
|
|
@@ -161,12 +151,7 @@ const esbuildOptions = (entryPoint) => ({
|
|
|
161
151
|
platform: "node",
|
|
162
152
|
format: "esm",
|
|
163
153
|
logLevel: "silent",
|
|
164
|
-
external:
|
|
165
|
-
"@confect/core",
|
|
166
|
-
"@confect/server",
|
|
167
|
-
"effect",
|
|
168
|
-
"@effect/*"
|
|
169
|
-
],
|
|
154
|
+
external: EXTERNAL_PACKAGES,
|
|
170
155
|
plugins: [{
|
|
171
156
|
name: "notify-rebuild",
|
|
172
157
|
setup(build) {
|
package/dist/confect/dev.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.mjs","names":["GroupPath.toString","FunctionPaths.make","FunctionPaths.diff","GroupPath.modulePath"],"sources":["../../src/confect/dev.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport {\n Array,\n Console,\n Deferred,\n Duration,\n Effect,\n Equal,\n HashSet,\n Match,\n Option,\n pipe,\n Queue,\n Ref,\n Schema,\n Stream,\n String,\n} from \"effect\";\nimport type { ReadonlyRecord } from \"effect/Record\";\nimport * as esbuild from \"esbuild\";\nimport * as tsx from \"tsx/esm/api\";\nimport type * as FunctionPath from \"../FunctionPath\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport * as GroupPath from \"../GroupPath\";\nimport { logFailure, logPending, logSuccess } from \"../log\";\nimport { ConfectDirectory } from \"../services/ConfectDirectory\";\nimport { ConvexDirectory } from \"../services/ConvexDirectory\";\nimport { ProjectRoot } from \"../services/ProjectRoot\";\nimport {\n generateAuthConfig,\n generateConvexConfig,\n generateCrons,\n generateHttp,\n removeGroups,\n writeGroups,\n} from \"../utils\";\nimport {\n codegenHandler,\n generateNodeApi,\n generateNodeRegisteredFunctions,\n} from \"./codegen\";\n\ntype Pending = {\n readonly specDirty: boolean;\n readonly nodeImplDirty: boolean;\n readonly httpDirty: boolean;\n readonly appDirty: boolean;\n readonly cronsDirty: boolean;\n readonly authDirty: boolean;\n};\n\nconst pendingInit: Pending = {\n specDirty: false,\n nodeImplDirty: false,\n httpDirty: false,\n appDirty: false,\n cronsDirty: false,\n authDirty: false,\n};\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.yellow })),\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 logFunctionAddedIndented = (functionPath: FunctionPath.FunctionPath) =>\n Console.log(\n pipe(\n AnsiDoc.text(\" \"),\n AnsiDoc.cat(pipe(AnsiDoc.char(\"+\"), AnsiDoc.annotate(Ansi.green))),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(\n AnsiDoc.text(GroupPath.toString(functionPath.groupPath) + \".\"),\n AnsiDoc.annotate(Ansi.blackBright),\n ),\n pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.green)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nconst logFunctionRemovedIndented = (functionPath: FunctionPath.FunctionPath) =>\n Console.log(\n pipe(\n AnsiDoc.text(\" \"),\n AnsiDoc.cat(pipe(AnsiDoc.char(\"-\"), AnsiDoc.annotate(Ansi.red))),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(\n AnsiDoc.text(GroupPath.toString(functionPath.groupPath) + \".\"),\n AnsiDoc.annotate(Ansi.blackBright),\n ),\n pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.red)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nexport const dev = Command.make(\"dev\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n const initialFunctionPaths = yield* codegenHandler;\n\n const pendingRef = yield* Ref.make<Pending>(pendingInit);\n const signal = yield* Queue.sliding<void>(1);\n const specWatcherRestartQueue = yield* Queue.sliding<void>(1);\n\n yield* Effect.all(\n [\n specFileWatcher(signal, pendingRef, specWatcherRestartQueue),\n confectDirectoryWatcher(signal, pendingRef, specWatcherRestartQueue),\n syncLoop(signal, pendingRef, initialFunctionPaths),\n ],\n { concurrency: \"unbounded\" },\n );\n }),\n).pipe(Command.withDescription(\"Start the Confect development server\"));\n\nconst syncLoop = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n initialFunctionPaths: FunctionPaths.FunctionPaths,\n) =>\n Effect.gen(function* () {\n const functionPathsRef = yield* Ref.make(initialFunctionPaths);\n const initialSyncDone = yield* Deferred.make<void>();\n\n return yield* Effect.forever(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Running sync loop...\");\n yield* Queue.take(signal);\n\n const isDone = yield* Deferred.isDone(initialSyncDone);\n yield* Effect.when(\n logPending(\"Dependencies changed, reloading…\"),\n () => isDone,\n );\n yield* Deferred.succeed(initialSyncDone, undefined);\n\n const pending = yield* Ref.getAndSet(pendingRef, pendingInit);\n\n if (pending.specDirty || pending.nodeImplDirty) {\n yield* generateNodeApi;\n yield* generateNodeRegisteredFunctions;\n }\n\n const specResult: Option.Option<void> = yield* Effect.if(\n pending.specDirty,\n {\n onTrue: () =>\n loadSpec.pipe(\n Effect.andThen(\n Effect.fn(function* (spec) {\n yield* Effect.logDebug(\"Spec loaded\");\n\n const previous = yield* Ref.get(functionPathsRef);\n\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const current = FunctionPaths.make(spec);\n const {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n } = FunctionPaths.diff(previous, current);\n\n // Removed groups\n yield* removeGroups(groupsRemoved);\n yield* Effect.forEach(groupsRemoved, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath =\n yield* GroupPath.modulePath(gp);\n const filePath = path.join(\n convexDirectory,\n relativeModulePath,\n );\n yield* logFileChangeIndented(\"Removed\", filePath);\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemovedIndented,\n );\n }),\n );\n\n // Added groups\n yield* writeGroups(spec, groupsAdded);\n yield* Effect.forEach(groupsAdded, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath =\n yield* GroupPath.modulePath(gp);\n const filePath = path.join(\n convexDirectory,\n relativeModulePath,\n );\n yield* logFileChangeIndented(\"Added\", filePath);\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAddedIndented,\n );\n }),\n );\n\n // Changed groups\n yield* writeGroups(spec, groupsChanged);\n yield* Effect.forEach(groupsChanged, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath =\n yield* GroupPath.modulePath(gp);\n const filePath = path.join(\n convexDirectory,\n relativeModulePath,\n );\n yield* logFileChangeIndented(\"Modified\", filePath);\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAddedIndented,\n );\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemovedIndented,\n );\n }),\n );\n\n yield* Ref.set(functionPathsRef, current);\n\n return Option.some(undefined);\n }),\n ),\n Effect.catchTag(\"SpecImportFailedError\", () =>\n logFailure(\"Spec import failed\").pipe(\n Effect.as(Option.none()),\n ),\n ),\n Effect.catchTag(\"SpecFileDoesNotExportSpecError\", () =>\n logFailure(\n \"Spec file does not default export a Convex spec\",\n ).pipe(Effect.as(Option.none())),\n ),\n Effect.catchTag(\"NodeSpecFileDoesNotExportSpecError\", () =>\n logFailure(\n \"Node spec file does not default export a Node spec\",\n ).pipe(Effect.as(Option.none())),\n ),\n ),\n onFalse: () => Effect.succeed(Option.some(undefined)),\n },\n );\n\n const dirtyOptionalFiles = [\n ...(pending.httpDirty\n ? [syncOptionalFile(generateHttp, \"http.ts\")]\n : []),\n ...(pending.appDirty\n ? [syncOptionalFile(generateConvexConfig, \"convex.config.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* Option.match(specResult, {\n onSome: () => logSuccess(\"Generated files are up-to-date\"),\n onNone: () => Effect.void,\n });\n }),\n );\n });\n\nconst loadSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specPathUrl = yield* path.toFileUrl(yield* getSpecPath);\n const specModule = yield* Effect.tryPromise({\n try: () => tsx.tsImport(specPathUrl.href, import.meta.url),\n catch: (error) => new SpecImportFailedError({ error }),\n });\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* new SpecFileDoesNotExportSpecError();\n }\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecOption = yield* loadNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),\n });\n\n return mergedSpec;\n});\n\nconst getSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n return path.join(confectDirectory, \"spec.ts\");\n});\n\nconst getNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n return path.join(confectDirectory, \"nodeSpec.ts\");\n});\n\nconst loadNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const nodeSpecPath = yield* getNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none();\n }\n\n const nodeSpecPathUrl = yield* path.toFileUrl(nodeSpecPath);\n const nodeSpecModule = yield* Effect.tryPromise({\n try: () => tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),\n catch: (error) => new SpecImportFailedError({ error }),\n });\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* new NodeSpecFileDoesNotExportSpecError();\n }\n\n return Option.some(nodeSpec);\n});\n\nconst esbuildOptions = (entryPoint: string) => ({\n entryPoints: [entryPoint],\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 external: [\"@confect/core\", \"@confect/server\", \"effect\", \"@effect/*\"],\n plugins: [\n {\n name: \"notify-rebuild\",\n setup(build: esbuild.PluginBuild) {\n build.onEnd((result) => {\n if (result.errors.length === 0) {\n (build as { _emit?: (v: void) => void })._emit?.();\n } else {\n Effect.runPromise(\n Effect.gen(function* () {\n const formattedMessages = yield* Effect.promise(() =>\n esbuild.formatMessages(result.errors, {\n kind: \"error\",\n color: true,\n terminalWidth: 80,\n }),\n );\n const output = formatBuildErrors(\n result.errors,\n formattedMessages,\n );\n yield* Console.error(\"\\n\" + output + \"\\n\");\n yield* logFailure(\"Build errors found\");\n }),\n );\n }\n });\n },\n },\n ],\n});\n\nconst createSpecWatcher = (entryPoint: string) =>\n Stream.asyncPush<void>(\n (emit) =>\n Effect.acquireRelease(\n Effect.promise(async () => {\n const opts = esbuildOptions(entryPoint);\n const plugin = opts.plugins[0];\n const originalSetup = plugin!.setup!;\n (plugin as { setup: (build: esbuild.PluginBuild) => void }).setup = (\n build,\n ) => {\n (build as { _emit?: (v: void) => void })._emit = () =>\n emit.single();\n return originalSetup(build);\n };\n\n const ctx = await esbuild.context({\n ...opts,\n plugins: [plugin],\n });\n\n await ctx.watch();\n return ctx;\n }),\n (ctx) =>\n Effect.promise(() => ctx.dispose()).pipe(\n Effect.tap(() => Effect.logDebug(\"esbuild watcher disposed\")),\n ),\n ),\n { bufferSize: 1, strategy: \"sliding\" },\n );\n\ntype SpecWatcherEvent = \"change\" | \"restart\";\n\nconst specFileWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n specWatcherRestartQueue: Queue.Queue<void>,\n) =>\n Effect.forever(\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getSpecPath;\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n\n const specWatcher = createSpecWatcher(specPath);\n const nodeSpecWatcher = nodeSpecExists\n ? createSpecWatcher(nodeSpecPath)\n : Stream.empty;\n\n const specChanges = pipe(\n Stream.merge(specWatcher, nodeSpecWatcher),\n Stream.map((): SpecWatcherEvent => \"change\"),\n );\n const restartStream = pipe(\n Stream.fromQueue(specWatcherRestartQueue),\n Stream.map((): SpecWatcherEvent => \"restart\"),\n );\n\n yield* pipe(\n Stream.merge(specChanges, restartStream),\n Stream.debounce(Duration.millis(200)),\n Stream.takeUntil((event): event is \"restart\" => event === \"restart\"),\n Stream.runForEach((event) =>\n event === \"change\"\n ? Ref.update(pendingRef, (pending) => ({\n ...pending,\n specDirty: true,\n })).pipe(Effect.andThen(Queue.offer(signal, undefined)))\n : Effect.void,\n ),\n );\n }),\n );\n\nconst formatBuildError = (\n error: esbuild.Message | undefined,\n formattedMessage: string,\n): string => {\n const lines = String.split(formattedMessage, \"\\n\");\n const redErrorText = pipe(\n AnsiDoc.text(error?.text ?? \"\"),\n AnsiDoc.annotate(Ansi.red),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n const replaced = pipe(\n Array.findFirstIndex(lines, (l) => pipe(l, String.trim, String.isNonEmpty)),\n Option.match({\n onNone: () => lines,\n onSome: (index) => Array.modify(lines, index, () => redErrorText),\n }),\n );\n return pipe(replaced, Array.join(\"\\n\"));\n};\n\nconst formatBuildErrors = (\n errors: readonly esbuild.Message[],\n formattedMessages: readonly string[],\n): string =>\n pipe(\n formattedMessages,\n Array.map((message, i) => formatBuildError(errors[i], message)),\n Array.join(\"\"),\n String.trimEnd,\n );\n\nexport class SpecFileDoesNotExportSpecError extends Schema.TaggedError<SpecFileDoesNotExportSpecError>()(\n \"SpecFileDoesNotExportSpecError\",\n {},\n) {}\n\nexport class NodeSpecFileDoesNotExportSpecError extends Schema.TaggedError<NodeSpecFileDoesNotExportSpecError>()(\n \"NodeSpecFileDoesNotExportSpecError\",\n {},\n) {}\n\nexport class SpecImportFailedError extends Schema.TaggedError<SpecImportFailedError>()(\n \"SpecImportFailedError\",\n {\n error: Schema.Unknown,\n },\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\nconst optionalConfectFiles: ReadonlyRecord<string, keyof Pending> = {\n \"http.ts\": \"httpDirty\",\n \"app.ts\": \"appDirty\",\n \"crons.ts\": \"cronsDirty\",\n \"auth.ts\": \"authDirty\",\n \"nodeSpec.ts\": \"specDirty\",\n \"nodeImpl.ts\": \"nodeImplDirty\",\n};\n\nconst confectDirectoryWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n specWatcherRestartQueue: 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),\n Stream.runForEach((event) => {\n const basename = path.basename(event.path);\n const pendingKey = optionalConfectFiles[basename];\n\n if (pendingKey !== undefined) {\n return pipe(\n pendingRef,\n Ref.update((pending) => {\n const next = { ...pending, [pendingKey]: true };\n if (basename === \"nodeImpl.ts\") {\n return { ...next, specDirty: true };\n }\n return next;\n }),\n Effect.andThen(Queue.offer(signal, undefined)),\n Effect.andThen(\n basename === \"nodeSpec.ts\"\n ? Queue.offer(specWatcherRestartQueue, undefined)\n : Effect.void,\n ),\n );\n }\n return Effect.void;\n }),\n );\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dev.mjs","names":["GroupPath.toString","FunctionPaths.make","FunctionPaths.diff","GroupPath.modulePath"],"sources":["../../src/confect/dev.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport {\n Array,\n Console,\n Deferred,\n Duration,\n Effect,\n Equal,\n HashSet,\n Match,\n Option,\n pipe,\n Queue,\n Ref,\n Schema,\n Stream,\n String,\n} from \"effect\";\nimport type { ReadonlyRecord } from \"effect/Record\";\nimport * as esbuild from \"esbuild\";\nimport type * as FunctionPath from \"../FunctionPath\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport * as GroupPath from \"../GroupPath\";\nimport { logFailure, logPending, logSuccess } from \"../log\";\nimport { ConfectDirectory } from \"../services/ConfectDirectory\";\nimport { ConvexDirectory } from \"../services/ConvexDirectory\";\nimport { ProjectRoot } from \"../services/ProjectRoot\";\nimport {\n bundleAndImport,\n EXTERNAL_PACKAGES,\n generateAuthConfig,\n generateConvexConfig,\n generateCrons,\n generateHttp,\n removeGroups,\n writeGroups,\n} from \"../utils\";\nimport {\n codegenHandler,\n generateNodeApi,\n generateNodeRegisteredFunctions,\n} from \"./codegen\";\n\ntype Pending = {\n readonly specDirty: boolean;\n readonly nodeImplDirty: boolean;\n readonly httpDirty: boolean;\n readonly appDirty: boolean;\n readonly cronsDirty: boolean;\n readonly authDirty: boolean;\n};\n\nconst pendingInit: Pending = {\n specDirty: false,\n nodeImplDirty: false,\n httpDirty: false,\n appDirty: false,\n cronsDirty: false,\n authDirty: false,\n};\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.yellow })),\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 logFunctionAddedIndented = (functionPath: FunctionPath.FunctionPath) =>\n Console.log(\n pipe(\n AnsiDoc.text(\" \"),\n AnsiDoc.cat(pipe(AnsiDoc.char(\"+\"), AnsiDoc.annotate(Ansi.green))),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(\n AnsiDoc.text(GroupPath.toString(functionPath.groupPath) + \".\"),\n AnsiDoc.annotate(Ansi.blackBright),\n ),\n pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.green)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nconst logFunctionRemovedIndented = (functionPath: FunctionPath.FunctionPath) =>\n Console.log(\n pipe(\n AnsiDoc.text(\" \"),\n AnsiDoc.cat(pipe(AnsiDoc.char(\"-\"), AnsiDoc.annotate(Ansi.red))),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(\n AnsiDoc.text(GroupPath.toString(functionPath.groupPath) + \".\"),\n AnsiDoc.annotate(Ansi.blackBright),\n ),\n pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.red)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nexport const dev = Command.make(\"dev\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n const initialFunctionPaths = yield* codegenHandler;\n\n const pendingRef = yield* Ref.make<Pending>(pendingInit);\n const signal = yield* Queue.sliding<void>(1);\n const specWatcherRestartQueue = yield* Queue.sliding<void>(1);\n\n yield* Effect.all(\n [\n specFileWatcher(signal, pendingRef, specWatcherRestartQueue),\n confectDirectoryWatcher(signal, pendingRef, specWatcherRestartQueue),\n syncLoop(signal, pendingRef, initialFunctionPaths),\n ],\n { concurrency: \"unbounded\" },\n );\n }),\n).pipe(Command.withDescription(\"Start the Confect development server\"));\n\nconst syncLoop = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n initialFunctionPaths: FunctionPaths.FunctionPaths,\n) =>\n Effect.gen(function* () {\n const functionPathsRef = yield* Ref.make(initialFunctionPaths);\n const initialSyncDone = yield* Deferred.make<void>();\n\n return yield* Effect.forever(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Running sync loop...\");\n yield* Queue.take(signal);\n\n const isDone = yield* Deferred.isDone(initialSyncDone);\n yield* Effect.when(\n logPending(\"Dependencies changed, reloading…\"),\n () => isDone,\n );\n yield* Deferred.succeed(initialSyncDone, undefined);\n\n const pending = yield* Ref.getAndSet(pendingRef, pendingInit);\n\n if (pending.specDirty || pending.nodeImplDirty) {\n yield* generateNodeApi;\n yield* generateNodeRegisteredFunctions;\n }\n\n const specResult: Option.Option<void> = yield* Effect.if(\n pending.specDirty,\n {\n onTrue: () =>\n loadSpec.pipe(\n Effect.andThen(\n Effect.fn(function* (spec) {\n yield* Effect.logDebug(\"Spec loaded\");\n\n const previous = yield* Ref.get(functionPathsRef);\n\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const current = FunctionPaths.make(spec);\n const {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n } = FunctionPaths.diff(previous, current);\n\n // Removed groups\n yield* removeGroups(groupsRemoved);\n yield* Effect.forEach(groupsRemoved, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath =\n yield* GroupPath.modulePath(gp);\n const filePath = path.join(\n convexDirectory,\n relativeModulePath,\n );\n yield* logFileChangeIndented(\"Removed\", filePath);\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemovedIndented,\n );\n }),\n );\n\n // Added groups\n yield* writeGroups(spec, groupsAdded);\n yield* Effect.forEach(groupsAdded, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath =\n yield* GroupPath.modulePath(gp);\n const filePath = path.join(\n convexDirectory,\n relativeModulePath,\n );\n yield* logFileChangeIndented(\"Added\", filePath);\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAddedIndented,\n );\n }),\n );\n\n // Changed groups\n yield* writeGroups(spec, groupsChanged);\n yield* Effect.forEach(groupsChanged, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath =\n yield* GroupPath.modulePath(gp);\n const filePath = path.join(\n convexDirectory,\n relativeModulePath,\n );\n yield* logFileChangeIndented(\"Modified\", filePath);\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAddedIndented,\n );\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemovedIndented,\n );\n }),\n );\n\n yield* Ref.set(functionPathsRef, current);\n\n return Option.some(undefined);\n }),\n ),\n Effect.catchTag(\"SpecImportFailedError\", () =>\n logFailure(\"Spec import failed\").pipe(\n Effect.as(Option.none()),\n ),\n ),\n Effect.catchTag(\"SpecFileDoesNotExportSpecError\", () =>\n logFailure(\n \"Spec file does not default export a Convex spec\",\n ).pipe(Effect.as(Option.none())),\n ),\n Effect.catchTag(\"NodeSpecFileDoesNotExportSpecError\", () =>\n logFailure(\n \"Node spec file does not default export a Node spec\",\n ).pipe(Effect.as(Option.none())),\n ),\n ),\n onFalse: () => Effect.succeed(Option.some(undefined)),\n },\n );\n\n const dirtyOptionalFiles = [\n ...(pending.httpDirty\n ? [syncOptionalFile(generateHttp, \"http.ts\")]\n : []),\n ...(pending.appDirty\n ? [syncOptionalFile(generateConvexConfig, \"convex.config.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* Option.match(specResult, {\n onSome: () => logSuccess(\"Generated files are up-to-date\"),\n onNone: () => Effect.void,\n });\n }),\n );\n });\n\nconst loadSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specPath = yield* getSpecPath;\n const specModule = yield* bundleAndImport(specPath).pipe(\n Effect.mapError((error) => new SpecImportFailedError({ error })),\n );\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* new SpecFileDoesNotExportSpecError();\n }\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecOption = yield* loadNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),\n });\n\n return mergedSpec;\n});\n\nconst getSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n return path.join(confectDirectory, \"spec.ts\");\n});\n\nconst getNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n return path.join(confectDirectory, \"nodeSpec.ts\");\n});\n\nconst loadNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none();\n }\n\n const nodeSpecModule = yield* bundleAndImport(nodeSpecPath).pipe(\n Effect.mapError((error) => new SpecImportFailedError({ error })),\n );\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* new NodeSpecFileDoesNotExportSpecError();\n }\n\n return Option.some(nodeSpec);\n});\n\nconst esbuildOptions = (entryPoint: string) => ({\n entryPoints: [entryPoint],\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 external: EXTERNAL_PACKAGES,\n plugins: [\n {\n name: \"notify-rebuild\",\n setup(build: esbuild.PluginBuild) {\n build.onEnd((result) => {\n if (result.errors.length === 0) {\n (build as { _emit?: (v: void) => void })._emit?.();\n } else {\n Effect.runPromise(\n Effect.gen(function* () {\n const formattedMessages = yield* Effect.promise(() =>\n esbuild.formatMessages(result.errors, {\n kind: \"error\",\n color: true,\n terminalWidth: 80,\n }),\n );\n const output = formatBuildErrors(\n result.errors,\n formattedMessages,\n );\n yield* Console.error(\"\\n\" + output + \"\\n\");\n yield* logFailure(\"Build errors found\");\n }),\n );\n }\n });\n },\n },\n ],\n});\n\nconst createSpecWatcher = (entryPoint: string) =>\n Stream.asyncPush<void>(\n (emit) =>\n Effect.acquireRelease(\n Effect.promise(async () => {\n const opts = esbuildOptions(entryPoint);\n const plugin = opts.plugins[0];\n const originalSetup = plugin!.setup!;\n (plugin as { setup: (build: esbuild.PluginBuild) => void }).setup = (\n build,\n ) => {\n (build as { _emit?: (v: void) => void })._emit = () =>\n emit.single();\n return originalSetup(build);\n };\n\n const ctx = await esbuild.context({\n ...opts,\n plugins: [plugin],\n });\n\n await ctx.watch();\n return ctx;\n }),\n (ctx) =>\n Effect.promise(() => ctx.dispose()).pipe(\n Effect.tap(() => Effect.logDebug(\"esbuild watcher disposed\")),\n ),\n ),\n { bufferSize: 1, strategy: \"sliding\" },\n );\n\ntype SpecWatcherEvent = \"change\" | \"restart\";\n\nconst specFileWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n specWatcherRestartQueue: Queue.Queue<void>,\n) =>\n Effect.forever(\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getSpecPath;\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n\n const specWatcher = createSpecWatcher(specPath);\n const nodeSpecWatcher = nodeSpecExists\n ? createSpecWatcher(nodeSpecPath)\n : Stream.empty;\n\n const specChanges = pipe(\n Stream.merge(specWatcher, nodeSpecWatcher),\n Stream.map((): SpecWatcherEvent => \"change\"),\n );\n const restartStream = pipe(\n Stream.fromQueue(specWatcherRestartQueue),\n Stream.map((): SpecWatcherEvent => \"restart\"),\n );\n\n yield* pipe(\n Stream.merge(specChanges, restartStream),\n Stream.debounce(Duration.millis(200)),\n Stream.takeUntil((event): event is \"restart\" => event === \"restart\"),\n Stream.runForEach((event) =>\n event === \"change\"\n ? Ref.update(pendingRef, (pending) => ({\n ...pending,\n specDirty: true,\n })).pipe(Effect.andThen(Queue.offer(signal, undefined)))\n : Effect.void,\n ),\n );\n }),\n );\n\nconst formatBuildError = (\n error: esbuild.Message | undefined,\n formattedMessage: string,\n): string => {\n const lines = String.split(formattedMessage, \"\\n\");\n const redErrorText = pipe(\n AnsiDoc.text(error?.text ?? \"\"),\n AnsiDoc.annotate(Ansi.red),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n const replaced = pipe(\n Array.findFirstIndex(lines, (l) => pipe(l, String.trim, String.isNonEmpty)),\n Option.match({\n onNone: () => lines,\n onSome: (index) => Array.modify(lines, index, () => redErrorText),\n }),\n );\n return pipe(replaced, Array.join(\"\\n\"));\n};\n\nconst formatBuildErrors = (\n errors: readonly esbuild.Message[],\n formattedMessages: readonly string[],\n): string =>\n pipe(\n formattedMessages,\n Array.map((message, i) => formatBuildError(errors[i], message)),\n Array.join(\"\"),\n String.trimEnd,\n );\n\nexport class SpecFileDoesNotExportSpecError extends Schema.TaggedError<SpecFileDoesNotExportSpecError>()(\n \"SpecFileDoesNotExportSpecError\",\n {},\n) {}\n\nexport class NodeSpecFileDoesNotExportSpecError extends Schema.TaggedError<NodeSpecFileDoesNotExportSpecError>()(\n \"NodeSpecFileDoesNotExportSpecError\",\n {},\n) {}\n\nexport class SpecImportFailedError extends Schema.TaggedError<SpecImportFailedError>()(\n \"SpecImportFailedError\",\n {\n error: Schema.Unknown,\n },\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\nconst optionalConfectFiles: ReadonlyRecord<string, keyof Pending> = {\n \"http.ts\": \"httpDirty\",\n \"app.ts\": \"appDirty\",\n \"crons.ts\": \"cronsDirty\",\n \"auth.ts\": \"authDirty\",\n \"nodeSpec.ts\": \"specDirty\",\n \"nodeImpl.ts\": \"nodeImplDirty\",\n};\n\nconst confectDirectoryWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n specWatcherRestartQueue: 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),\n Stream.runForEach((event) => {\n const basename = path.basename(event.path);\n const pendingKey = optionalConfectFiles[basename];\n\n if (pendingKey !== undefined) {\n return pipe(\n pendingRef,\n Ref.update((pending) => {\n const next = { ...pending, [pendingKey]: true };\n if (basename === \"nodeImpl.ts\") {\n return { ...next, specDirty: true };\n }\n return next;\n }),\n Effect.andThen(Queue.offer(signal, undefined)),\n Effect.andThen(\n basename === \"nodeSpec.ts\"\n ? Queue.offer(specWatcherRestartQueue, undefined)\n : Effect.void,\n ),\n );\n }\n return Effect.void;\n }),\n );\n });\n"],"mappings":"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"}
|
package/dist/package.mjs
CHANGED
package/dist/utils.mjs
CHANGED
|
@@ -7,12 +7,54 @@ import { GroupPaths } from "./GroupPaths.mjs";
|
|
|
7
7
|
import { groupPaths, make } from "./FunctionPaths.mjs";
|
|
8
8
|
import { Array, Effect, HashSet, Option, Order, Record, String, pipe } from "effect";
|
|
9
9
|
import { FileSystem, Path } from "@effect/platform";
|
|
10
|
+
import * as esbuild from "esbuild";
|
|
10
11
|
|
|
11
12
|
//#region src/utils.ts
|
|
12
13
|
const removePathExtension = (pathStr) => Effect.gen(function* () {
|
|
13
14
|
const path = yield* Path.Path;
|
|
14
15
|
return String.slice(0, -path.extname(pathStr).length)(pathStr);
|
|
15
16
|
});
|
|
17
|
+
const EXTERNAL_PACKAGES = [
|
|
18
|
+
"@confect/core",
|
|
19
|
+
"@confect/server",
|
|
20
|
+
"effect",
|
|
21
|
+
"@effect/*"
|
|
22
|
+
];
|
|
23
|
+
const isExternalImport = (path) => EXTERNAL_PACKAGES.some((p) => {
|
|
24
|
+
if (p.endsWith("/*")) return path.startsWith(p.slice(0, -1));
|
|
25
|
+
return path === p || path.startsWith(p + "/");
|
|
26
|
+
});
|
|
27
|
+
const absoluteExternalsPlugin = {
|
|
28
|
+
name: "absolute-externals",
|
|
29
|
+
setup(build) {
|
|
30
|
+
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
31
|
+
if (args.kind !== "import-statement" && args.kind !== "dynamic-import") return;
|
|
32
|
+
if (!isExternalImport(args.path)) return;
|
|
33
|
+
return {
|
|
34
|
+
path: import.meta.resolve(args.path, "file://" + args.resolveDir + "/"),
|
|
35
|
+
external: true
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Bundle a TypeScript entry point with esbuild and import the result via a
|
|
42
|
+
* data URL. This handles extensionless `.ts` imports regardless of whether the
|
|
43
|
+
* user's project sets `"type": "module"` in package.json.
|
|
44
|
+
*/
|
|
45
|
+
const bundleAndImport = (entryPoint) => Effect.gen(function* () {
|
|
46
|
+
const code = (yield* Effect.promise(() => esbuild.build({
|
|
47
|
+
entryPoints: [entryPoint],
|
|
48
|
+
bundle: true,
|
|
49
|
+
write: false,
|
|
50
|
+
platform: "node",
|
|
51
|
+
format: "esm",
|
|
52
|
+
logLevel: "silent",
|
|
53
|
+
plugins: [absoluteExternalsPlugin]
|
|
54
|
+
}))).outputFiles[0].text;
|
|
55
|
+
const dataUrl = "data:text/javascript;base64," + Buffer.from(code).toString("base64");
|
|
56
|
+
return yield* Effect.promise(() => import(dataUrl));
|
|
57
|
+
});
|
|
16
58
|
const writeFileStringAndLog = (filePath, contents) => Effect.gen(function* () {
|
|
17
59
|
const fs = yield* FileSystem.FileSystem;
|
|
18
60
|
if (!(yield* fs.exists(filePath))) {
|
|
@@ -164,5 +206,5 @@ const generateCrons = generateOptionalFile("crons.ts", "crons.ts", (importPath)
|
|
|
164
206
|
const generateAuthConfig = generateOptionalFile("auth.ts", "auth.config.ts", (importPath) => authConfig({ authImportPath: importPath }));
|
|
165
207
|
|
|
166
208
|
//#endregion
|
|
167
|
-
export { generateAuthConfig, generateConvexConfig, generateCrons, generateFunctions, generateHttp, removeGroups, removePathExtension, writeFileStringAndLog, writeGroups };
|
|
209
|
+
export { EXTERNAL_PACKAGES, bundleAndImport, generateAuthConfig, generateConvexConfig, generateCrons, generateFunctions, generateHttp, removeGroups, removePathExtension, writeFileStringAndLog, writeGroups };
|
|
168
210
|
//# sourceMappingURL=utils.mjs.map
|
package/dist/utils.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":["GroupPath.modulePath","modulePath","templates.functions","FunctionPaths.make","FunctionPaths.groupPaths","GroupPath.getGroupSpec","GroupPath.fromGroupModulePath","templates.http","templates.convexConfig","templates.crons","templates.authConfig"],"sources":["../src/utils.ts"],"sourcesContent":["import type { FunctionSpec, Spec } from \"@confect/core\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport type { PlatformError } from \"@effect/platform/Error\";\nimport {\n Array,\n Effect,\n HashSet,\n Option,\n Order,\n pipe,\n Record,\n String,\n} from \"effect\";\nimport * as FunctionPaths from \"./FunctionPaths\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log\";\nimport { ConfectDirectory } from \"./services/ConfectDirectory\";\nimport { ConvexDirectory } from \"./services/ConvexDirectory\";\nimport * as templates from \"./templates\";\n\nexport const removePathExtension = (pathStr: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return String.slice(0, -path.extname(pathStr).length)(pathStr);\n });\n\nexport const writeFileStringAndLog = (filePath: string, contents: string) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(filePath))) {\n yield* fs.writeFileString(filePath, contents);\n yield* logFileAdded(filePath);\n return;\n }\n const existing = yield* fs.readFileString(filePath);\n if (existing !== contents) {\n yield* fs.writeFileString(filePath, contents);\n yield* logFileModified(filePath);\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 Option.getOrElse(projectRoot, () => startDir);\n});\n\nexport type WriteChange = \"Added\" | \"Modified\" | \"Unchanged\";\n\nexport const writeFileString = (\n filePath: string,\n contents: string,\n): Effect.Effect<WriteChange, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n if (!(yield* fs.exists(filePath))) {\n yield* fs.writeFileString(filePath, contents);\n return \"Added\";\n }\n const existing = yield* fs.readFileString(filePath);\n if (existing !== contents) {\n yield* fs.writeFileString(filePath, contents);\n return \"Modified\";\n }\n return \"Unchanged\";\n });\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: string[];\n}) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const isNodeGroup = groupPath.pathSegments[0] === \"node\";\n const registeredFunctionsFileName = isNodeGroup\n ? \"nodeRegisteredFunctions.ts\"\n : \"registeredFunctions.ts\";\n const registeredFunctionsPath = path.join(\n confectDirectory,\n \"_generated\",\n registeredFunctionsFileName,\n );\n const registeredFunctionsImportPath = yield* removePathExtension(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n const registeredFunctionsVariableName = isNodeGroup\n ? \"nodeRegisteredFunctions\"\n : \"registeredFunctions\";\n\n const functionsContentsString = yield* templates.functions({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n registeredFunctionsVariableName,\n useNode: isNodeGroup,\n ...(isNodeGroup\n ? {\n registeredFunctionsLookupPath: groupPath.pathSegments.slice(1),\n }\n : {}),\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n });\n\nconst logGroupPaths = <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(groupPaths, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n });\n\nexport const generateFunctions = (spec: Spec.AnyWithProps) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n const functionPaths = FunctionPaths.make(spec);\n const groupPathsFromSpec = FunctionPaths.groupPaths(functionPaths);\n\n const overlappingGroupPaths = GroupPaths.GroupPaths.make(\n HashSet.intersection(groupPathsFromFs, groupPathsFromSpec),\n );\n yield* Effect.forEach(overlappingGroupPaths, (groupPath) =>\n Effect.gen(function* () {\n const group = yield* GroupPath.getGroupSpec(spec, groupPath);\n const functionNames = pipe(\n group.functions,\n Record.values,\n Array.sortBy(\n Order.mapInput(\n Order.string,\n (fn: FunctionSpec.AnyWithProps) => fn.name,\n ),\n ),\n Array.map((fn) => fn.name),\n );\n const result = yield* generateGroupModule({ groupPath, functionNames });\n if (result === \"Modified\") {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n yield* logFileModified(\n path.join(convexDirectory, relativeModulePath),\n );\n }\n }),\n );\n\n const extinctGroupPaths = GroupPaths.GroupPaths.make(\n HashSet.difference(groupPathsFromFs, groupPathsFromSpec),\n );\n yield* removeGroups(extinctGroupPaths);\n yield* logGroupPaths(extinctGroupPaths, logFileRemoved);\n\n const newGroupPaths = GroupPaths.GroupPaths.make(\n HashSet.difference(groupPathsFromSpec, groupPathsFromFs),\n );\n yield* writeGroups(spec, newGroupPaths);\n yield* logGroupPaths(newGroupPaths, logFileAdded);\n\n return functionPaths;\n });\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n ]);\n\n const allConvexPaths = yield* fs.readDirectory(convexDirectory, {\n recursive: true,\n });\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) &&\n path.basename(path.dirname(convexPath)) !== \"_generated\",\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return pipe(groupPathArray, HashSet.fromIterable, GroupPaths.GroupPaths.make);\n});\n\nexport const removeGroups = (groupPaths: GroupPaths.GroupPaths) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* fs.remove(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n });\n\nexport const writeGroups = (\n spec: Spec.AnyWithProps,\n groupPaths: GroupPaths.GroupPaths,\n) =>\n Effect.forEach(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const group = yield* GroupPath.getGroupSpec(spec, groupPath);\n\n const functionNames = pipe(\n group.functions,\n Record.values,\n Array.sortBy(\n Order.mapInput(\n Order.string,\n (fn: FunctionSpec.AnyWithProps) => fn.name,\n ),\n ),\n Array.map((fn) => fn.name),\n );\n\n yield* Effect.logDebug(`Generating group ${groupPath}...`);\n yield* generateGroupModule({\n groupPath,\n functionNames,\n });\n yield* Effect.logDebug(`Group ${groupPath} generated`);\n }),\n );\n\nconst generateOptionalFile = (\n confectFile: string,\n convexFile: string,\n generateContents: (importPath: string) => Effect.Effect<string>,\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 convexDirectory = yield* ConvexDirectory.get;\n\n const confectFilePath = path.join(confectDirectory, confectFile);\n\n if (!(yield* fs.exists(confectFilePath))) {\n return Option.none();\n }\n\n const convexFilePath = path.join(convexDirectory, convexFile);\n const relativeImportPath = path.relative(\n path.dirname(convexFilePath),\n confectFilePath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const contents = yield* generateContents(importPathWithoutExt);\n const change = yield* writeFileString(convexFilePath, contents);\n return Option.some({ change, convexFilePath });\n });\n\nexport const generateHttp = generateOptionalFile(\n \"http.ts\",\n \"http.ts\",\n (importPath) => templates.http({ httpImportPath: importPath }),\n);\n\nexport const generateConvexConfig = generateOptionalFile(\n \"app.ts\",\n \"convex.config.ts\",\n (importPath) => templates.convexConfig({ appImportPath: importPath }),\n);\n\nexport const generateCrons = generateOptionalFile(\n \"crons.ts\",\n \"crons.ts\",\n (importPath) => templates.crons({ cronsImportPath: importPath }),\n);\n\nexport const generateAuthConfig = generateOptionalFile(\n \"auth.ts\",\n \"auth.config.ts\",\n (importPath) => templates.authConfig({ authImportPath: importPath }),\n);\n"],"mappings":";;;;;;;;;;;AAqBA,MAAa,uBAAuB,YAClC,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;AAEzB,QAAO,OAAO,MAAM,GAAG,CAAC,KAAK,QAAQ,QAAQ,CAAC,OAAO,CAAC,QAAQ;EAC9D;AAEJ,MAAa,yBAAyB,UAAkB,aACtD,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;AAC7B,KAAI,EAAE,OAAO,GAAG,OAAO,SAAS,GAAG;AACjC,SAAO,GAAG,gBAAgB,UAAU,SAAS;AAC7C,SAAO,aAAa,SAAS;AAC7B;;AAGF,MADiB,OAAO,GAAG,eAAe,SAAS,MAClC,UAAU;AACzB,SAAO,GAAG,gBAAgB,UAAU,SAAS;AAC7C,SAAO,gBAAgB,SAAS;;EAElC;AAEJ,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,UAAU,mBAAmB,SAAS;EACpD;AAIF,MAAa,mBACX,UACA,aAEA,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;AAE7B,KAAI,EAAE,OAAO,GAAG,OAAO,SAAS,GAAG;AACjC,SAAO,GAAG,gBAAgB,UAAU,SAAS;AAC7C,SAAO;;AAGT,MADiB,OAAO,GAAG,eAAe,SAAS,MAClC,UAAU;AACzB,SAAO,GAAG,gBAAgB,UAAU,SAAS;AAC7C,SAAO;;AAET,QAAO;EACP;AAEJ,MAAa,uBAAuB,EAClC,WACA,oBAKA,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,gBAAgB;CAC/C,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,qBAAqB,OAAOA,WAAqB,UAAU;CACjE,MAAMC,eAAa,KAAK,KAAK,iBAAiB,mBAAmB;CAEjE,MAAM,gBAAgB,KAAK,QAAQA,aAAW;AAC9C,KAAI,EAAE,OAAO,GAAG,OAAO,cAAc,EACnC,QAAO,GAAG,cAAc,eAAe,EAAE,WAAW,MAAM,CAAC;CAG7D,MAAM,cAAc,UAAU,aAAa,OAAO;CAClD,MAAM,8BAA8B,cAChC,+BACA;CACJ,MAAM,0BAA0B,KAAK,KACnC,kBACA,cACA,4BACD;CACD,MAAM,gCAAgC,OAAO,oBAC3C,KAAK,SAAS,KAAK,QAAQA,aAAW,EAAE,wBAAwB,CACjE;CACD,MAAM,kCAAkC,cACpC,4BACA;CAEJ,MAAM,0BAA0B,OAAOC,UAAoB;EACzD;EACA;EACA;EACA;EACA,SAAS;EACT,GAAI,cACA,EACE,+BAA+B,UAAU,aAAa,MAAM,EAAE,EAC/D,GACD,EAAE;EACP,CAAC;AAEF,KAAI,EAAE,OAAO,GAAG,OAAOD,aAAW,GAAG;AACnC,SAAO,GAAG,gBAAgBA,cAAY,wBAAwB;AAC9D,SAAO;;AAGT,MADiB,OAAO,GAAG,eAAeA,aAAW,MACpC,yBAAyB;AACxC,SAAO,GAAG,gBAAgBA,cAAY,wBAAwB;AAC9D,SAAO;;AAET,QAAO;EACP;AAEJ,MAAM,iBACJ,YACA,UAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,gBAAgB;AAE/C,QAAO,OAAO,QAAQ,aAAa,OACjC,OAAO,IAAI,aAAa;EACtB,MAAM,qBAAqB,OAAOD,WAAqB,GAAG;AAC1D,SAAO,MAAM,KAAK,KAAK,iBAAiB,mBAAmB,CAAC;GAC5D,CACH;EACD;AAEJ,MAAa,qBAAqB,SAChC,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,gBAAgB;CAE/C,MAAM,mBAAmB,OAAO;CAChC,MAAM,gBAAgBG,KAAmB,KAAK;CAC9C,MAAM,qBAAqBC,WAAyB,cAAc;CAElE,MAAM,mCAA8C,KAClD,QAAQ,aAAa,kBAAkB,mBAAmB,CAC3D;AACD,QAAO,OAAO,QAAQ,wBAAwB,cAC5C,OAAO,IAAI,aAAa;AActB,OADe,OAAO,oBAAoB;GAAE;GAAW,eAXjC,MADR,OAAOC,aAAuB,MAAM,UAAU,EAEpD,WACN,OAAO,QACP,MAAM,OACJ,MAAM,SACJ,MAAM,SACL,OAAkC,GAAG,KACvC,CACF,EACD,MAAM,KAAK,OAAO,GAAG,KAAK,CAC3B;GACqE,CAAC,MACxD,YAAY;GACzB,MAAM,qBAAqB,OAAOL,WAAqB,UAAU;AACjE,UAAO,gBACL,KAAK,KAAK,iBAAiB,mBAAmB,CAC/C;;GAEH,CACH;CAED,MAAM,+BAA0C,KAC9C,QAAQ,WAAW,kBAAkB,mBAAmB,CACzD;AACD,QAAO,aAAa,kBAAkB;AACtC,QAAO,cAAc,mBAAmB,eAAe;CAEvD,MAAM,2BAAsC,KAC1C,QAAQ,WAAW,oBAAoB,iBAAiB,CACzD;AACD,QAAO,YAAY,MAAM,cAAc;AACvC,QAAO,cAAc,eAAe,aAAa;AAEjD,QAAO;EACP;AAEJ,MAAM,sBAAsB,OAAO,IAAI,aAAa;CAClD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,gBAAgB;CAE/C,MAAM,gCAAgC,IAAI,IAAI;EAC5C;EACA;EACA;EACA;EACA;EACD,CAAC;AAiBF,QAAO,KAZgB,OAAO,KAHP,OAAO,GAAG,cAAc,iBAAiB,EAC9D,WAAW,MACZ,CAAC,EAGA,MAAM,QACH,eACC,KAAK,QAAQ,WAAW,KAAK,SAC7B,CAAC,8BAA8B,IAAI,KAAK,SAAS,WAAW,CAAC,IAC7D,KAAK,SAAS,KAAK,QAAQ,WAAW,CAAC,KAAK,aAC/C,EACD,OAAO,SAAS,oBACdM,oBAA8B,gBAAgB,CAC/C,CACF,EAC2B,QAAQ,yBAAoC,KAAK;EAC7E;AAEF,MAAa,gBAAgB,eAC3B,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,kBAAkB,OAAO,gBAAgB;AAE/C,QAAO,OAAO,IACZ,QAAQ,IAAI,aAAa,cACvB,OAAO,IAAI,aAAa;EACtB,MAAM,qBAAqB,OAAON,WAAqB,UAAU;EACjE,MAAMC,eAAa,KAAK,KAAK,iBAAiB,mBAAmB;AAEjE,SAAO,OAAO,SAAS,mBAAmB,mBAAmB,MAAM;AAEnE,SAAO,GAAG,OAAOA,aAAW;AAC5B,SAAO,OAAO,SAAS,UAAU,mBAAmB,WAAW;GAC/D,CACH,EACD,EAAE,aAAa,aAAa,CAC7B;EACD;AAEJ,MAAa,eACX,MACA,eAEA,OAAO,QAAQ,aAAa,cAC1B,OAAO,IAAI,aAAa;CAGtB,MAAM,gBAAgB,MAFR,OAAOI,aAAuB,MAAM,UAAU,EAGpD,WACN,OAAO,QACP,MAAM,OACJ,MAAM,SACJ,MAAM,SACL,OAAkC,GAAG,KACvC,CACF,EACD,MAAM,KAAK,OAAO,GAAG,KAAK,CAC3B;AAED,QAAO,OAAO,SAAS,oBAAoB,UAAU,KAAK;AAC1D,QAAO,oBAAoB;EACzB;EACA;EACD,CAAC;AACF,QAAO,OAAO,SAAS,SAAS,UAAU,YAAY;EACtD,CACH;AAEH,MAAM,wBACJ,aACA,YACA,qBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,kBAAkB,OAAO,gBAAgB;CAE/C,MAAM,kBAAkB,KAAK,KAAK,kBAAkB,YAAY;AAEhE,KAAI,EAAE,OAAO,GAAG,OAAO,gBAAgB,EACrC,QAAO,OAAO,MAAM;CAGtB,MAAM,iBAAiB,KAAK,KAAK,iBAAiB,WAAW;CAO7D,MAAM,SAAS,OAAO,gBAAgB,gBADrB,OAAO,iBADK,OAAO,oBAJT,KAAK,SAC9B,KAAK,QAAQ,eAAe,EAC5B,gBACD,CAC0E,CACb,CACC;AAC/D,QAAO,OAAO,KAAK;EAAE;EAAQ;EAAgB,CAAC;EAC9C;AAEJ,MAAa,eAAe,qBAC1B,WACA,YACC,eAAeE,KAAe,EAAE,gBAAgB,YAAY,CAAC,CAC/D;AAED,MAAa,uBAAuB,qBAClC,UACA,qBACC,eAAeC,aAAuB,EAAE,eAAe,YAAY,CAAC,CACtE;AAED,MAAa,gBAAgB,qBAC3B,YACA,aACC,eAAeC,MAAgB,EAAE,iBAAiB,YAAY,CAAC,CACjE;AAED,MAAa,qBAAqB,qBAChC,WACA,mBACC,eAAeC,WAAqB,EAAE,gBAAgB,YAAY,CAAC,CACrE"}
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":["GroupPath.modulePath","modulePath","templates.functions","FunctionPaths.make","FunctionPaths.groupPaths","GroupPath.getGroupSpec","GroupPath.fromGroupModulePath","templates.http","templates.convexConfig","templates.crons","templates.authConfig"],"sources":["../src/utils.ts"],"sourcesContent":["import type { FunctionSpec, Spec } from \"@confect/core\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport type { PlatformError } from \"@effect/platform/Error\";\nimport {\n Array,\n Effect,\n HashSet,\n Option,\n Order,\n pipe,\n Record,\n String,\n} from \"effect\";\nimport * as esbuild from \"esbuild\";\nimport * as FunctionPaths from \"./FunctionPaths\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log\";\nimport { ConfectDirectory } from \"./services/ConfectDirectory\";\nimport { ConvexDirectory } from \"./services/ConvexDirectory\";\nimport * as templates from \"./templates\";\n\nexport const removePathExtension = (pathStr: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return String.slice(0, -path.extname(pathStr).length)(pathStr);\n });\n\nexport const EXTERNAL_PACKAGES = [\n \"@confect/core\",\n \"@confect/server\",\n \"effect\",\n \"@effect/*\",\n];\n\nconst isExternalImport = (path: string) =>\n EXTERNAL_PACKAGES.some((p) => {\n if (p.endsWith(\"/*\")) {\n return path.startsWith(p.slice(0, -1));\n }\n return path === p || path.startsWith(p + \"/\");\n });\n\nconst absoluteExternalsPlugin: esbuild.Plugin = {\n name: \"absolute-externals\",\n setup(build) {\n build.onResolve({ filter: /.*/ }, async (args) => {\n if (args.kind !== \"import-statement\" && args.kind !== \"dynamic-import\")\n return;\n if (!isExternalImport(args.path)) return;\n const resolved = import.meta.resolve(\n args.path,\n \"file://\" + args.resolveDir + \"/\",\n );\n return { path: resolved, external: true };\n });\n },\n};\n\n/**\n * Bundle a TypeScript entry point with esbuild and import the result via a\n * data URL. This handles extensionless `.ts` imports regardless of whether the\n * user's project sets `\"type\": \"module\"` in package.json.\n */\nexport const bundleAndImport = (entryPoint: string) =>\n Effect.gen(function* () {\n const result = yield* Effect.promise(() =>\n esbuild.build({\n entryPoints: [entryPoint],\n bundle: true,\n write: false,\n platform: \"node\",\n format: \"esm\",\n logLevel: \"silent\",\n plugins: [absoluteExternalsPlugin],\n }),\n );\n const code = result.outputFiles[0]!.text;\n const dataUrl =\n \"data:text/javascript;base64,\" + Buffer.from(code).toString(\"base64\");\n return yield* Effect.promise(() => import(dataUrl));\n });\n\nexport const writeFileStringAndLog = (filePath: string, contents: string) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(filePath))) {\n yield* fs.writeFileString(filePath, contents);\n yield* logFileAdded(filePath);\n return;\n }\n const existing = yield* fs.readFileString(filePath);\n if (existing !== contents) {\n yield* fs.writeFileString(filePath, contents);\n yield* logFileModified(filePath);\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 Option.getOrElse(projectRoot, () => startDir);\n});\n\nexport type WriteChange = \"Added\" | \"Modified\" | \"Unchanged\";\n\nexport const writeFileString = (\n filePath: string,\n contents: string,\n): Effect.Effect<WriteChange, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n if (!(yield* fs.exists(filePath))) {\n yield* fs.writeFileString(filePath, contents);\n return \"Added\";\n }\n const existing = yield* fs.readFileString(filePath);\n if (existing !== contents) {\n yield* fs.writeFileString(filePath, contents);\n return \"Modified\";\n }\n return \"Unchanged\";\n });\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: string[];\n}) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const isNodeGroup = groupPath.pathSegments[0] === \"node\";\n const registeredFunctionsFileName = isNodeGroup\n ? \"nodeRegisteredFunctions.ts\"\n : \"registeredFunctions.ts\";\n const registeredFunctionsPath = path.join(\n confectDirectory,\n \"_generated\",\n registeredFunctionsFileName,\n );\n const registeredFunctionsImportPath = yield* removePathExtension(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n const registeredFunctionsVariableName = isNodeGroup\n ? \"nodeRegisteredFunctions\"\n : \"registeredFunctions\";\n\n const functionsContentsString = yield* templates.functions({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n registeredFunctionsVariableName,\n useNode: isNodeGroup,\n ...(isNodeGroup\n ? {\n registeredFunctionsLookupPath: groupPath.pathSegments.slice(1),\n }\n : {}),\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n });\n\nconst logGroupPaths = <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(groupPaths, (gp) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n });\n\nexport const generateFunctions = (spec: Spec.AnyWithProps) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n const functionPaths = FunctionPaths.make(spec);\n const groupPathsFromSpec = FunctionPaths.groupPaths(functionPaths);\n\n const overlappingGroupPaths = GroupPaths.GroupPaths.make(\n HashSet.intersection(groupPathsFromFs, groupPathsFromSpec),\n );\n yield* Effect.forEach(overlappingGroupPaths, (groupPath) =>\n Effect.gen(function* () {\n const group = yield* GroupPath.getGroupSpec(spec, groupPath);\n const functionNames = pipe(\n group.functions,\n Record.values,\n Array.sortBy(\n Order.mapInput(\n Order.string,\n (fn: FunctionSpec.AnyWithProps) => fn.name,\n ),\n ),\n Array.map((fn) => fn.name),\n );\n const result = yield* generateGroupModule({ groupPath, functionNames });\n if (result === \"Modified\") {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n yield* logFileModified(\n path.join(convexDirectory, relativeModulePath),\n );\n }\n }),\n );\n\n const extinctGroupPaths = GroupPaths.GroupPaths.make(\n HashSet.difference(groupPathsFromFs, groupPathsFromSpec),\n );\n yield* removeGroups(extinctGroupPaths);\n yield* logGroupPaths(extinctGroupPaths, logFileRemoved);\n\n const newGroupPaths = GroupPaths.GroupPaths.make(\n HashSet.difference(groupPathsFromSpec, groupPathsFromFs),\n );\n yield* writeGroups(spec, newGroupPaths);\n yield* logGroupPaths(newGroupPaths, logFileAdded);\n\n return functionPaths;\n });\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n ]);\n\n const allConvexPaths = yield* fs.readDirectory(convexDirectory, {\n recursive: true,\n });\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) &&\n path.basename(path.dirname(convexPath)) !== \"_generated\",\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return pipe(groupPathArray, HashSet.fromIterable, GroupPaths.GroupPaths.make);\n});\n\nexport const removeGroups = (groupPaths: GroupPaths.GroupPaths) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* fs.remove(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n });\n\nexport const writeGroups = (\n spec: Spec.AnyWithProps,\n groupPaths: GroupPaths.GroupPaths,\n) =>\n Effect.forEach(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const group = yield* GroupPath.getGroupSpec(spec, groupPath);\n\n const functionNames = pipe(\n group.functions,\n Record.values,\n Array.sortBy(\n Order.mapInput(\n Order.string,\n (fn: FunctionSpec.AnyWithProps) => fn.name,\n ),\n ),\n Array.map((fn) => fn.name),\n );\n\n yield* Effect.logDebug(`Generating group ${groupPath}...`);\n yield* generateGroupModule({\n groupPath,\n functionNames,\n });\n yield* Effect.logDebug(`Group ${groupPath} generated`);\n }),\n );\n\nconst generateOptionalFile = (\n confectFile: string,\n convexFile: string,\n generateContents: (importPath: string) => Effect.Effect<string>,\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 convexDirectory = yield* ConvexDirectory.get;\n\n const confectFilePath = path.join(confectDirectory, confectFile);\n\n if (!(yield* fs.exists(confectFilePath))) {\n return Option.none();\n }\n\n const convexFilePath = path.join(convexDirectory, convexFile);\n const relativeImportPath = path.relative(\n path.dirname(convexFilePath),\n confectFilePath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const contents = yield* generateContents(importPathWithoutExt);\n const change = yield* writeFileString(convexFilePath, contents);\n return Option.some({ change, convexFilePath });\n });\n\nexport const generateHttp = generateOptionalFile(\n \"http.ts\",\n \"http.ts\",\n (importPath) => templates.http({ httpImportPath: importPath }),\n);\n\nexport const generateConvexConfig = generateOptionalFile(\n \"app.ts\",\n \"convex.config.ts\",\n (importPath) => templates.convexConfig({ appImportPath: importPath }),\n);\n\nexport const generateCrons = generateOptionalFile(\n \"crons.ts\",\n \"crons.ts\",\n (importPath) => templates.crons({ cronsImportPath: importPath }),\n);\n\nexport const generateAuthConfig = generateOptionalFile(\n \"auth.ts\",\n \"auth.config.ts\",\n (importPath) => templates.authConfig({ authImportPath: importPath }),\n);\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@confect/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Developer tooling for codegen and sync",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -44,8 +44,7 @@
|
|
|
44
44
|
"@effect/printer": "^0.47.0",
|
|
45
45
|
"@effect/printer-ansi": "^0.47.0",
|
|
46
46
|
"code-block-writer": "^13.0.3",
|
|
47
|
-
"esbuild": "^0.27.3"
|
|
48
|
-
"tsx": "^4.21.0"
|
|
47
|
+
"esbuild": "^0.27.3"
|
|
49
48
|
},
|
|
50
49
|
"devDependencies": {
|
|
51
50
|
"@effect/language-service": "0.73.1",
|
|
@@ -67,8 +66,8 @@
|
|
|
67
66
|
"peerDependencies": {
|
|
68
67
|
"@effect/platform": "^0.94.4",
|
|
69
68
|
"effect": "^3.19.16",
|
|
70
|
-
"@confect/core": "1.0.
|
|
71
|
-
"@confect/server": "1.0.
|
|
69
|
+
"@confect/core": "1.0.2",
|
|
70
|
+
"@confect/server": "1.0.2"
|
|
72
71
|
},
|
|
73
72
|
"engines": {
|
|
74
73
|
"node": ">=22",
|
package/src/confect/codegen.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { DatabaseSchema } from "@confect/server";
|
|
|
3
3
|
import { Command } from "@effect/cli";
|
|
4
4
|
import { FileSystem, Path } from "@effect/platform";
|
|
5
5
|
import { Effect, Match, Option } from "effect";
|
|
6
|
-
import * as tsx from "tsx/esm/api";
|
|
7
6
|
import {
|
|
8
7
|
logFileAdded,
|
|
9
8
|
logFileModified,
|
|
@@ -15,6 +14,7 @@ import { ConfectDirectory } from "../services/ConfectDirectory";
|
|
|
15
14
|
import { ConvexDirectory } from "../services/ConvexDirectory";
|
|
16
15
|
import * as templates from "../templates";
|
|
17
16
|
import {
|
|
17
|
+
bundleAndImport,
|
|
18
18
|
generateAuthConfig,
|
|
19
19
|
generateConvexConfig,
|
|
20
20
|
generateCrons,
|
|
@@ -32,17 +32,13 @@ const getNodeSpecPath = Effect.gen(function* () {
|
|
|
32
32
|
|
|
33
33
|
const loadNodeSpec = Effect.gen(function* () {
|
|
34
34
|
const fs = yield* FileSystem.FileSystem;
|
|
35
|
-
const path = yield* Path.Path;
|
|
36
35
|
const nodeSpecPath = yield* getNodeSpecPath;
|
|
37
36
|
|
|
38
37
|
if (!(yield* fs.exists(nodeSpecPath))) {
|
|
39
38
|
return Option.none<Spec.AnyWithPropsWithRuntime<"Node">>();
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
const
|
|
43
|
-
const nodeSpecModule = yield* Effect.promise(() =>
|
|
44
|
-
tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),
|
|
45
|
-
);
|
|
41
|
+
const nodeSpecModule = yield* bundleAndImport(nodeSpecPath);
|
|
46
42
|
const nodeSpec = nodeSpecModule.default;
|
|
47
43
|
|
|
48
44
|
if (!Spec.isNodeSpec(nodeSpec)) {
|
|
@@ -167,11 +163,8 @@ const generateFunctionModules = Effect.gen(function* () {
|
|
|
167
163
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
168
164
|
|
|
169
165
|
const specPath = path.join(confectDirectory, "spec.ts");
|
|
170
|
-
const specPathUrl = yield* path.toFileUrl(specPath);
|
|
171
166
|
|
|
172
|
-
const specModule = yield*
|
|
173
|
-
tsx.tsImport(specPathUrl.href, import.meta.url),
|
|
174
|
-
);
|
|
167
|
+
const specModule = yield* bundleAndImport(specPath);
|
|
175
168
|
const spec = specModule.default;
|
|
176
169
|
|
|
177
170
|
if (!Spec.isConvexSpec(spec)) {
|
|
@@ -196,11 +189,8 @@ const generateSchema = Effect.gen(function* () {
|
|
|
196
189
|
const convexDirectory = yield* ConvexDirectory.get;
|
|
197
190
|
|
|
198
191
|
const confectSchemaPath = path.join(confectDirectory, "schema.ts");
|
|
199
|
-
const confectSchemaUrl = yield* path.toFileUrl(confectSchemaPath);
|
|
200
192
|
|
|
201
|
-
yield*
|
|
202
|
-
tsx.tsImport(confectSchemaUrl.href, import.meta.url),
|
|
203
|
-
).pipe(
|
|
193
|
+
yield* bundleAndImport(confectSchemaPath).pipe(
|
|
204
194
|
Effect.andThen((schemaModule) => {
|
|
205
195
|
const defaultExport = schemaModule.default;
|
|
206
196
|
|
package/src/confect/dev.ts
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
} from "effect";
|
|
22
22
|
import type { ReadonlyRecord } from "effect/Record";
|
|
23
23
|
import * as esbuild from "esbuild";
|
|
24
|
-
import * as tsx from "tsx/esm/api";
|
|
25
24
|
import type * as FunctionPath from "../FunctionPath";
|
|
26
25
|
import * as FunctionPaths from "../FunctionPaths";
|
|
27
26
|
import * as GroupPath from "../GroupPath";
|
|
@@ -30,6 +29,8 @@ import { ConfectDirectory } from "../services/ConfectDirectory";
|
|
|
30
29
|
import { ConvexDirectory } from "../services/ConvexDirectory";
|
|
31
30
|
import { ProjectRoot } from "../services/ProjectRoot";
|
|
32
31
|
import {
|
|
32
|
+
bundleAndImport,
|
|
33
|
+
EXTERNAL_PACKAGES,
|
|
33
34
|
generateAuthConfig,
|
|
34
35
|
generateConvexConfig,
|
|
35
36
|
generateCrons,
|
|
@@ -336,11 +337,10 @@ const loadSpec = Effect.gen(function* () {
|
|
|
336
337
|
const fs = yield* FileSystem.FileSystem;
|
|
337
338
|
const path = yield* Path.Path;
|
|
338
339
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
339
|
-
const
|
|
340
|
-
const specModule = yield*
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
});
|
|
340
|
+
const specPath = yield* getSpecPath;
|
|
341
|
+
const specModule = yield* bundleAndImport(specPath).pipe(
|
|
342
|
+
Effect.mapError((error) => new SpecImportFailedError({ error })),
|
|
343
|
+
);
|
|
344
344
|
const spec = specModule.default;
|
|
345
345
|
|
|
346
346
|
if (!Spec.isConvexSpec(spec)) {
|
|
@@ -374,18 +374,15 @@ const getNodeSpecPath = Effect.gen(function* () {
|
|
|
374
374
|
|
|
375
375
|
const loadNodeSpec = Effect.gen(function* () {
|
|
376
376
|
const fs = yield* FileSystem.FileSystem;
|
|
377
|
-
const path = yield* Path.Path;
|
|
378
377
|
const nodeSpecPath = yield* getNodeSpecPath;
|
|
379
378
|
|
|
380
379
|
if (!(yield* fs.exists(nodeSpecPath))) {
|
|
381
380
|
return Option.none();
|
|
382
381
|
}
|
|
383
382
|
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
catch: (error) => new SpecImportFailedError({ error }),
|
|
388
|
-
});
|
|
383
|
+
const nodeSpecModule = yield* bundleAndImport(nodeSpecPath).pipe(
|
|
384
|
+
Effect.mapError((error) => new SpecImportFailedError({ error })),
|
|
385
|
+
);
|
|
389
386
|
const nodeSpec = nodeSpecModule.default;
|
|
390
387
|
|
|
391
388
|
if (!Spec.isNodeSpec(nodeSpec)) {
|
|
@@ -403,7 +400,7 @@ const esbuildOptions = (entryPoint: string) => ({
|
|
|
403
400
|
platform: "node" as const,
|
|
404
401
|
format: "esm" as const,
|
|
405
402
|
logLevel: "silent" as const,
|
|
406
|
-
external:
|
|
403
|
+
external: EXTERNAL_PACKAGES,
|
|
407
404
|
plugins: [
|
|
408
405
|
{
|
|
409
406
|
name: "notify-rebuild",
|
package/src/utils.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Record,
|
|
12
12
|
String,
|
|
13
13
|
} from "effect";
|
|
14
|
+
import * as esbuild from "esbuild";
|
|
14
15
|
import * as FunctionPaths from "./FunctionPaths";
|
|
15
16
|
import * as GroupPath from "./GroupPath";
|
|
16
17
|
import * as GroupPaths from "./GroupPaths";
|
|
@@ -26,6 +27,61 @@ export const removePathExtension = (pathStr: string) =>
|
|
|
26
27
|
return String.slice(0, -path.extname(pathStr).length)(pathStr);
|
|
27
28
|
});
|
|
28
29
|
|
|
30
|
+
export const EXTERNAL_PACKAGES = [
|
|
31
|
+
"@confect/core",
|
|
32
|
+
"@confect/server",
|
|
33
|
+
"effect",
|
|
34
|
+
"@effect/*",
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const isExternalImport = (path: string) =>
|
|
38
|
+
EXTERNAL_PACKAGES.some((p) => {
|
|
39
|
+
if (p.endsWith("/*")) {
|
|
40
|
+
return path.startsWith(p.slice(0, -1));
|
|
41
|
+
}
|
|
42
|
+
return path === p || path.startsWith(p + "/");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const absoluteExternalsPlugin: esbuild.Plugin = {
|
|
46
|
+
name: "absolute-externals",
|
|
47
|
+
setup(build) {
|
|
48
|
+
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
49
|
+
if (args.kind !== "import-statement" && args.kind !== "dynamic-import")
|
|
50
|
+
return;
|
|
51
|
+
if (!isExternalImport(args.path)) return;
|
|
52
|
+
const resolved = import.meta.resolve(
|
|
53
|
+
args.path,
|
|
54
|
+
"file://" + args.resolveDir + "/",
|
|
55
|
+
);
|
|
56
|
+
return { path: resolved, external: true };
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Bundle a TypeScript entry point with esbuild and import the result via a
|
|
63
|
+
* data URL. This handles extensionless `.ts` imports regardless of whether the
|
|
64
|
+
* user's project sets `"type": "module"` in package.json.
|
|
65
|
+
*/
|
|
66
|
+
export const bundleAndImport = (entryPoint: string) =>
|
|
67
|
+
Effect.gen(function* () {
|
|
68
|
+
const result = yield* Effect.promise(() =>
|
|
69
|
+
esbuild.build({
|
|
70
|
+
entryPoints: [entryPoint],
|
|
71
|
+
bundle: true,
|
|
72
|
+
write: false,
|
|
73
|
+
platform: "node",
|
|
74
|
+
format: "esm",
|
|
75
|
+
logLevel: "silent",
|
|
76
|
+
plugins: [absoluteExternalsPlugin],
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
const code = result.outputFiles[0]!.text;
|
|
80
|
+
const dataUrl =
|
|
81
|
+
"data:text/javascript;base64," + Buffer.from(code).toString("base64");
|
|
82
|
+
return yield* Effect.promise(() => import(dataUrl));
|
|
83
|
+
});
|
|
84
|
+
|
|
29
85
|
export const writeFileStringAndLog = (filePath: string, contents: string) =>
|
|
30
86
|
Effect.gen(function* () {
|
|
31
87
|
const fs = yield* FileSystem.FileSystem;
|