convex-zen 1.9.1 → 1.10.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 (159) hide show
  1. package/dist/cli/generate.d.ts.map +1 -1
  2. package/dist/cli/generate.js +195 -236
  3. package/dist/cli/generate.js.map +1 -1
  4. package/dist/client/helpers.d.ts +1 -1
  5. package/dist/client/helpers.js +1 -1
  6. package/dist/client/index.d.ts +13 -8
  7. package/dist/client/index.d.ts.map +1 -1
  8. package/dist/client/index.js +109 -13
  9. package/dist/client/index.js.map +1 -1
  10. package/dist/component/_generated/api.d.ts +48 -0
  11. package/dist/component/_generated/api.d.ts.map +1 -0
  12. package/{src/component/plugins/admin/_generated/api.ts → dist/component/_generated/api.js} +5 -24
  13. package/dist/component/_generated/api.js.map +1 -0
  14. package/dist/component/_generated/component.d.ts +357 -0
  15. package/dist/component/_generated/component.d.ts.map +1 -0
  16. package/dist/component/_generated/component.js +11 -0
  17. package/dist/component/_generated/component.js.map +1 -0
  18. package/{src/component/plugins/organization/_generated/dataModel.ts → dist/component/_generated/dataModel.d.ts} +4 -18
  19. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  20. package/dist/component/_generated/dataModel.js +11 -0
  21. package/dist/component/_generated/dataModel.js.map +1 -0
  22. package/{src/component/plugins/admin/_generated/server.ts → dist/component/_generated/server.d.ts} +9 -44
  23. package/dist/component/_generated/server.d.ts.map +1 -0
  24. package/dist/component/_generated/server.js +78 -0
  25. package/dist/component/_generated/server.js.map +1 -0
  26. package/dist/component/core/_generated/api.d.ts +46 -0
  27. package/dist/component/core/_generated/api.d.ts.map +1 -0
  28. package/{src/component/plugins/organization/_generated/api.ts → dist/component/core/_generated/api.js} +5 -24
  29. package/dist/component/core/_generated/api.js.map +1 -0
  30. package/dist/component/core/_generated/component.d.ts +117 -0
  31. package/dist/component/core/_generated/component.d.ts.map +1 -0
  32. package/dist/component/core/_generated/component.js +11 -0
  33. package/dist/component/core/_generated/component.js.map +1 -0
  34. package/{src/component/plugins/admin/_generated/dataModel.ts → dist/component/core/_generated/dataModel.d.ts} +4 -18
  35. package/dist/component/core/_generated/dataModel.d.ts.map +1 -0
  36. package/dist/component/core/_generated/dataModel.js +11 -0
  37. package/dist/component/core/_generated/dataModel.js.map +1 -0
  38. package/{src/component/plugins/organization/_generated/server.ts → dist/component/core/_generated/server.d.ts} +9 -44
  39. package/dist/component/core/_generated/server.d.ts.map +1 -0
  40. package/dist/component/core/_generated/server.js +78 -0
  41. package/dist/component/core/_generated/server.js.map +1 -0
  42. package/dist/component/core/convex.config.d.ts +3 -0
  43. package/dist/component/core/convex.config.d.ts.map +1 -0
  44. package/dist/component/core/convex.config.js +4 -0
  45. package/dist/component/core/convex.config.js.map +1 -0
  46. package/dist/component/core/core/users.d.ts +2 -0
  47. package/dist/component/core/core/users.d.ts.map +1 -0
  48. package/dist/component/core/core/users.js +2 -0
  49. package/dist/component/core/core/users.js.map +1 -0
  50. package/dist/component/core/core/verifications.d.ts +2 -0
  51. package/dist/component/core/core/verifications.d.ts.map +1 -0
  52. package/dist/component/core/core/verifications.js +2 -0
  53. package/dist/component/core/core/verifications.js.map +1 -0
  54. package/dist/component/core/gateway.d.ts +2 -0
  55. package/dist/component/core/gateway.d.ts.map +1 -0
  56. package/dist/component/core/gateway.js +2 -0
  57. package/dist/component/core/gateway.js.map +1 -0
  58. package/dist/component/core/providers/oauth.d.ts +2 -0
  59. package/dist/component/core/providers/oauth.d.ts.map +1 -0
  60. package/dist/component/core/providers/oauth.js +2 -0
  61. package/dist/component/core/providers/oauth.js.map +1 -0
  62. package/dist/component/core/schema.d.ts +2 -0
  63. package/dist/component/core/schema.d.ts.map +1 -0
  64. package/dist/component/core/schema.js +2 -0
  65. package/dist/component/core/schema.js.map +1 -0
  66. package/dist/component/core/sessions.d.ts +105 -0
  67. package/dist/component/core/sessions.d.ts.map +1 -0
  68. package/dist/component/core/sessions.js +201 -0
  69. package/dist/component/core/sessions.js.map +1 -0
  70. package/dist/component/core/users.d.ts +193 -0
  71. package/dist/component/core/users.d.ts.map +1 -0
  72. package/dist/component/core/users.js +237 -0
  73. package/dist/component/core/users.js.map +1 -0
  74. package/dist/component/core/verifications.d.ts +85 -0
  75. package/dist/component/core/verifications.d.ts.map +1 -0
  76. package/dist/component/core/verifications.js +133 -0
  77. package/dist/component/core/verifications.js.map +1 -0
  78. package/dist/component/gateway.d.ts +128 -0
  79. package/dist/component/gateway.d.ts.map +1 -0
  80. package/dist/component/gateway.js +162 -0
  81. package/dist/component/gateway.js.map +1 -0
  82. package/dist/component/index.d.ts +5 -0
  83. package/dist/component/index.d.ts.map +1 -0
  84. package/dist/component/index.js +7 -0
  85. package/dist/component/index.js.map +1 -0
  86. package/dist/component/lib/crypto.d.ts +41 -0
  87. package/dist/component/lib/crypto.d.ts.map +1 -0
  88. package/dist/component/lib/crypto.js +152 -0
  89. package/dist/component/lib/crypto.js.map +1 -0
  90. package/dist/component/lib/internalApi.d.ts +58 -0
  91. package/dist/component/lib/internalApi.d.ts.map +1 -0
  92. package/dist/component/lib/internalApi.js +3 -0
  93. package/dist/component/lib/internalApi.js.map +1 -0
  94. package/dist/component/lib/object.d.ts +11 -0
  95. package/dist/component/lib/object.d.ts.map +1 -0
  96. package/dist/component/lib/object.js +4 -0
  97. package/dist/component/lib/object.js.map +1 -0
  98. package/dist/component/lib/rateLimit.d.ts +34 -0
  99. package/dist/component/lib/rateLimit.d.ts.map +1 -0
  100. package/dist/component/lib/rateLimit.js +96 -0
  101. package/dist/component/lib/rateLimit.js.map +1 -0
  102. package/dist/component/lib/validators.d.ts +31 -0
  103. package/dist/component/lib/validators.d.ts.map +1 -0
  104. package/dist/component/lib/validators.js +18 -0
  105. package/dist/component/lib/validators.js.map +1 -0
  106. package/dist/component/plugin.d.ts +59 -0
  107. package/dist/component/plugin.d.ts.map +1 -0
  108. package/dist/component/plugin.js +102 -0
  109. package/dist/component/plugin.js.map +1 -0
  110. package/dist/component/providers/emailPassword.d.ts +104 -0
  111. package/dist/component/providers/emailPassword.d.ts.map +1 -0
  112. package/dist/component/providers/emailPassword.js +363 -0
  113. package/dist/component/providers/emailPassword.js.map +1 -0
  114. package/dist/component/providers/oauth.d.ts +129 -0
  115. package/dist/component/providers/oauth.d.ts.map +1 -0
  116. package/dist/component/providers/oauth.js +349 -0
  117. package/dist/component/providers/oauth.js.map +1 -0
  118. package/dist/component/schema.d.ts +262 -0
  119. package/dist/component/schema.d.ts.map +1 -0
  120. package/dist/component/schema.js +153 -0
  121. package/dist/component/schema.js.map +1 -0
  122. package/dist/types.d.ts +81 -25
  123. package/dist/types.d.ts.map +1 -1
  124. package/dist/types.js +2 -4
  125. package/dist/types.js.map +1 -1
  126. package/package.json +1 -33
  127. package/src/cli/generate.ts +284 -273
  128. package/src/client/helpers.ts +1 -1
  129. package/src/client/index.ts +202 -21
  130. package/src/component/_generated/api.ts +0 -4
  131. package/src/component/core/users.ts +15 -12
  132. package/src/component/gateway.ts +13 -10
  133. package/src/component/index.ts +9 -0
  134. package/src/component/lib/internalApi.ts +1 -45
  135. package/src/component/lib/object.ts +17 -0
  136. package/src/component/plugin.ts +362 -0
  137. package/src/component/providers/emailPassword.ts +3 -3
  138. package/src/component/providers/oauth.ts +51 -31
  139. package/src/types.ts +178 -33
  140. package/dist/client/plugins/admin.d.ts +0 -84
  141. package/dist/client/plugins/admin.d.ts.map +0 -1
  142. package/dist/client/plugins/admin.js +0 -161
  143. package/dist/client/plugins/admin.js.map +0 -1
  144. package/dist/client/plugins/organization.d.ts +0 -216
  145. package/dist/client/plugins/organization.d.ts.map +0 -1
  146. package/dist/client/plugins/organization.js +0 -634
  147. package/dist/client/plugins/organization.js.map +0 -1
  148. package/src/client/plugins/admin.ts +0 -265
  149. package/src/client/plugins/organization.ts +0 -1103
  150. package/src/component/plugins/admin/_generated/component.ts +0 -86
  151. package/src/component/plugins/admin/convex.config.ts +0 -5
  152. package/src/component/plugins/admin/gateway.ts +0 -105
  153. package/src/component/plugins/admin/schema.ts +0 -16
  154. package/src/component/plugins/admin.ts +0 -268
  155. package/src/component/plugins/organization/_generated/component.ts +0 -408
  156. package/src/component/plugins/organization/convex.config.ts +0 -5
  157. package/src/component/plugins/organization/gateway.ts +0 -626
  158. package/src/component/plugins/organization/schema.ts +0 -70
  159. package/src/component/plugins/organization.ts +0 -2111
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAk3CD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAsRzB"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAs2CD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAySzB"}
@@ -1,6 +1,8 @@
1
- import { access, mkdir, readFile, readdir, rm, writeFile, } from "node:fs/promises";
1
+ import { access, mkdir, readFile, readdir, rm, stat, writeFile, } from "node:fs/promises";
2
+ import { createRequire } from "node:module";
2
3
  import path from "node:path";
