@confect/cli 1.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +7 -0
  3. package/dist/FunctionPath.mjs +19 -0
  4. package/dist/FunctionPath.mjs.map +1 -0
  5. package/dist/FunctionPaths.mjs +41 -0
  6. package/dist/FunctionPaths.mjs.map +1 -0
  7. package/dist/GroupPath.mjs +52 -0
  8. package/dist/GroupPath.mjs.map +1 -0
  9. package/dist/GroupPaths.mjs +9 -0
  10. package/dist/GroupPaths.mjs.map +1 -0
  11. package/dist/_virtual/rolldown_runtime.mjs +28 -0
  12. package/dist/cliApp.mjs +13 -0
  13. package/dist/cliApp.mjs.map +1 -0
  14. package/dist/confect/codegen.mjs +111 -0
  15. package/dist/confect/codegen.mjs.map +1 -0
  16. package/dist/confect/dev.mjs +253 -0
  17. package/dist/confect/dev.mjs.map +1 -0
  18. package/dist/confect.mjs +14 -0
  19. package/dist/confect.mjs.map +1 -0
  20. package/dist/index.d.mts +1 -0
  21. package/dist/index.mjs +19 -0
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/log.mjs +25 -0
  24. package/dist/log.mjs.map +1 -0
  25. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeCommandExecutor.mjs +12 -0
  26. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeCommandExecutor.mjs.map +1 -0
  27. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeFileSystem.mjs +15 -0
  28. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeFileSystem.mjs.map +1 -0
  29. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodePath.mjs +25 -0
  30. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodePath.mjs.map +1 -0
  31. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeRuntime.mjs +12 -0
  32. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeRuntime.mjs.map +1 -0
  33. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeTerminal.mjs +17 -0
  34. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/NodeTerminal.mjs.map +1 -0
  35. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/commandExecutor.mjs +129 -0
  36. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/commandExecutor.mjs.map +1 -0
  37. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/error.mjs +43 -0
  38. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/error.mjs.map +1 -0
  39. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/fileSystem.mjs +329 -0
  40. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/fileSystem.mjs.map +1 -0
  41. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/path.mjs +51 -0
  42. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/path.mjs.map +1 -0
  43. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/runtime.mjs +31 -0
  44. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/runtime.mjs.map +1 -0
  45. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/sink.mjs +24 -0
  46. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/sink.mjs.map +1 -0
  47. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/stream.mjs +91 -0
  48. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/stream.mjs.map +1 -0
  49. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/terminal.mjs +75 -0
  50. package/dist/node_modules/.pnpm/@effect_platform-node-shared@0.53.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effe_e0eeb3aae5ffec3060feb87d17ffb17c/node_modules/@effect/platform-node-shared/dist/esm/internal/terminal.mjs.map +1 -0
  51. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeContext.mjs +21 -0
  52. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeContext.mjs.map +1 -0
  53. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeFileSystem.mjs +15 -0
  54. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeFileSystem.mjs.map +1 -0
  55. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeRuntime.mjs +15 -0
  56. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeRuntime.mjs.map +1 -0
  57. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeWorker.mjs +27 -0
  58. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/NodeWorker.mjs.map +1 -0
  59. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/internal/worker.mjs +71 -0
  60. package/dist/node_modules/.pnpm/@effect_platform-node@0.100.0_@effect_cluster@0.52.9_@effect_platform@0.93.2_effect@3.1_a15ca1802d939cd85cc564105ef862ac/node_modules/@effect/platform-node/dist/esm/internal/worker.mjs.map +1 -0
  61. package/dist/packages/cli/package.mjs +6 -0
  62. package/dist/packages/cli/package.mjs.map +1 -0
  63. package/dist/packages/core/dist/Spec.mjs +23 -0
  64. package/dist/packages/core/dist/Spec.mjs.map +1 -0
  65. package/dist/packages/core/dist/_virtual/rolldown_runtime.mjs +14 -0
  66. package/dist/packages/core/dist/_virtual/rolldown_runtime.mjs.map +1 -0
  67. package/dist/services/ConfectDirectory.mjs +31 -0
  68. package/dist/services/ConfectDirectory.mjs.map +1 -0
  69. package/dist/services/ConvexDirectory.mjs +41 -0
  70. package/dist/services/ConvexDirectory.mjs.map +1 -0
  71. package/dist/services/ProjectRoot.mjs +35 -0
  72. package/dist/services/ProjectRoot.mjs.map +1 -0
  73. package/dist/templates.mjs +204 -0
  74. package/dist/templates.mjs.map +1 -0
  75. package/dist/utils.mjs +162 -0
  76. package/dist/utils.mjs.map +1 -0
  77. package/package.json +86 -0
  78. package/src/FunctionPath.ts +28 -0
  79. package/src/FunctionPaths.ts +103 -0
  80. package/src/GroupPath.ts +117 -0
  81. package/src/GroupPaths.ts +7 -0
  82. package/src/cliApp.ts +8 -0
  83. package/src/confect/codegen.ts +228 -0
  84. package/src/confect/dev.ts +611 -0
  85. package/src/confect.ts +19 -0
  86. package/src/index.ts +22 -0
  87. package/src/log.ts +106 -0
  88. package/src/services/ConfectDirectory.ts +41 -0
  89. package/src/services/ConvexDirectory.ts +67 -0
  90. package/src/services/ProjectRoot.ts +49 -0
  91. package/src/templates.ts +380 -0
  92. package/src/utils.ts +332 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # @confect/cli