3
- import { pathToFileURL } from "node:url";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import { collectPluginGatewayMetadata } from "../component/plugin";
4
6
  const GENERATED_MARKER = "// @generated by convex-zen generate. DO NOT EDIT.";
5
7
  const RESERVED_CORE_FUNCTION_NAMES = new Set([
6
8
  "getSession",
@@ -9,6 +11,7 @@ const RESERVED_CORE_FUNCTION_NAMES = new Set([
9
11
  "plugin",
10
12
  "core",
11
13
  ]);
14
+ const nodeRequire = createRequire(import.meta.url);
12
15
  function normalizeContent(content) {
13
16
  const trimmed = content.trimEnd();
14
17
  return trimmed.endsWith("\n") ? trimmed : `${trimmed}\n`;
@@ -22,6 +25,90 @@ async function fileExists(filePath) {
22
25
  return false;
23
26
  }
24
27
  }
28
+ function splitPackageSpecifier(moduleSpecifier) {
29
+ if (moduleSpecifier.startsWith("@")) {
30
+ const [scope, name, ...rest] = moduleSpecifier.split("/");
31
+ return {
32
+ packageName: [scope, name].filter(Boolean).join("/"),
33
+ subpath: rest.join("/"),
34
+ };
35
+ }
36
+ const [name, ...rest] = moduleSpecifier.split("/");
37
+ return {
38
+ packageName: name ?? moduleSpecifier,
39
+ subpath: rest.join("/"),
40
+ };
41
+ }
42
+ function readExportTarget(exportsField, key) {
43
+ if (!exportsField || typeof exportsField !== "object") {
44
+ return null;
45
+ }
46
+ const record = exportsField;
47
+ const entry = record[key];
48
+ if (!entry) {
49
+ return null;
50
+ }
51
+ if (typeof entry === "string") {
52
+ return entry;
53
+ }
54
+ if (typeof entry === "object" && entry !== null) {
55
+ const importTarget = entry.import;
56
+ if (typeof importTarget === "string") {
57
+ return importTarget;
58
+ }
59
+ const defaultTarget = entry.default;
60
+ if (typeof defaultTarget === "string") {
61
+ return defaultTarget;
62
+ }
63
+ const typesTarget = entry.types;
64
+ if (typeof typesTarget === "string") {
65
+ return typesTarget;
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+ async function findWorkspacePackage(authSource, packageName) {
71
+ const workspaceRoot = (await findWorkspaceRoot(path.dirname(authSource.absolutePath))) ??
72
+ (await findWorkspaceRoot(path.dirname(fileURLToPath(import.meta.url))));
73
+ if (!workspaceRoot) {
74
+ return null;
75
+ }
76
+ const packagesDir = path.join(workspaceRoot, "packages");
77
+ const packageDirs = await readdir(packagesDir).catch(() => []);
78
+ for (const packageDirName of packageDirs) {
79
+ const dir = path.join(packagesDir, packageDirName);
80
+ const packageJsonPath = path.join(dir, "package.json");
81
+ if (!(await fileExists(packageJsonPath))) {
82
+ continue;
83
+ }
84
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
85
+ if (packageJson.name !== packageName) {
86
+ continue;
87
+ }
88
+ return {
89
+ dir,
90
+ name: packageName,
91
+ packageJson,
92
+ };
93
+ }
94
+ return null;
95
+ }
96
+ async function resolveWorkspacePackageImport(authSource, moduleSpecifier) {
97
+ const { packageName, subpath } = splitPackageSpecifier(moduleSpecifier);
98
+ const workspacePackage = await findWorkspacePackage(authSource, packageName);
99
+ if (!workspacePackage) {
100
+ return null;
101
+ }
102
+ const exportKey = subpath.length > 0 ? `./${subpath}` : ".";
103
+ const exportTarget = readExportTarget(workspacePackage.packageJson.exports, exportKey) ??
104
+ (subpath.length === 0 && typeof workspacePackage.packageJson.main === "string"
105
+ ? workspacePackage.packageJson.main
106
+ : null);
107
+ if (!exportTarget) {
108
+ return null;
109
+ }
110
+ return pathToFileURL(path.resolve(workspacePackage.dir, exportTarget)).href;
111
+ }
25
112
  function isGeneratedFile(content) {
26
113
  return content.startsWith(GENERATED_MARKER);
27
114
  }
@@ -121,19 +208,71 @@ function toGeneratedImportPath(sourceFileAbsolutePath, targetFileAbsolutePath) {
121
208
  const normalized = relativeImport.replace(/\\/g, "/").replace(/\.ts$/, "");
122
209
  return normalized.startsWith(".") ? normalized : `./${normalized}`;
123
210
  }
124
- async function resolveGeneratedComponentImportPath(authSource, pluginModuleSpecifier, componentImportPath) {
125
- if (!componentImportPath.startsWith(".")) {
126
- return componentImportPath;
211
+ async function resolveGeneratedComponentImportPath(authSource, pluginModuleSpecifier, pluginDefinition) {
212
+ if (!pluginModuleSpecifier.startsWith(".") && !path.isAbsolute(pluginModuleSpecifier)) {
213
+ return `${pluginModuleSpecifier}/convex.config`;
214
+ }
215
+ if (pluginModuleSpecifier.startsWith("convex-zen/plugins/")) {
216
+ return `${pluginModuleSpecifier}/convex.config`;
127
217
  }
128
- const pluginModulePath = pluginModuleSpecifier.startsWith(".")
129
- ? path.resolve(path.dirname(authSource.absolutePath), pluginModuleSpecifier)
130
- : null;
218
+ const pluginModulePath = await resolvePluginModulePath(authSource, pluginModuleSpecifier);
131
219
  if (!pluginModulePath) {
132
- return componentImportPath;
220
+ throw new Error(`Could not resolve plugin module path for "${pluginDefinition.id}" from "${pluginModuleSpecifier}".`);
133
221
  }
134
- const componentAbsolutePath = path.resolve(path.dirname(pluginModulePath), componentImportPath);
222
+ if (pluginModulePath.includes(`${path.sep}src${path.sep}client${path.sep}plugins${path.sep}`) ||
223
+ pluginModulePath.includes(`${path.sep}src${path.sep}plugins${path.sep}`)) {
224
+ return `convex-zen/plugins/${pluginDefinition.id}/convex.config`;
225
+ }
226
+ const componentAbsolutePath = path.resolve(path.dirname(pluginModulePath), "convex.config.ts");
135
227
  return toGeneratedImportPath(path.join(path.dirname(authSource.absolutePath), "zen", "component", "convex.config.ts"), componentAbsolutePath);
136
228
  }
229
+ async function resolveGatewaySourcePath(authSource, pluginModuleSpecifier, pluginDefinition) {
230
+ if (!pluginModuleSpecifier.startsWith(".") && !path.isAbsolute(pluginModuleSpecifier)) {
231
+ return `${pluginModuleSpecifier}/gateway`;
232
+ }
233
+ if (pluginModuleSpecifier.startsWith("convex-zen/plugins/")) {
234
+ return `${pluginModuleSpecifier}/gateway`;
235
+ }
236
+ const pluginModulePath = await resolvePluginModulePath(authSource, pluginModuleSpecifier);
237
+ if (!pluginModulePath) {
238
+ throw new Error(`Could not resolve plugin module path for "${pluginDefinition.id}" from "${pluginModuleSpecifier}".`);
239
+ }
240
+ if (pluginModulePath.includes(`${path.sep}src${path.sep}client${path.sep}plugins${path.sep}`) ||
241
+ pluginModulePath.includes(`${path.sep}src${path.sep}plugins${path.sep}`)) {
242
+ return `convex-zen/plugins/${pluginDefinition.id}/gateway`;
243
+ }
244
+ return path.resolve(path.dirname(pluginModulePath), "gateway.ts");
245
+ }
246
+ async function resolvePluginModulePath(authSource, pluginModuleSpecifier) {
247
+ if (path.isAbsolute(pluginModuleSpecifier)) {
248
+ return pluginModuleSpecifier;
249
+ }
250
+ if (!pluginModuleSpecifier.startsWith(".")) {
251
+ if (pluginModuleSpecifier === "convex-zen") {
252
+ return null;
253
+ }
254
+ const moduleSpecifier = await resolveImportSpecifier(authSource, pluginModuleSpecifier);
255
+ return moduleSpecifier.startsWith("file:")
256
+ ? fileURLToPath(moduleSpecifier)
257
+ : null;
258
+ }
259
+ const resolved = path.resolve(path.dirname(authSource.absolutePath), pluginModuleSpecifier);
260
+ if (await fileExists(resolved)) {
261
+ const resolvedStats = await stat(resolved);
262
+ if (resolvedStats.isFile()) {
263
+ return resolved;
264
+ }
265
+ }
266
+ const indexPath = path.join(resolved, "index.ts");
267
+ if (await fileExists(indexPath)) {
268
+ return indexPath;
269
+ }
270
+ const directTsPath = `${resolved}.ts`;
271
+ if (await fileExists(directTsPath)) {
272
+ return directTsPath;
273
+ }
274
+ return resolved;
275
+ }
137
276
  async function resolveImportSpecifier(authSource, moduleSpecifier) {
138
277
  if (moduleSpecifier.startsWith(".")) {
139
278
  return pathToFileURL(path.resolve(path.dirname(authSource.absolutePath), moduleSpecifier)).href;
@@ -155,13 +294,25 @@ async function resolveImportSpecifier(authSource, moduleSpecifier) {
155
294
  : subpath === "core/convex.config"
156
295
  ? path.join(workspaceRoot, "packages", "convex-zen", "src", "component", "core", "convex.config.ts")
157
296
  : subpath.startsWith("plugins/") && subpath.endsWith("/convex.config")
158
- ? path.join(workspaceRoot, "packages", "convex-zen", "src", "component", subpath.replace(/\/convex\.config$/, ""), "convex.config.ts")
159
- : path.join(workspaceRoot, "packages", "convex-zen", "src", "client", `${subpath}.ts`);
297
+ ? path.join(workspaceRoot, "packages", "convex-zen", "src", "plugins", subpath.replace(/^plugins\//, "").replace(/\/convex\.config$/, ""), "convex.config.ts")
298
+ : subpath.startsWith("plugins/") && subpath.endsWith("/gateway")
299
+ ? path.join(workspaceRoot, "packages", "convex-zen", "src", "plugins", subpath.replace(/^plugins\//, "").replace(/\/gateway$/, ""), "gateway.ts")
300
+ : path.join(workspaceRoot, "packages", "convex-zen", "src", "client", `${subpath}.ts`);
160
301
  if (await fileExists(mapped)) {
161
302
  return pathToFileURL(mapped).href;
162
303
  }
163
304
  }
164
305
  }
306
+ if (!moduleSpecifier.startsWith(".")) {
307
+ const workspaceImport = await resolveWorkspacePackageImport(authSource, moduleSpecifier);
308
+ if (workspaceImport) {
309
+ return workspaceImport;
310
+ }
311
+ const resolved = nodeRequire.resolve(moduleSpecifier, {
312
+ paths: [path.dirname(authSource.absolutePath)],
313
+ });
314
+ return pathToFileURL(resolved).href;
315
+ }
165
316
  return moduleSpecifier;
166
317
  }
167
318
  async function findWorkspaceRoot(startDir) {
@@ -188,10 +339,13 @@ async function loadPluginDefinitions(authSource, authSourceContents) {
188
339
  throw new Error(`Could not resolve plugin factory "${factoryId}" from ${authSource.relativePath}.`);
189
340
  }
190
341
  const definition = await importPluginDefinition(authSource, binding);
342
+ const gatewayFunctions = collectPluginGatewayMetadata(definition.gateway);
191
343
  definitions.push({
192
344
  definition,
193
- componentImportPath: await resolveGeneratedComponentImportPath(authSource, binding.moduleSpecifier, definition.component.importPath),
194
- childName: definition.component.childName ?? definition.id,
345
+ componentImportPath: await resolveGeneratedComponentImportPath(authSource, binding.moduleSpecifier, definition),
346
+ gatewaySourcePath: await resolveGatewaySourcePath(authSource, binding.moduleSpecifier, definition),
347
+ childName: `${definition.id}Component`,
348
+ gatewayFunctions,
195
349
  });
196
350
  }
197
351
  return definitions;
@@ -575,113 +729,22 @@ export const getUserById = query({
575
729
  ${oauthExports}
576
730
  `);
577
731
  }
578
- function addInternalActorFieldsToArgsSource(argsSource, options) {
579
- const actorFields = [
580
- " actorUserId: v.optional(v.string()),",
581
- ...(options?.includeActorEmail === true
582
- ? [" actorEmail: v.optional(v.string()),"]
583
- : []),
584
- ];
585
- if (argsSource.trim() === "{}") {
586
- return `{\n${actorFields.join("\n")}\n }`;
587
- }
588
- return argsSource.replace("{", `{\n${actorFields.join("\n")}\n`);
732
+ function resolveGatewayImportPathForGeneratedFile(generatedFileAbsolutePath, gatewaySourcePath) {
733
+ return gatewaySourcePath.startsWith("/")
734
+ ? toGeneratedImportPath(generatedFileAbsolutePath, gatewaySourcePath)
735
+ : gatewaySourcePath;
589
736
  }
590
- function renderComponentPluginFacadeFile(options) {
737
+ function renderPluginFacadeFile(options) {
591
738
  const pluginName = options.pluginDefinition.id;
592
- const publicFunctions = options.pluginDefinition.publicFunctions;
593
- if (!publicFunctions) {
594
- throw new Error(`Plugin "${pluginName}" is missing public function metadata.`);
595
- }
596
- const kinds = new Set(Object.values(publicFunctions.functions).map((fn) => fn.kind));
739
+ const kinds = new Set(Object.values(options.gatewayFunctions).map((fn) => fn.kind));
597
740
  const serverImports = [...kinds].sort().join(", ");
598
- const needsActorHelper = Object.values(publicFunctions.functions).some((fn) => fn.auth === "actor" || fn.auth === "optionalActor");
599
- const preamble = publicFunctions.preambleSource
600
- ? `${publicFunctions.preambleSource}\n\n`
601
- : "";
602
- const actorHelper = needsActorHelper
603
- ? `async function requireActorUserId(ctx: { auth: { getUserIdentity: () => Promise<{ subject?: string } | null> } }): Promise<string> {
604
- const identity = await ctx.auth.getUserIdentity();
605
- const actorUserId = identity?.subject;
606
- if (!actorUserId) {
607
- throw new Error("Unauthorized: missing identity subject");
608
- }
609
- return actorUserId;
610
- }
611
-
612
- `
613
- : "";
614
- const actorEmailMethods = pluginName === "organization"
615
- ? new Set([
616
- "listIncomingInvitations",
617
- "acceptInvitation",
618
- "acceptIncomingInvitation",
619
- "declineIncomingInvitation",
620
- ])
621
- : new Set();
622
- const actorEmailHelper = actorEmailMethods.size > 0
623
- ? `async function resolveActorEmail(ctx: unknown): Promise<string | undefined> {
624
- const actor = await auth.user.safeGet(ctx as { runQuery(fn: unknown, args: Record<string, unknown>): Promise<unknown> });
625
- return actor?.email;
626
- }
627
-
628
- `
629
- : "";
630
- const functionSource = Object.entries(publicFunctions.functions)
741
+ const functionSource = Object.entries(options.gatewayFunctions)
631
742
  .map(([functionName, fn]) => {
632
- const runtimeAccess = `auth.plugins.${pluginName}`;
633
- const kindFactory = fn.kind;
634
- const argsSource = fn.auth === "actor" || fn.auth === "optionalActor"
635
- ? addInternalActorFieldsToArgsSource(fn.argsSource, {
636
- includeActorEmail: actorEmailMethods.has(functionName),
637
- })
638
- : fn.argsSource;
639
- if (fn.auth === "public") {
640
- return `export const ${functionName} = ${kindFactory}({
641
- args: ${argsSource},
642
- handler: async (ctx, args) => {
643
- return ${runtimeAccess}.${fn.runtimeMethod}(ctx, args as any);
644
- },
645
- });`;
646
- }
647
- if (fn.auth === "optionalActor") {
648
- const optionalActorEmail = actorEmailMethods.has(functionName)
649
- ? ` const actorEmail = await resolveActorEmail(ctx);\n`
650
- : "";
651
- const optionalActorEmailSpread = actorEmailMethods.has(functionName)
652
- ? ` ...(actorEmail ? { actorEmail } : {}),\n`
653
- : "";
654
- return `export const ${functionName} = ${kindFactory}({
655
- args: ${argsSource},
656
- handler: async (ctx, args) => {
657
- const identity = await ctx.auth.getUserIdentity();
658
- const actorUserId = identity?.subject;
659
- if (!actorUserId) {
660
- return false;
661
- }
662
- ${optionalActorEmail} const { actorUserId: _ignoredActorUserId, ...inputArgs } = args as Record<string, unknown>;
663
- return ${runtimeAccess}.${fn.runtimeMethod}(ctx, {
664
- ...inputArgs,
665
- actorUserId,
666
- ${optionalActorEmailSpread} } as any);
667
- },
668
- });`;
669
- }
670
- const actorEmailResolution = actorEmailMethods.has(functionName)
671
- ? ` const actorEmail = await resolveActorEmail(ctx);\n`
672
- : "";
673
- const actorEmailSpread = actorEmailMethods.has(functionName)
674
- ? ` ...(actorEmail ? { actorEmail } : {}),\n`
675
- : "";
676
- return `export const ${functionName} = ${kindFactory}({
677
- args: ${argsSource},
743
+ const runtimeAccess = `auth.plugins.${pluginName}.${functionName}`;
744
+ return `export const ${functionName} = ${fn.kind}({
745
+ args: getPublicPluginFunctionArgs(pluginGateway.${functionName}, ${JSON.stringify(functionName)}),
678
746
  handler: async (ctx, args) => {
679
- const actorUserId = await requireActorUserId(ctx);
680
- ${actorEmailResolution} const { actorUserId: _ignoredActorUserId, ...inputArgs } = args as Record<string, unknown>;
681
- return ${runtimeAccess}.${fn.runtimeMethod}(ctx, {
682
- ...inputArgs,
683
- actorUserId,
684
- ${actorEmailSpread} } as any);
747
+ return ${runtimeAccess}(ctx, args);
685
748
  },
686
749
  });`;
687
750
  })
@@ -691,11 +754,12 @@ ${actorEmailSpread} } as any);
691
754
  ? `import { auth } from ${JSON.stringify(options.runtimeImportPath)};`
692
755
  : `import { ${runtimeImportName} as auth } from ${JSON.stringify(options.runtimeImportPath)};`;
693
756
  return normalizeContent(`${GENERATED_MARKER}
694
- import { v } from "convex/values";
695
757
  import { ${serverImports} } from ${JSON.stringify(options.serverImportPath)};
758
+ import { getPublicPluginFunctionArgs } from "convex-zen/component";
759
+ import * as pluginGateway from ${JSON.stringify(options.gatewayImportPath)};
696
760
  ${runtimeImport}
697
761
 
698
- ${actorHelper}${actorEmailHelper}${preamble}${functionSource}
762
+ ${functionSource}
699
763
  `);
700
764
  }
701
765
  function renderCoreFile(options) {
@@ -881,117 +945,6 @@ export const currentUser = query({
881
945
  ${oauthExports}
882
946
  `);
883
947
  }
884
- function renderPluginFile(options) {
885
- const pluginName = options.pluginDefinition.id;
886
- const publicFunctions = options.pluginDefinition.publicFunctions;
887
- if (!publicFunctions) {
888
- throw new Error(`Plugin "${pluginName}" is missing public function metadata.`);
889
- }
890
- const kinds = new Set(Object.values(publicFunctions.functions).map((fn) => fn.kind));
891
- const serverImports = [...kinds].sort().join(", ");
892
- const needsActorHelper = Object.values(publicFunctions.functions).some((fn) => fn.auth === "actor" || fn.auth === "optionalActor");
893
- const preamble = publicFunctions.preambleSource
894
- ? `${publicFunctions.preambleSource}\n\n`
895
- : "";
896
- const actorHelper = needsActorHelper
897
- ? `async function requireActorUserId(ctx: { auth: { getUserIdentity: () => Promise<{ subject?: string } | null> } }): Promise<string> {
898
- const identity = await ctx.auth.getUserIdentity();
899
- const actorUserId = identity?.subject;
900
- if (!actorUserId) {
901
- throw new Error("Unauthorized: missing identity subject");
902
- }
903
- return actorUserId;
904
- }
905
-
906
- `
907
- : "";
908
- const actorEmailMethods = pluginName === "organization"
909
- ? new Set([
910
- "listIncomingInvitations",
911
- "acceptInvitation",
912
- "acceptIncomingInvitation",
913
- "declineIncomingInvitation",
914
- ])
915
- : new Set();
916
- const actorEmailHelper = actorEmailMethods.size > 0
917
- ? `async function resolveActorEmail(ctx: unknown): Promise<string | undefined> {
918
- const actor = await auth.user.safeGet(ctx as { runQuery(fn: unknown, args: Record<string, unknown>): Promise<unknown> });
919
- return actor?.email;
920
- }
921
-
922
- `
923
- : "";
924
- const functionSource = Object.entries(publicFunctions.functions)
925
- .map(([functionName, fn]) => {
926
- const runtimeAccess = `auth.plugins.${pluginName}`;
927
- const kindFactory = fn.kind;
928
- const argsSource = fn.auth === "actor" || fn.auth === "optionalActor"
929
- ? addInternalActorFieldsToArgsSource(fn.argsSource, {
930
- includeActorEmail: actorEmailMethods.has(functionName),
931
- })
932
- : fn.argsSource;
933
- if (fn.auth === "public") {
934
- return `export const ${functionName} = ${kindFactory}({
935
- args: ${argsSource},
936
- handler: async (ctx, args) => {
937
- return ${runtimeAccess}.${fn.runtimeMethod}(ctx, args as any);
938
- },
939
- });`;
940
- }
941
- if (fn.auth === "optionalActor") {
942
- const optionalActorEmail = actorEmailMethods.has(functionName)
943
- ? `
944
- const actorEmail = await resolveActorEmail(ctx);`
945
- : "";
946
- const optionalActorEmailSpread = actorEmailMethods.has(functionName)
947
- ? `
948
- ...(actorEmail ? { actorEmail } : {}),`
949
- : "";
950
- return `export const ${functionName} = ${kindFactory}({
951
- args: ${argsSource},
952
- handler: async (ctx, args) => {
953
- const identity = await ctx.auth.getUserIdentity();
954
- const actorUserId = identity?.subject;
955
- if (!actorUserId) {
956
- return false;
957
- }
958
- ${optionalActorEmail}
959
- const { actorUserId: _ignoredActorUserId, ...inputArgs } = args as Record<string, unknown>;
960
- return ${runtimeAccess}.${fn.runtimeMethod}(ctx, {
961
- ...inputArgs,
962
- actorUserId,
963
- ${optionalActorEmailSpread}
964
- } as any);
965
- },
966
- });`;
967
- }
968
- const actorEmailResolution = actorEmailMethods.has(functionName)
969
- ? ` const actorEmail = await resolveActorEmail(ctx);\n`
970
- : "";
971
- const actorEmailSpread = actorEmailMethods.has(functionName)
972
- ? ` ...(actorEmail ? { actorEmail } : {}),\n`
973
- : "";
974
- return `export const ${functionName} = ${kindFactory}({
975
- args: ${argsSource},
976
- handler: async (ctx, args) => {
977
- const actorUserId = await requireActorUserId(ctx);
978
- ${actorEmailResolution} const { actorUserId: _ignoredActorUserId, ...inputArgs } = args as Record<string, unknown>;
979
- return ${runtimeAccess}.${fn.runtimeMethod}(ctx, {
980
- ...inputArgs,
981
- actorUserId,
982
- ${actorEmailSpread} } as any);
983
- },
984
- });`;
985
- })
986
- .join("\n\n");
987
- return normalizeContent(`${GENERATED_MARKER}
988
- import { v } from "convex/values";
989
- import { ${serverImports} } from "../../_generated/server";
990
- import { auth } from "../_generated/auth";
991
-
992
- ${actorHelper}${actorEmailHelper}${preamble}${functionSource}
993
- `);
994
- }
995
948
  function parseFunctionKinds(source) {
996
949
  const result = {};
997
950
  const pattern = /export\s+const\s+([A-Za-z0-9_]+)\s*=\s*(query|mutation|action)\s*\(/g;
@@ -1244,24 +1197,30 @@ export async function generateAuthFunctions(options) {
1244
1197
  const generatedPluginSources = new Map();
1245
1198
  const coreMeta = parseFunctionKinds(coreContent);
1246
1199
  for (const pluginDefinition of pluginDefinitions) {
1247
- const pluginContent = renderComponentPluginFacadeFile({
1200
+ const pluginAbsolutePath = path.join(pluginDir, `${pluginDefinition.definition.id}.ts`);
1201
+ const pluginContent = renderPluginFacadeFile({
1248
1202
  pluginDefinition: pluginDefinition.definition,
1203
+ gatewayFunctions: pluginDefinition.gatewayFunctions,
1204
+ gatewayImportPath: resolveGatewayImportPathForGeneratedFile(pluginAbsolutePath, pluginDefinition.gatewaySourcePath),
1249
1205
  serverImportPath: "../../_generated/server",
1250
1206
  runtimeImportPath: "../_generated/auth",
1251
1207
  });
1252
1208
  filesToGenerate.push({
1253
- absolutePath: path.join(pluginDir, `${pluginDefinition.definition.id}.ts`),
1209
+ absolutePath: pluginAbsolutePath,
1254
1210
  relativePath: path.join("convex", "zen", "plugin", `${pluginDefinition.definition.id}.ts`),
1255
1211
  content: pluginContent,
1256
1212
  });
1257
1213
  generatedPluginSources.set(pluginDefinition.definition.id, pluginContent);
1258
- const zenPluginContent = renderComponentPluginFacadeFile({
1214
+ const componentGatewayAbsolutePath = path.join(componentDir, pluginDefinition.definition.id, "gateway.ts");
1215
+ const zenPluginContent = renderPluginFacadeFile({
1259
1216
  pluginDefinition: pluginDefinition.definition,
1217
+ gatewayFunctions: pluginDefinition.gatewayFunctions,
1218
+ gatewayImportPath: resolveGatewayImportPathForGeneratedFile(componentGatewayAbsolutePath, pluginDefinition.gatewaySourcePath),
1260
1219
  serverImportPath: "../_generated/server",
1261
1220
  runtimeImportPath: "../_runtime",
1262
1221
  });
1263
1222
  filesToGenerate.push({
1264
- absolutePath: path.join(componentDir, pluginDefinition.definition.id, "gateway.ts"),
1223
+ absolutePath: componentGatewayAbsolutePath,
1265
1224
  relativePath: path.join("convex", "zen", "component", pluginDefinition.definition.id, "gateway.ts"),
1266
1225
  content: zenPluginContent,
1267
1226
  });
@@ -1271,10 +1230,10 @@ export async function generateAuthFunctions(options) {
1271
1230
  }
1272
1231
  await deleteGeneratedFileIfExists(path.join(zenDir, "admin.ts"), path.join("convex", "zen", "admin.ts"), options, result);
1273
1232
  const pluginMeta = {};
1274
- for (const [pluginName, source] of generatedPluginSources) {
1275
- const kinds = parseFunctionKinds(source);
1233
+ for (const pluginDefinition of pluginDefinitions) {
1234
+ const kinds = Object.fromEntries(Object.entries(pluginDefinition.gatewayFunctions).map(([functionName, metadata]) => [functionName, metadata.kind]));
1276
1235
  if (Object.keys(kinds).length > 0) {
1277
- pluginMeta[pluginName] = kinds;
1236
+ pluginMeta[pluginDefinition.definition.id] = kinds;
1278
1237
  }
1279
1238
  }
1280
1239
  if (await fileExists(pluginDir)) {