2
+
3
+ ## 1.0.0-next.0
4
+
5
+ ### Major Changes
6
+
7
+ - 2ff70a7: Initial release.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [2ff70a7]
12
+ - @confect/server@1.0.0-next.0
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ ISC License
2
+
3
+ Copyright 2024 RJ Dellecese
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,19 @@
1
+ import { GroupPath } from "./GroupPath.mjs";
2
+ import { Schema } from "effect";
3
+
4
+ //#region src/FunctionPath.ts
5
+ /**
6
+ * The path to a function in the Confect API.
7
+ */
8
+ var FunctionPath = class extends Schema.Class("FunctionPath")({
9
+ groupPath: GroupPath,
10
+ name: Schema.NonEmptyString
11
+ }) {};
12
+ /**
13
+ * Get the group path from a function path.
14
+ */
15
+ const groupPath = (functionPath) => functionPath.groupPath;
16
+
17
+ //#endregion
18
+ export { FunctionPath, groupPath };
19
+ //# sourceMappingURL=FunctionPath.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FunctionPath.mjs","names":["GroupPath.GroupPath"],"sources":["../src/FunctionPath.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport * as GroupPath from \"./GroupPath\";\n\n/**\n * The path to a function in the Confect API.\n */\nexport class FunctionPath extends Schema.Class<FunctionPath>(\"FunctionPath\")({\n // TODO: Support root-level functions (also must be supported in the other packages, e.g. `core` and `server`)\n groupPath: GroupPath.GroupPath,\n name: Schema.NonEmptyString,\n}) {}\n\n/**\n * Get the group path from a function path.\n */\nexport const groupPath = (functionPath: FunctionPath): GroupPath.GroupPath =>\n functionPath.groupPath;\n\n/**\n * Get the function name from a function path.\n */\nexport const name = (functionPath: FunctionPath): string => functionPath.name;\n\n/**\n * Get the function path as a string.\n */\nexport const toString = (functionPath: FunctionPath): string =>\n `${GroupPath.toString(functionPath.groupPath)}.${functionPath.name}`;\n"],"mappings":";;;;;;;AAMA,IAAa,eAAb,cAAkC,OAAO,MAAoB,eAAe,CAAC;CAE3E,WAAWA;CACX,MAAM,OAAO;CACd,CAAC,CAAC;;;;AAKH,MAAa,aAAa,iBACxB,aAAa"}
@@ -0,0 +1,41 @@
1
+ import { append, make as make$1 } from "./GroupPath.mjs";
2
+ import { FunctionPath, groupPath } from "./FunctionPath.mjs";
3
+ import { GroupPaths } from "./GroupPaths.mjs";
4
+ import { HashSet, Option, Record, Schema, pipe } from "effect";
5
+
6
+ //#region src/FunctionPaths.ts
7
+ const FunctionPaths = Schema.HashSetFromSelf(FunctionPath).pipe(Schema.brand("@confect/cli/FunctionPaths"));
8
+ const make = (spec) => makeHelper(spec.groups, Option.none(), FunctionPaths.make(HashSet.empty()));
9
+ const makeHelper = (groups, currentGroupPath, apiPaths) => Record.reduce(groups, apiPaths, (acc, group, groupName) => {
10
+ const groupPath$1 = Option.match(currentGroupPath, {
11
+ onNone: () => make$1([groupName]),
12
+ onSome: (path) => append(path, groupName)
13
+ });
14
+ const accWithFunctions = Record.reduce(group.functions, acc, (acc_, _fn, functionName) => FunctionPaths.make(HashSet.add(acc_, FunctionPath.make({
15
+ groupPath: groupPath$1,
16
+ name: functionName
17
+ }))));
18
+ return makeHelper(group.groups, Option.some(groupPath$1), accWithFunctions);
19
+ });
20
+ const groupPaths = (functionPaths) => pipe(functionPaths, HashSet.map(groupPath), GroupPaths.make);
21
+ const diff = (previousFunctions, currentFunctions) => {
22
+ const currentGroups = groupPaths(currentFunctions);
23
+ const previousGroups = groupPaths(previousFunctions);
24
+ const groupsAdded = GroupPaths.make(HashSet.difference(currentGroups, previousGroups));
25
+ const groupsRemoved = GroupPaths.make(HashSet.difference(previousGroups, currentGroups));
26
+ const functionsAdded = FunctionPaths.make(HashSet.difference(currentFunctions, previousFunctions));
27
+ const existingGroupsToWhichFunctionsWereAdded = GroupPaths.make(HashSet.intersection(currentGroups, groupPaths(functionsAdded)));
28
+ const functionsRemoved = FunctionPaths.make(HashSet.difference(previousFunctions, currentFunctions));
29
+ const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.make(HashSet.intersection(previousGroups, groupPaths(functionsRemoved)));
30
+ return {
31
+ functionsAdded,
32
+ functionsRemoved,
33
+ groupsRemoved,
34
+ groupsAdded,
35
+ groupsChanged: pipe(existingGroupsToWhichFunctionsWereAdded, HashSet.union(existingGroupsToWhichFunctionsWereRemoved), HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)), GroupPaths.make)
36
+ };
37
+ };
38
+
39
+ //#endregion
40
+ export { diff, groupPaths, make };
41
+ //# sourceMappingURL=FunctionPaths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FunctionPaths.mjs","names":["FunctionPath.FunctionPath","groupPath","GroupPath.make","GroupPath.append","FunctionPath.groupPath"],"sources":["../src/FunctionPaths.ts"],"sourcesContent":["import type { GroupSpec, Spec } from \"@confect/core\";\nimport { HashSet, Option, pipe, Record, Schema } from \"effect\";\nimport * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\n\nexport const FunctionPaths = Schema.HashSetFromSelf(\n FunctionPath.FunctionPath,\n).pipe(Schema.brand(\"@confect/cli/FunctionPaths\"));\nexport type FunctionPaths = typeof FunctionPaths.Type;\n\nexport const make = (spec: Spec.AnyWithProps): FunctionPaths =>\n makeHelper(spec.groups, Option.none(), FunctionPaths.make(HashSet.empty()));\n\nconst makeHelper = (\n groups: {\n [key: string]: GroupSpec.AnyWithProps;\n },\n currentGroupPath: Option.Option<GroupPath.GroupPath>,\n apiPaths: FunctionPaths,\n): FunctionPaths =>\n Record.reduce(groups, apiPaths, (acc, group, groupName) => {\n const groupPath = Option.match(currentGroupPath, {\n onNone: () => GroupPath.make([groupName]),\n onSome: (path) => GroupPath.append(path, groupName),\n });\n\n const accWithFunctions = Record.reduce(\n group.functions,\n acc,\n (acc_, _fn, functionName) =>\n FunctionPaths.make(\n HashSet.add(\n acc_,\n FunctionPath.FunctionPath.make({\n groupPath,\n name: functionName,\n }),\n ),\n ),\n );\n\n return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);\n });\n\nexport const groupPaths = (\n functionPaths: FunctionPaths,\n): GroupPaths.GroupPaths =>\n pipe(\n functionPaths,\n HashSet.map(FunctionPath.groupPath),\n GroupPaths.GroupPaths.make,\n );\n\nexport const diff = (\n previousFunctions: FunctionPaths,\n currentFunctions: FunctionPaths,\n): {\n functionsAdded: FunctionPaths;\n functionsRemoved: FunctionPaths;\n groupsRemoved: GroupPaths.GroupPaths;\n groupsAdded: GroupPaths.GroupPaths;\n groupsChanged: GroupPaths.GroupPaths;\n} => {\n const currentGroups = groupPaths(currentFunctions);\n const previousGroups = groupPaths(previousFunctions);\n\n const groupsAdded = GroupPaths.GroupPaths.make(\n HashSet.difference(currentGroups, previousGroups),\n );\n const groupsRemoved = GroupPaths.GroupPaths.make(\n HashSet.difference(previousGroups, currentGroups),\n );\n\n const functionsAdded = FunctionPaths.make(\n HashSet.difference(currentFunctions, previousFunctions),\n );\n const existingGroupsToWhichFunctionsWereAdded = GroupPaths.GroupPaths.make(\n HashSet.intersection(currentGroups, groupPaths(functionsAdded)),\n );\n\n const functionsRemoved = FunctionPaths.make(\n HashSet.difference(previousFunctions, currentFunctions),\n );\n const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.GroupPaths.make(\n HashSet.intersection(previousGroups, groupPaths(functionsRemoved)),\n );\n\n const groupsChanged = pipe(\n existingGroupsToWhichFunctionsWereAdded,\n HashSet.union(existingGroupsToWhichFunctionsWereRemoved),\n HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)),\n GroupPaths.GroupPaths.make,\n );\n\n return {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n };\n};\n"],"mappings":";;;;;;AAMA,MAAa,gBAAgB,OAAO,gBAClCA,aACD,CAAC,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAGlD,MAAa,QAAQ,SACnB,WAAW,KAAK,QAAQ,OAAO,MAAM,EAAE,cAAc,KAAK,QAAQ,OAAO,CAAC,CAAC;AAE7E,MAAM,cACJ,QAGA,kBACA,aAEA,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,cAAc;CACzD,MAAMC,cAAY,OAAO,MAAM,kBAAkB;EAC/C,cAAcC,OAAe,CAAC,UAAU,CAAC;EACzC,SAAS,SAASC,OAAiB,MAAM,UAAU;EACpD,CAAC;CAEF,MAAM,mBAAmB,OAAO,OAC9B,MAAM,WACN,MACC,MAAM,KAAK,iBACV,cAAc,KACZ,QAAQ,IACN,mBAC0B,KAAK;EAC7B;EACA,MAAM;EACP,CAAC,CACH,CACF,CACJ;AAED,QAAO,WAAW,MAAM,QAAQ,OAAO,KAAKF,YAAU,EAAE,iBAAiB;EACzE;AAEJ,MAAa,cACX,kBAEA,KACE,eACA,QAAQ,IAAIG,UAAuB,aACb,KACvB;AAEH,MAAa,QACX,mBACA,qBAOG;CACH,MAAM,gBAAgB,WAAW,iBAAiB;CAClD,MAAM,iBAAiB,WAAW,kBAAkB;CAEpD,MAAM,yBAAoC,KACxC,QAAQ,WAAW,eAAe,eAAe,CAClD;CACD,MAAM,2BAAsC,KAC1C,QAAQ,WAAW,gBAAgB,cAAc,CAClD;CAED,MAAM,iBAAiB,cAAc,KACnC,QAAQ,WAAW,kBAAkB,kBAAkB,CACxD;CACD,MAAM,qDAAgE,KACpE,QAAQ,aAAa,eAAe,WAAW,eAAe,CAAC,CAChE;CAED,MAAM,mBAAmB,cAAc,KACrC,QAAQ,WAAW,mBAAmB,iBAAiB,CACxD;CACD,MAAM,uDAAkE,KACtE,QAAQ,aAAa,gBAAgB,WAAW,iBAAiB,CAAC,CACnE;AASD,QAAO;EACL;EACA;EACA;EACA;EACA,eAZoB,KACpB,yCACA,QAAQ,MAAM,0CAA0C,EACxD,QAAQ,WAAW,QAAQ,MAAM,aAAa,cAAc,CAAC,aACvC,KACvB;EAQA"}
@@ -0,0 +1,52 @@
1
+ import { Array, Data, Effect, Option, Record, Schema, String, pipe } from "effect";
2
+ import { Path } from "@effect/platform";
3
+
4
+ //#region src/GroupPath.ts
5
+ /**
6
+ * The path to a group in the Confect API.
7
+ */
8
+ var GroupPath = class extends Schema.Class("GroupPath")({ pathSegments: Schema.Data(Schema.NonEmptyArray(Schema.NonEmptyString)) }) {};
9
+ /**
10
+ * Create a GroupPath from path segments.
11
+ */
12
+ const make = (pathSegments) => GroupPath.make({ pathSegments: Data.array(pathSegments) });
13
+ /**
14
+ * Append a group name to a GroupPath to create a new GroupPath.
15
+ */
16
+ const append = (groupPath, groupName) => make([...groupPath.pathSegments, groupName]);
17
+ /**
18
+ * Expects a path string of the form `./group1/group2.ts`, relative to the Convex functions directory.
19
+ */
20
+ const fromGroupModulePath = (groupModulePath) => Effect.gen(function* () {
21
+ const path = yield* Path.Path;
22
+ const { dir, name, ext } = path.parse(groupModulePath);
23
+ if (ext === ".ts") {
24
+ const dirSegments = Array.filter(String.split(dir, path.sep), String.isNonEmpty);
25
+ yield* Effect.logDebug(Array.append(dirSegments, name));
26
+ return make(Array.append(dirSegments, name));
27
+ } else return yield* Effect.fail(new GroupModulePathIsNotATypeScriptFileError({ path: groupModulePath }));
28
+ });
29
+ /**
30
+ * Get the module path for a group, relative to the Convex functions directory.
31
+ */
32
+ const modulePath = (groupPath) => Effect.gen(function* () {
33
+ return (yield* Path.Path).join(...groupPath.pathSegments) + ".ts";
34
+ });
35
+ const getGroupSpec = (spec, groupPath) => pipe(groupPath.pathSegments, Array.matchLeft({
36
+ onEmpty: () => Option.none(),
37
+ onNonEmpty: (head, tail) => pipe(Record.get(spec.groups, head), Option.flatMap((group) => Array.isNonEmptyArray(tail) ? getGroupSpecHelper(group, tail) : Option.some(group)))
38
+ }));
39
+ const getGroupSpecHelper = (group, remainingPath) => pipe(remainingPath, Array.matchLeft({
40
+ onEmpty: () => Option.some(group),
41
+ onNonEmpty: (head, tail) => pipe(Record.get(group.groups, head), Option.flatMap((subGroup) => Array.isNonEmptyArray(tail) ? getGroupSpecHelper(subGroup, tail) : Option.some(subGroup)))
42
+ }));
43
+ const toString = (groupPath) => Array.join(groupPath.pathSegments, ".");
44
+ var GroupModulePathIsNotATypeScriptFileError = class extends Schema.TaggedError("GroupModulePathIsNotATypeScriptFileError")("GroupModulePathIsNotATypeScriptFileError", { path: Schema.NonEmptyString }) {
45
+ get message() {
46
+ return `Expected group module path to end with .ts, got ${this.path}`;
47
+ }
48
+ };
49
+
50
+ //#endregion
51
+ export { GroupPath, append, fromGroupModulePath, getGroupSpec, make, modulePath, toString };
52
+ //# sourceMappingURL=GroupPath.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupPath.mjs","names":[],"sources":["../src/GroupPath.ts"],"sourcesContent":["import { type GroupSpec, type Spec } from \"@confect/core\";\nimport { Path } from \"@effect/platform\";\nimport {\n Array,\n Data,\n Effect,\n Option,\n pipe,\n Record,\n Schema,\n String,\n} from \"effect\";\n\n/**\n * The path to a group in the Confect API.\n */\nexport class GroupPath extends Schema.Class<GroupPath>(\"GroupPath\")({\n pathSegments: Schema.Data(Schema.NonEmptyArray(Schema.NonEmptyString)),\n}) {}\n\n/**\n * Create a GroupPath from path segments.\n */\nexport const make = (pathSegments: readonly [string, ...string[]]): GroupPath =>\n GroupPath.make({ pathSegments: Data.array(pathSegments) });\n\n/**\n * Append a group name to a GroupPath to create a new GroupPath.\n */\nexport const append = (groupPath: GroupPath, groupName: string): GroupPath =>\n make([...groupPath.pathSegments, groupName]);\n\n/**\n * Expects a path string of the form `./group1/group2.ts`, relative to the Convex functions directory.\n */\nexport const fromGroupModulePath = (groupModulePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n const { dir, name, ext } = path.parse(groupModulePath);\n\n if (ext === \".ts\") {\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n yield* Effect.logDebug(Array.append(dirSegments, name));\n return make(Array.append(dirSegments, name));\n } else {\n return yield* Effect.fail(\n new GroupModulePathIsNotATypeScriptFileError({ path: groupModulePath }),\n );\n }\n });\n\n/**\n * Get the module path for a group, relative to the Convex functions directory.\n */\nexport const modulePath = (groupPath: GroupPath) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return path.join(...groupPath.pathSegments) + \".ts\";\n });\n\nexport const getGroupSpec = (\n spec: Spec.AnyWithProps,\n groupPath: GroupPath,\n): Option.Option<GroupSpec.AnyWithProps> =>\n pipe(\n groupPath.pathSegments,\n Array.matchLeft({\n onEmpty: () => Option.none(),\n onNonEmpty: (head, tail) =>\n pipe(\n Record.get(spec.groups, head),\n Option.flatMap((group) =>\n Array.isNonEmptyArray(tail)\n ? getGroupSpecHelper(group, tail)\n : Option.some(group),\n ),\n ),\n }),\n );\n\nconst getGroupSpecHelper = (\n group: GroupSpec.AnyWithProps,\n remainingPath: ReadonlyArray<string>,\n): Option.Option<GroupSpec.AnyWithProps> =>\n pipe(\n remainingPath,\n Array.matchLeft({\n onEmpty: () => Option.some(group),\n onNonEmpty: (head, tail) =>\n pipe(\n Record.get(group.groups, head),\n Option.flatMap((subGroup) =>\n Array.isNonEmptyArray(tail)\n ? getGroupSpecHelper(subGroup, tail)\n : Option.some(subGroup),\n ),\n ),\n }),\n );\n\nexport const toString = (groupPath: GroupPath) =>\n Array.join(groupPath.pathSegments, \".\");\n\nexport class GroupModulePathIsNotATypeScriptFileError extends Schema.TaggedError<GroupModulePathIsNotATypeScriptFileError>(\n \"GroupModulePathIsNotATypeScriptFileError\",\n)(\"GroupModulePathIsNotATypeScriptFileError\", {\n path: Schema.NonEmptyString,\n}) {\n override get message(): string {\n return `Expected group module path to end with .ts, got ${this.path}`;\n }\n}\n"],"mappings":";;;;;;;AAgBA,IAAa,YAAb,cAA+B,OAAO,MAAiB,YAAY,CAAC,EAClE,cAAc,OAAO,KAAK,OAAO,cAAc,OAAO,eAAe,CAAC,EACvE,CAAC,CAAC;;;;AAKH,MAAa,QAAQ,iBACnB,UAAU,KAAK,EAAE,cAAc,KAAK,MAAM,aAAa,EAAE,CAAC;;;;AAK5D,MAAa,UAAU,WAAsB,cAC3C,KAAK,CAAC,GAAG,UAAU,cAAc,UAAU,CAAC;;;;AAK9C,MAAa,uBAAuB,oBAClC,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,gBAAgB;AAEtD,KAAI,QAAQ,OAAO;EACjB,MAAM,cAAc,MAAM,OACxB,OAAO,MAAM,KAAK,KAAK,IAAI,EAC3B,OAAO,WACR;AACD,SAAO,OAAO,SAAS,MAAM,OAAO,aAAa,KAAK,CAAC;AACvD,SAAO,KAAK,MAAM,OAAO,aAAa,KAAK,CAAC;OAE5C,QAAO,OAAO,OAAO,KACnB,IAAI,yCAAyC,EAAE,MAAM,iBAAiB,CAAC,CACxE;EAEH;;;;AAKJ,MAAa,cAAc,cACzB,OAAO,IAAI,aAAa;AAGtB,SAFa,OAAO,KAAK,MAEb,KAAK,GAAG,UAAU,aAAa,GAAG;EAC9C;AAEJ,MAAa,gBACX,MACA,cAEA,KACE,UAAU,cACV,MAAM,UAAU;CACd,eAAe,OAAO,MAAM;CAC5B,aAAa,MAAM,SACjB,KACE,OAAO,IAAI,KAAK,QAAQ,KAAK,EAC7B,OAAO,SAAS,UACd,MAAM,gBAAgB,KAAK,GACvB,mBAAmB,OAAO,KAAK,GAC/B,OAAO,KAAK,MAAM,CACvB,CACF;CACJ,CAAC,CACH;AAEH,MAAM,sBACJ,OACA,kBAEA,KACE,eACA,MAAM,UAAU;CACd,eAAe,OAAO,KAAK,MAAM;CACjC,aAAa,MAAM,SACjB,KACE,OAAO,IAAI,MAAM,QAAQ,KAAK,EAC9B,OAAO,SAAS,aACd,MAAM,gBAAgB,KAAK,GACvB,mBAAmB,UAAU,KAAK,GAClC,OAAO,KAAK,SAAS,CAC1B,CACF;CACJ,CAAC,CACH;AAEH,MAAa,YAAY,cACvB,MAAM,KAAK,UAAU,cAAc,IAAI;AAEzC,IAAa,2CAAb,cAA8D,OAAO,YACnE,2CACD,CAAC,4CAA4C,EAC5C,MAAM,OAAO,gBACd,CAAC,CAAC;CACD,IAAa,UAAkB;AAC7B,SAAO,mDAAmD,KAAK"}
@@ -0,0 +1,9 @@
1
+ import { GroupPath } from "./GroupPath.mjs";
2
+ import { Schema } from "effect";
3
+
4
+ //#region src/GroupPaths.ts
5
+ const GroupPaths = Schema.HashSetFromSelf(GroupPath).pipe(Schema.brand("@confect/cli/GroupPaths"));
6
+
7
+ //#endregion
8
+ export { GroupPaths };
9
+ //# sourceMappingURL=GroupPaths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupPaths.mjs","names":["GroupPath.GroupPath"],"sources":["../src/GroupPaths.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport * as GroupPath from \"./GroupPath\";\n\nexport const GroupPaths = Schema.HashSetFromSelf(GroupPath.GroupPath).pipe(\n Schema.brand(\"@confect/cli/GroupPaths\"),\n);\nexport type GroupPaths = typeof GroupPaths.Type;\n"],"mappings":";;;;AAGA,MAAa,aAAa,OAAO,gBAAgBA,UAAoB,CAAC,KACpE,OAAO,MAAM,0BAA0B,CACxC"}
@@ -0,0 +1,28 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region rolldown:runtime
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
22
+ value: mod,
23
+ enumerable: true
24
+ }) : target, mod));
25
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
26
+
27
+ //#endregion
28
+ export { };
@@ -0,0 +1,13 @@
1
+ import { version } from "./packages/cli/package.mjs";
2
+ import { confect } from "./confect.mjs";
3
+ import { Command } from "@effect/cli";
4
+
5
+ //#region src/cliApp.ts
6
+ const cliApp = Command.run(confect, {
7
+ name: "Confect",
8
+ version
9
+ });
10
+
11
+ //#endregion
12
+ export { cliApp };
13
+ //# sourceMappingURL=cliApp.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliApp.mjs","names":["packageJson.version"],"sources":["../src/cliApp.ts"],"sourcesContent":["import { Command } from \"@effect/cli\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport { confect } from \"./confect\";\n\nexport const cliApp = Command.run(confect, {\n name: \"Confect\",\n version: packageJson.version,\n});\n"],"mappings":";;;;;AAIA,MAAa,SAAS,QAAQ,IAAI,SAAS;CACzC,MAAM;CACGA;CACV,CAAC"}
@@ -0,0 +1,111 @@
1
+ import { Spec_exports } from "../packages/core/dist/Spec.mjs";
2
+ import { logCompleted, logFileAdded, logFileModified } from "../log.mjs";
3
+ import { ConvexDirectory } from "../services/ConvexDirectory.mjs";
4
+ import { ConfectDirectory } from "../services/ConfectDirectory.mjs";
5
+ import { api, refs, registeredFunctions, schema, services } from "../templates.mjs";
6
+ import { generateAuthConfig, generateConvexConfig, generateCrons, generateFunctions, generateHttp, removePathExtension, writeFileStringAndLog } from "../utils.mjs";
7
+ import { Effect, Match, Option } from "effect";
8
+ import { Command } from "@effect/cli";
9
+ import { DatabaseSchema } from "@confect/server";
10
+ import { FileSystem, Path } from "@effect/platform";
11
+ import * as tsx from "tsx/esm/api";
12
+
13
+ //#region src/confect/codegen.ts
14
+ const codegen = Command.make("codegen", {}, () => Effect.gen(function* () {
15
+ yield* codegenHandler;
16
+ yield* logCompleted("Generated files are up-to-date");
17
+ })).pipe(Command.withDescription("Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)"));
18
+ const codegenHandler = Effect.gen(function* () {
19
+ yield* generateConfectGeneratedDirectory;
20
+ yield* Effect.all([
21
+ generateApi,
22
+ generateRefs,
23
+ generateRegisteredFunctions,
24
+ generateServices
25
+ ], { concurrency: "unbounded" });
26
+ const [functionPaths] = yield* Effect.all([
27
+ generateFunctionModules,
28
+ generateSchema,
29
+ logGenerated(generateHttp),
30
+ logGenerated(generateConvexConfig),
31
+ logGenerated(generateCrons),
32
+ logGenerated(generateAuthConfig)
33
+ ], { concurrency: "unbounded" });
34
+ return functionPaths;
35
+ });
36
+ const generateConfectGeneratedDirectory = Effect.gen(function* () {
37
+ const fs = yield* FileSystem.FileSystem;
38
+ const path = yield* Path.Path;
39
+ const confectDirectory = yield* ConfectDirectory.get;
40
+ if (!(yield* fs.exists(path.join(confectDirectory, "_generated")))) {
41
+ yield* fs.makeDirectory(path.join(confectDirectory, "_generated"), { recursive: true });
42
+ yield* logFileAdded(path.join(confectDirectory, "_generated") + "/");
43
+ }
44
+ });
45
+ const generateApi = Effect.gen(function* () {
46
+ const path = yield* Path.Path;
47
+ const confectDirectory = yield* ConfectDirectory.get;
48
+ const apiPath = path.join(confectDirectory, "_generated", "api.ts");
49
+ const schemaImportPath = yield* removePathExtension(path.relative(path.dirname(apiPath), path.join(confectDirectory, "schema.ts")));
50
+ const specImportPath = yield* removePathExtension(path.relative(path.dirname(apiPath), path.join(confectDirectory, "spec.ts")));
51
+ yield* writeFileStringAndLog(apiPath, yield* api({
52
+ schemaImportPath,
53
+ specImportPath
54
+ }));
55
+ });
56
+ const generateFunctionModules = Effect.gen(function* () {
57
+ const path = yield* Path.Path;
58
+ const confectDirectory = yield* ConfectDirectory.get;
59
+ const specPath = path.join(confectDirectory, "spec.ts");
60
+ const specPathUrl = yield* path.toFileUrl(specPath);
61
+ const spec = (yield* Effect.promise(() => tsx.tsImport(specPathUrl.href, import.meta.url))).default;
62
+ if (!Spec_exports.isSpec(spec)) return yield* Effect.die("spec.ts does not export a valid Spec");
63
+ return yield* generateFunctions(spec);
64
+ });
65
+ const generateSchema = Effect.gen(function* () {
66
+ const path = yield* Path.Path;
67
+ const confectDirectory = yield* ConfectDirectory.get;
68
+ const convexDirectory = yield* ConvexDirectory.get;
69
+ const confectSchemaPath = path.join(confectDirectory, "schema.ts");
70
+ const confectSchemaUrl = yield* path.toFileUrl(confectSchemaPath);
71
+ yield* Effect.promise(() => tsx.tsImport(confectSchemaUrl.href, import.meta.url)).pipe(Effect.andThen((schemaModule) => {
72
+ const defaultExport = schemaModule.default;
73
+ return DatabaseSchema.isSchema(defaultExport) ? Effect.succeed(defaultExport) : Effect.die("Invalid schema module");
74
+ }));
75
+ const convexSchemaPath = path.join(convexDirectory, "schema.ts");
76
+ const importPathWithoutExt = yield* removePathExtension(path.relative(path.dirname(convexSchemaPath), confectSchemaPath));
77
+ yield* writeFileStringAndLog(convexSchemaPath, yield* schema({ schemaImportPath: importPathWithoutExt }));
78
+ });
79
+ const generateServices = Effect.gen(function* () {
80
+ const path = yield* Path.Path;
81
+ const confectDirectory = yield* ConfectDirectory.get;
82
+ const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
83
+ const servicesPath = path.join(confectGeneratedDirectory, "services.ts");
84
+ const schemaImportPath = path.relative(path.dirname(servicesPath), path.join(confectDirectory, "schema"));
85
+ yield* writeFileStringAndLog(servicesPath, yield* services({ schemaImportPath }));
86
+ });
87
+ const generateRegisteredFunctions = Effect.gen(function* () {
88
+ const path = yield* Path.Path;
89
+ const confectDirectory = yield* ConfectDirectory.get;
90
+ const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
91
+ const registeredFunctionsPath = path.join(confectGeneratedDirectory, "registeredFunctions.ts");
92
+ const implImportPath = yield* removePathExtension(path.relative(path.dirname(registeredFunctionsPath), path.join(confectDirectory, "impl.ts")));
93
+ yield* writeFileStringAndLog(registeredFunctionsPath, yield* registeredFunctions({ implImportPath }));
94
+ });
95
+ const generateRefs = Effect.gen(function* () {
96
+ const path = yield* Path.Path;
97
+ const confectDirectory = yield* ConfectDirectory.get;
98
+ const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
99
+ const confectSpecPath = path.join(confectDirectory, "spec.ts");
100
+ const refsPath = path.join(confectGeneratedDirectory, "refs.ts");
101
+ const importPathWithoutExt = yield* removePathExtension(path.relative(path.dirname(refsPath), confectSpecPath));
102
+ yield* writeFileStringAndLog(refsPath, yield* refs({ specImportPath: importPathWithoutExt }));
103
+ });
104
+ const logGenerated = (effect) => effect.pipe(Effect.tap(Option.match({
105
+ onNone: () => Effect.void,
106
+ onSome: ({ change, convexFilePath }) => Match.value(change).pipe(Match.when("Added", () => logFileAdded(convexFilePath)), Match.when("Modified", () => logFileModified(convexFilePath)), Match.when("Unchanged", () => Effect.void), Match.exhaustive)
107
+ })));
108
+
109
+ //#endregion
110
+ export { codegen, codegenHandler };
111
+ //# sourceMappingURL=codegen.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.mjs","names":["templates.api","Spec","templates.schema","templates.services","templates.registeredFunctions","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 { logCompleted, logFileAdded, logFileModified } 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\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* codegenHandler;\n yield* logCompleted(\"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 [generateApi, generateRefs, generateRegisteredFunctions, generateServices],\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\n const schemaImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(apiPath),\n path.join(confectDirectory, \"schema.ts\"),\n ),\n );\n\n const specImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(apiPath),\n path.join(confectDirectory, \"spec.ts\"),\n ),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\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.isSpec(spec)) {\n return yield* Effect.die(\"spec.ts does not export a valid Spec\");\n }\n\n return yield* generateFunctions(spec);\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\nconst generateRefs = 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 confectSpecPath = path.join(confectDirectory, \"spec.ts\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(refsPath),\n confectSpecPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n\n const refsContents = yield* templates.refs({\n specImportPath: importPathWithoutExt,\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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"}
@@ -0,0 +1,253 @@
1
+ import { Spec_exports } from "../packages/core/dist/Spec.mjs";
2
+ import { modulePath, toString } from "../GroupPath.mjs";
3
+ import { ProjectRoot } from "../services/ProjectRoot.mjs";
4
+ import { logCompleted, logFailed } from "../log.mjs";
5
+ import { ConvexDirectory } from "../services/ConvexDirectory.mjs";
6
+ import { ConfectDirectory } from "../services/ConfectDirectory.mjs";
7
+ import { diff, make } from "../FunctionPaths.mjs";
8
+ import { generateAuthConfig, generateConvexConfig, generateCrons, generateHttp, removeGroups, writeGroups } from "../utils.mjs";
9
+ import { codegenHandler } from "./codegen.mjs";
10
+ import { Array, Console, Data, Duration, Effect, Equal, HashSet, Match, Option, Queue, Ref, Schema, Stream, String, pipe } from "effect";
11
+ import { Command } from "@effect/cli";
12
+ import { FileSystem, Path } from "@effect/platform";
13
+ import * as tsx from "tsx/esm/api";
14
+ import { Ansi, AnsiDoc } from "@effect/printer-ansi";
15
+ import * as esbuild from "esbuild";
16
+
17
+ //#region src/confect/dev.ts
18
+ const pendingInit = {
19
+ specDirty: false,
20
+ httpDirty: false,
21
+ appDirty: false,
22
+ cronsDirty: false,
23
+ authDirty: false
24
+ };
25
+ const FileChange = Data.taggedEnum();
26
+ const logChangeReport = (changes) => Effect.gen(function* () {
27
+ yield* logCompleted("Generated files are up-to-date");
28
+ yield* Effect.when(Effect.forEach(changes, (change) => FileChange.$match(change, {
29
+ OptionalFile: ({ change: c, filePath }) => logFileChangeIndented(c, filePath),
30
+ GroupModule: ({ change: c, filePath, functionsAdded, functionsRemoved }) => Effect.gen(function* () {
31
+ yield* logFileChangeIndented(c, filePath);
32
+ yield* Effect.forEach(functionsAdded, logFunctionAddedIndented);
33
+ yield* Effect.forEach(functionsRemoved, logFunctionRemovedIndented);
34
+ })
35
+ })), () => Array.isNonEmptyReadonlyArray(changes));
36
+ });
37
+ const changeChar = (change) => Match.value(change).pipe(Match.when("Added", () => ({
38
+ char: "+",
39
+ color: Ansi.green
40
+ })), Match.when("Removed", () => ({
41
+ char: "-",
42
+ color: Ansi.red
43
+ })), Match.when("Modified", () => ({
44
+ char: "~",
45
+ color: Ansi.yellow
46
+ })), Match.exhaustive);
47
+ const logFileChangeIndented = (change, fullPath) => Effect.gen(function* () {
48
+ const prefix = (yield* ProjectRoot.get) + (yield* Path.Path).sep;
49
+ const suffix = pipe(fullPath, String.startsWith(prefix)) ? pipe(fullPath, String.slice(prefix.length)) : fullPath;
50
+ const { char, color } = changeChar(change);
51
+ yield* Console.log(pipe(AnsiDoc.text(" "), AnsiDoc.cat(pipe(AnsiDoc.char(char), AnsiDoc.annotate(color))), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color))])), AnsiDoc.render({ style: "pretty" })));
52
+ });
53
+ const logFunctionAddedIndented = (functionPath) => Console.log(pipe(AnsiDoc.text(" "), AnsiDoc.cat(pipe(AnsiDoc.char("+"), AnsiDoc.annotate(Ansi.green))), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(toString(functionPath.groupPath) + "."), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.green))])), AnsiDoc.render({ style: "pretty" })));
54
+ const logFunctionRemovedIndented = (functionPath) => Console.log(pipe(AnsiDoc.text(" "), AnsiDoc.cat(pipe(AnsiDoc.char("-"), AnsiDoc.annotate(Ansi.red))), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(toString(functionPath.groupPath) + "."), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.red))])), AnsiDoc.render({ style: "pretty" })));
55
+ const dev = Command.make("dev", {}, () => Effect.gen(function* () {
56
+ const initialFunctionPaths = yield* codegenHandler;
57
+ const pendingRef = yield* Ref.make(pendingInit);
58
+ const signal = yield* Queue.sliding(1);
59
+ yield* Effect.all([
60
+ specFileWatcher(signal, pendingRef),
61
+ confectDirectoryWatcher(signal, pendingRef),
62
+ syncLoop(signal, pendingRef, initialFunctionPaths)
63
+ ], { concurrency: "unbounded" });
64
+ })).pipe(Command.withDescription("Start the Confect development server"));
65
+ const syncLoop = (signal, pendingRef, initialFunctionPaths) => Effect.gen(function* () {
66
+ const functionPathsRef = yield* Ref.make(initialFunctionPaths);
67
+ const changesRef = yield* Ref.make([]);
68
+ return yield* Effect.forever(Effect.gen(function* () {
69
+ yield* Effect.logDebug("Running sync loop...");
70
+ yield* Queue.take(signal);
71
+ const pending = yield* Ref.getAndSet(pendingRef, pendingInit);
72
+ const specResult = yield* Effect.if(pending.specDirty, {
73
+ onTrue: () => loadSpec.pipe(Effect.andThen(Effect.fn(function* (spec) {
74
+ yield* Effect.logDebug("Spec loaded");
75
+ const previous = yield* Ref.get(functionPathsRef);
76
+ const path = yield* Path.Path;
77
+ const convexDirectory = yield* ConvexDirectory.get;
78
+ const current = make(spec);
79
+ const { functionsAdded, functionsRemoved, groupsRemoved, groupsAdded, groupsChanged } = diff(previous, current);
80
+ yield* removeGroups(groupsRemoved);
81
+ const removedChanges = yield* Effect.forEach(groupsRemoved, (gp) => Effect.gen(function* () {
82
+ const relativeModulePath = yield* modulePath(gp);
83
+ return FileChange.GroupModule({
84
+ change: "Removed",
85
+ filePath: path.join(convexDirectory, relativeModulePath),
86
+ functionsAdded: [],
87
+ functionsRemoved: Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp)))
88
+ });
89
+ }));
90
+ yield* writeGroups(spec, groupsAdded);
91
+ const addedChanges = yield* Effect.forEach(groupsAdded, (gp) => Effect.gen(function* () {
92
+ const relativeModulePath = yield* modulePath(gp);
93
+ return FileChange.GroupModule({
94
+ change: "Added",
95
+ filePath: path.join(convexDirectory, relativeModulePath),
96
+ functionsAdded: Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))),
97
+ functionsRemoved: []
98
+ });
99
+ }));
100
+ yield* writeGroups(spec, groupsChanged);
101
+ const changedChanges = yield* Effect.forEach(groupsChanged, (gp) => Effect.gen(function* () {
102
+ const relativeModulePath = yield* modulePath(gp);
103
+ return FileChange.GroupModule({
104
+ change: "Modified",
105
+ filePath: path.join(convexDirectory, relativeModulePath),
106
+ functionsAdded: Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))),
107
+ functionsRemoved: Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp)))
108
+ });
109
+ }));
110
+ yield* Ref.set(functionPathsRef, current);
111
+ return Option.some([
112
+ ...removedChanges,
113
+ ...addedChanges,
114
+ ...changedChanges
115
+ ]);
116
+ })), Effect.catchTag("SpecImportFailedError", () => logFailed("Spec import failed").pipe(Effect.as(Option.none()))), Effect.catchTag("SpecFileDoesNotExportSpecError", () => logFailed("Spec file does not default export a spec").pipe(Effect.as(Option.none())))),
117
+ onFalse: () => Effect.succeed(Option.some([]))
118
+ });
119
+ const specChanges = Option.getOrElse(specResult, () => []);
120
+ const dirtyOptionalFiles = [
121
+ ...pending.httpDirty ? [syncOptionalFile(generateHttp, "http.ts")] : [],
122
+ ...pending.appDirty ? [syncOptionalFile(generateConvexConfig, "convex.config.ts")] : [],
123
+ ...pending.cronsDirty ? [syncOptionalFile(generateCrons, "crons.ts")] : [],
124
+ ...pending.authDirty ? [syncOptionalFile(generateAuthConfig, "auth.config.ts")] : []
125
+ ];
126
+ const optionalChanges = Array.isNonEmptyReadonlyArray(dirtyOptionalFiles) ? yield* pipe(Effect.all(dirtyOptionalFiles, { concurrency: "unbounded" }), Effect.map(Array.getSomes)) : [];
127
+ yield* Ref.update(changesRef, (prev) => [
128
+ ...prev,
129
+ ...specChanges,
130
+ ...optionalChanges
131
+ ]);
132
+ yield* Option.match(specResult, {
133
+ onSome: () => Effect.gen(function* () {
134
+ const pendingSize = yield* Queue.size(signal);
135
+ yield* Effect.when(Effect.gen(function* () {
136
+ yield* logChangeReport(yield* Ref.getAndSet(changesRef, []));
137
+ }), () => pendingSize === 0);
138
+ }),
139
+ onNone: () => Ref.set(changesRef, [])
140
+ });
141
+ }));
142
+ });
143
+ const loadSpec = Effect.gen(function* () {
144
+ const specPathUrl = yield* (yield* Path.Path).toFileUrl(yield* getSpecPath);
145
+ const spec = (yield* Effect.tryPromise({
146
+ try: () => tsx.tsImport(specPathUrl.href, import.meta.url),
147
+ catch: (error) => new SpecImportFailedError({ error })
148
+ })).default;
149
+ if (Spec_exports.isSpec(spec)) return spec;
150
+ else return yield* Effect.fail(new SpecFileDoesNotExportSpecError());
151
+ });
152
+ const getSpecPath = Effect.gen(function* () {
153
+ const path = yield* Path.Path;
154
+ const confectDirectory = yield* ConfectDirectory.get;
155
+ return path.join(confectDirectory, "spec.ts");
156
+ });
157
+ const specFileWatcher = (signal, pendingRef) => Effect.gen(function* () {
158
+ const specPath = yield* getSpecPath;
159
+ yield* pipe(Stream.asyncPush((emit) => Effect.acquireRelease(Effect.promise(async () => {
160
+ const ctx = await esbuild.context({
161
+ entryPoints: [specPath],
162
+ bundle: true,
163
+ write: false,
164
+ metafile: true,
165
+ platform: "node",
166
+ format: "esm",
167
+ logLevel: "silent",
168
+ external: [
169
+ "@confect/core",
170
+ "@confect/server",
171
+ "effect",
172
+ "@effect/*"
173
+ ],
174
+ plugins: [{
175
+ name: "notify-rebuild",
176
+ setup(build) {
177
+ build.onEnd((result) => {
178
+ if (result.errors.length === 0) emit.single();
179
+ else Effect.runPromise(Effect.gen(function* () {
180
+ yield* logFailed("Build errors");
181
+ const formattedMessages = yield* Effect.promise(() => esbuild.formatMessages(result.errors, {
182
+ kind: "error",
183
+ color: true,
184
+ terminalWidth: 80
185
+ }));
186
+ const output = formatBuildErrors(result.errors, formattedMessages);
187
+ yield* Console.error("\n" + output + "\n");
188
+ }));
189
+ });
190
+ }
191
+ }]
192
+ });
193
+ await ctx.watch();
194
+ return ctx;
195
+ }), (ctx) => Effect.promise(() => ctx.dispose()).pipe(Effect.tap(() => Effect.logDebug("esbuild watcher disposed")))), {
196
+ bufferSize: 1,
197
+ strategy: "sliding"
198
+ }), Stream.debounce(Duration.millis(200)), Stream.runForEach(() => Ref.update(pendingRef, (pending) => ({
199
+ ...pending,
200
+ specDirty: true
201
+ })).pipe(Effect.andThen(Queue.offer(signal, void 0)))));
202
+ });
203
+ const formatBuildError = (error, formattedMessage) => {
204
+ const lines = String.split(formattedMessage, "\n");
205
+ const redErrorText = pipe(AnsiDoc.text(error?.text ?? ""), AnsiDoc.annotate(Ansi.red), AnsiDoc.render({ style: "pretty" }));
206
+ return pipe(pipe(Array.findFirstIndex(lines, (l) => pipe(l, String.trim, String.isNonEmpty)), Option.match({
207
+ onNone: () => lines,
208
+ onSome: (idx) => Array.modify(lines, idx, () => redErrorText)
209
+ })), Array.map((l) => pipe(l, String.trim, String.isNonEmpty) ? ` ${l}` : l), Array.join("\n"));
210
+ };
211
+ const formatBuildErrors = (errors, formattedMessages) => pipe(formattedMessages, Array.map((message, i) => formatBuildError(errors[i], message)), Array.join(""), String.trimEnd);
212
+ var SpecFileDoesNotExportSpecError = class extends Schema.TaggedError("SpecFileDoesNotExportSpecError")("SpecFileDoesNotExportSpecError", {}) {};
213
+ var SpecImportFailedError = class extends Schema.TaggedError("SpecImportFailedError")("SpecImportFailedError", { error: Schema.Unknown }) {};
214
+ const syncOptionalFile = (generate, convexFile) => pipe(generate, Effect.andThen(Option.match({
215
+ onSome: ({ change, convexFilePath }) => Match.value(change).pipe(Match.when("Unchanged", () => Effect.succeed(Option.none())), Match.whenOr("Added", "Modified", (addedOrModified) => Effect.succeed(Option.some(FileChange.OptionalFile({
216
+ change: addedOrModified,
217
+ filePath: convexFilePath
218
+ })))), Match.exhaustive),
219
+ onNone: () => Effect.gen(function* () {
220
+ const fs = yield* FileSystem.FileSystem;
221
+ const path = yield* Path.Path;
222
+ const convexDirectory = yield* ConvexDirectory.get;
223
+ const convexFilePath = path.join(convexDirectory, convexFile);
224
+ if (yield* fs.exists(convexFilePath)) {
225
+ yield* fs.remove(convexFilePath);
226
+ return Option.some(FileChange.OptionalFile({
227
+ change: "Removed",
228
+ filePath: convexFilePath
229
+ }));
230
+ } else return Option.none();
231
+ })
232
+ })));
233
+ const optionalConfectFiles = {
234
+ "http.ts": "httpDirty",
235
+ "app.ts": "appDirty",
236
+ "crons.ts": "cronsDirty",
237
+ "auth.ts": "authDirty"
238
+ };
239
+ const confectDirectoryWatcher = (signal, pendingRef) => Effect.gen(function* () {
240
+ const fs = yield* FileSystem.FileSystem;
241
+ const confectDirectory = yield* ConfectDirectory.get;
242
+ yield* pipe(fs.watch(confectDirectory), Stream.runForEach((event) => pipe(Option.fromNullable(optionalConfectFiles[event.path]), Option.match({
243
+ onNone: () => Effect.void,
244
+ onSome: (pendingKey) => pipe(pendingRef, Ref.update((pending) => ({
245
+ ...pending,
246
+ [pendingKey]: true
247
+ })), Effect.andThen(Queue.offer(signal, void 0)))
248
+ }))));
249
+ });
250
+
251
+ //#endregion
252
+ export { dev };
253
+ //# sourceMappingURL=dev.mjs.map