kitcn 0.15.7 → 0.15.9

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.
@@ -7068,8 +7068,8 @@ const READ_OPTIONAL_RUNTIME_ENV_PROPERTY_RE = /\breadOptionalRuntimeEnv\s*:/m;
7068
7068
  const READ_OPTIONAL_RUNTIME_ENV_RE = /(\s*readOptionalRuntimeEnv\s*:\s*\[)([\s\S]*?)(\]\s*,?)/m;
7069
7069
  const LEADING_WHITESPACE_RE = /^\s*/;
7070
7070
  const STRING_LITERAL_ARRAY_ENTRY_RE = /^(['"])([^'"]+)\1$/;
7071
- const WHITESPACE_RE$1 = /\s/;
7072
- const findMatchingObjectBraceIndex = (source, openIndex) => {
7071
+ const WHITESPACE_RE$2 = /\s/;
7072
+ const findMatchingObjectBraceIndex$1 = (source, openIndex) => {
7073
7073
  let depth = 0;
7074
7074
  let quote;
7075
7075
  let escaped = false;
@@ -7188,7 +7188,7 @@ const upsertReadOptionalRuntimeEnvOption = (source, keys) => {
7188
7188
  const createEnvMatch = source.match(CREATE_ENV_OPTIONS_START_RE);
7189
7189
  if (!createEnvMatch || createEnvMatch.index === void 0) throw new Error("Expected env helper to call `createEnv({ ... })` before adding `readOptionalRuntimeEnv`.");
7190
7190
  const insertIndex = createEnvMatch.index + createEnvMatch[0].lastIndexOf("{") + 1;
7191
- const closingBraceIndex = findMatchingObjectBraceIndex(source, insertIndex - 1);
7191
+ const closingBraceIndex = findMatchingObjectBraceIndex$1(source, insertIndex - 1);
7192
7192
  if (closingBraceIndex === -1) throw new Error("Expected env helper `createEnv` options object to close before adding `readOptionalRuntimeEnv`.");
7193
7193
  const existingOptionsBody = source.slice(insertIndex, closingBraceIndex);
7194
7194
  const existingMatch = existingOptionsBody.match(READ_OPTIONAL_RUNTIME_ENV_RE);
@@ -7378,9 +7378,9 @@ const getPlannedFileContent = (files, absolutePath) => {
7378
7378
  const normalizedPath = normalizePath$1(relative(process.cwd(), absolutePath));
7379
7379
  return files?.find((file) => file.path === normalizedPath)?.content;
7380
7380
  };
7381
- const skipWhitespace$1 = (source, start) => {
7381
+ const skipWhitespace$2 = (source, start) => {
7382
7382
  let index = start;
7383
- while (index < source.length && WHITESPACE_RE$1.test(source[index] ?? "")) index += 1;
7383
+ while (index < source.length && WHITESPACE_RE$2.test(source[index] ?? "")) index += 1;
7384
7384
  return index;
7385
7385
  };
7386
7386
  const findBalancedParenEnd$1 = (source, openParenIndex) => {
@@ -7418,7 +7418,7 @@ const findSchemaExtensionInsertIndex = (source) => {
7418
7418
  };
7419
7419
  const cursor = defineSchemaCloseParenIndex + 1;
7420
7420
  while (cursor < source.length) {
7421
- const nextSegmentIndex = skipWhitespace$1(source, cursor);
7421
+ const nextSegmentIndex = skipWhitespace$2(source, cursor);
7422
7422
  if (source.startsWith(".relations(", nextSegmentIndex) || source.startsWith(".triggers(", nextSegmentIndex)) return {
7423
7423
  closeParenIndex: -1,
7424
7424
  hasExtend: false,
@@ -7662,7 +7662,7 @@ const createTypeScriptProxy = () => new Proxy({}, { get(_target, property) {
7662
7662
  const OBJECT_ENTRY_INDENT = " ";
7663
7663
  const LEADING_INDENT_RE = /^[ \t]*/;
7664
7664
  const LEGACY_MANAGED_COMMENT_RE = /^[ \t]*\/\* kitcn-managed [^*]+ \*\/\n?/gm;
7665
- const WHITESPACE_RE = /\s/;
7665
+ const WHITESPACE_RE$1 = /\s/;
7666
7666
  const ts$2 = createTypeScriptProxy();
7667
7667
  let printer = null;
7668
7668
  const getPrinter = () => {
@@ -8003,9 +8003,9 @@ const updateTablesObject = (source, registrations) => {
8003
8003
  if (!changed) return source;
8004
8004
  return replaceRange(source, info.object.getStart(info.sourceFile), info.object.end, renderObjectLiteral(getIndentAt(source, info.object.getStart(info.sourceFile)), existingEntries));
8005
8005
  };
8006
- const skipWhitespace = (source, start) => {
8006
+ const skipWhitespace$1 = (source, start) => {
8007
8007
  let cursor = start;
8008
- while (cursor < source.length && WHITESPACE_RE.test(source[cursor])) cursor += 1;
8008
+ while (cursor < source.length && WHITESPACE_RE$1.test(source[cursor])) cursor += 1;
8009
8009
  return cursor;
8010
8010
  };
8011
8011
  const findBalancedParenEnd = (source, openParenIndex) => {
@@ -8029,7 +8029,7 @@ const findRelationsInsertIndex = (source) => {
8029
8029
  if (defineSchemaCloseParenIndex < 0) return -1;
8030
8030
  let cursor = defineSchemaCloseParenIndex + 1;
8031
8031
  while (cursor < source.length) {
8032
- const nextSegmentIndex = skipWhitespace(source, cursor);
8032
+ const nextSegmentIndex = skipWhitespace$1(source, cursor);
8033
8033
  if (source.startsWith(".relations(", nextSegmentIndex)) return nextSegmentIndex;
8034
8034
  if (source.startsWith(".triggers(", nextSegmentIndex)) return nextSegmentIndex;
8035
8035
  if (!source.startsWith(".extend(", nextSegmentIndex)) return nextSegmentIndex;
@@ -13646,6 +13646,8 @@ const INIT_NEXT_IMPORT_SEMICOLON_RE = /^\s*import .*;\s*$/m;
13646
13646
  const INIT_NEXT_TRAILING_NEWLINES_RE = /\n*$/;
13647
13647
  const INIT_NEXT_PROVIDERS_IMPORT_RE = /from ['"]@\/components\/providers['"]/;
13648
13648
  const INIT_NEXT_CHILDREN_SLOT_RE = /\{\s*children\s*\}/g;
13649
+ const IDENTIFIER_CHAR_RE = /[A-Za-z0-9_$]/;
13650
+ const WHITESPACE_RE = /\s/;
13649
13651
  const VALID_SCOPES = new Set([
13650
13652
  "all",
13651
13653
  "auth",
@@ -14741,9 +14743,248 @@ function patchInitReactMainContent(source) {
14741
14743
  }
14742
14744
  return nextSource.endsWith("\n") ? nextSource : `${nextSource}\n`;
14743
14745
  }
14746
+ function findMatchingObjectBraceIndex(source, openIndex) {
14747
+ let depth = 0;
14748
+ let quote;
14749
+ let escaped = false;
14750
+ let lineComment = false;
14751
+ let blockComment = false;
14752
+ for (let index = openIndex; index < source.length; index++) {
14753
+ const char = source[index];
14754
+ const nextChar = source[index + 1];
14755
+ if (lineComment) {
14756
+ if (char === "\n" || char === "\r") lineComment = false;
14757
+ continue;
14758
+ }
14759
+ if (blockComment) {
14760
+ if (char === "*" && nextChar === "/") {
14761
+ blockComment = false;
14762
+ index++;
14763
+ }
14764
+ continue;
14765
+ }
14766
+ if (quote) {
14767
+ if (escaped) {
14768
+ escaped = false;
14769
+ continue;
14770
+ }
14771
+ if (char === "\\") {
14772
+ escaped = true;
14773
+ continue;
14774
+ }
14775
+ if (char === quote) quote = void 0;
14776
+ continue;
14777
+ }
14778
+ if (char === "/" && nextChar === "/") {
14779
+ lineComment = true;
14780
+ index++;
14781
+ continue;
14782
+ }
14783
+ if (char === "/" && nextChar === "*") {
14784
+ blockComment = true;
14785
+ index++;
14786
+ continue;
14787
+ }
14788
+ if (char === "\"" || char === "'" || char === "`") {
14789
+ quote = char;
14790
+ continue;
14791
+ }
14792
+ if (char === "{") {
14793
+ depth++;
14794
+ continue;
14795
+ }
14796
+ if (char === "}") {
14797
+ depth--;
14798
+ if (depth === 0) return index;
14799
+ }
14800
+ }
14801
+ return -1;
14802
+ }
14803
+ function isIdentifierChar(char) {
14804
+ return typeof char === "string" && IDENTIFIER_CHAR_RE.test(char);
14805
+ }
14806
+ function isIdentifierAt(source, index, identifier) {
14807
+ return source.startsWith(identifier, index) && !isIdentifierChar(source[index - 1]) && !isIdentifierChar(source[index + identifier.length]);
14808
+ }
14809
+ function skipWhitespace(source, index) {
14810
+ let nextIndex = index;
14811
+ while (nextIndex < source.length && WHITESPACE_RE.test(source[nextIndex] ?? "")) nextIndex++;
14812
+ return nextIndex;
14813
+ }
14814
+ function skipTrivia(source, index) {
14815
+ let nextIndex = index;
14816
+ while (nextIndex < source.length) {
14817
+ const whitespaceIndex = skipWhitespace(source, nextIndex);
14818
+ if (whitespaceIndex !== nextIndex) {
14819
+ nextIndex = whitespaceIndex;
14820
+ continue;
14821
+ }
14822
+ const char = source[nextIndex];
14823
+ const nextChar = source[nextIndex + 1];
14824
+ if (char === "/" && nextChar === "/") {
14825
+ const lineEndIndex = source.indexOf("\n", nextIndex + 2);
14826
+ nextIndex = lineEndIndex === -1 ? source.length : lineEndIndex + 1;
14827
+ continue;
14828
+ }
14829
+ if (char === "/" && nextChar === "*") {
14830
+ const blockEndIndex = source.indexOf("*/", nextIndex + 2);
14831
+ nextIndex = blockEndIndex === -1 ? source.length : blockEndIndex + 2;
14832
+ continue;
14833
+ }
14834
+ break;
14835
+ }
14836
+ return nextIndex;
14837
+ }
14838
+ function readObjectPropertyNameEndIndex(source, index, propertyName) {
14839
+ const char = source[index];
14840
+ if (char === "\"" || char === "'") {
14841
+ const closeIndex = source.indexOf(char, index + 1);
14842
+ if (closeIndex === -1) return -1;
14843
+ return source.slice(index + 1, closeIndex) === propertyName ? closeIndex + 1 : -1;
14844
+ }
14845
+ if (isIdentifierAt(source, index, propertyName)) return index + propertyName.length;
14846
+ return -1;
14847
+ }
14848
+ function findConfigObjectOpenIndex(source) {
14849
+ let quote;
14850
+ let escaped = false;
14851
+ let lineComment = false;
14852
+ let blockComment = false;
14853
+ for (let index = 0; index < source.length; index++) {
14854
+ const char = source[index];
14855
+ const nextChar = source[index + 1];
14856
+ if (lineComment) {
14857
+ if (char === "\n" || char === "\r") lineComment = false;
14858
+ continue;
14859
+ }
14860
+ if (blockComment) {
14861
+ if (char === "*" && nextChar === "/") {
14862
+ blockComment = false;
14863
+ index++;
14864
+ }
14865
+ continue;
14866
+ }
14867
+ if (quote) {
14868
+ if (escaped) {
14869
+ escaped = false;
14870
+ continue;
14871
+ }
14872
+ if (char === "\\") {
14873
+ escaped = true;
14874
+ continue;
14875
+ }
14876
+ if (char === quote) quote = void 0;
14877
+ continue;
14878
+ }
14879
+ if (char === "/" && nextChar === "/") {
14880
+ lineComment = true;
14881
+ index++;
14882
+ continue;
14883
+ }
14884
+ if (char === "/" && nextChar === "*") {
14885
+ blockComment = true;
14886
+ index++;
14887
+ continue;
14888
+ }
14889
+ if (char === "\"" || char === "'" || char === "`") {
14890
+ quote = char;
14891
+ continue;
14892
+ }
14893
+ if (isIdentifierAt(source, index, "defineConfig")) {
14894
+ const callIndex = skipTrivia(source, index + 12);
14895
+ if (source[callIndex] === "(") {
14896
+ const objectOpenIndex = skipTrivia(source, callIndex + 1);
14897
+ if (source[objectOpenIndex] === "{") return objectOpenIndex;
14898
+ }
14899
+ }
14900
+ if (isIdentifierAt(source, index, "export")) {
14901
+ const defaultIndex = skipTrivia(source, index + 6);
14902
+ if (isIdentifierAt(source, defaultIndex, "default")) {
14903
+ const objectOpenIndex = skipTrivia(source, defaultIndex + 7);
14904
+ if (source[objectOpenIndex] === "{") return objectOpenIndex;
14905
+ }
14906
+ }
14907
+ }
14908
+ return -1;
14909
+ }
14910
+ function findObjectPropertyValueIndex(source, openIndex, propertyName) {
14911
+ const closeIndex = findMatchingObjectBraceIndex(source, openIndex);
14912
+ if (closeIndex === -1) return -1;
14913
+ let depth = 1;
14914
+ let quote;
14915
+ let escaped = false;
14916
+ let lineComment = false;
14917
+ let blockComment = false;
14918
+ for (let index = openIndex + 1; index < closeIndex; index++) {
14919
+ const char = source[index];
14920
+ const nextChar = source[index + 1];
14921
+ if (lineComment) {
14922
+ if (char === "\n" || char === "\r") lineComment = false;
14923
+ continue;
14924
+ }
14925
+ if (blockComment) {
14926
+ if (char === "*" && nextChar === "/") {
14927
+ blockComment = false;
14928
+ index++;
14929
+ }
14930
+ continue;
14931
+ }
14932
+ if (quote) {
14933
+ if (escaped) {
14934
+ escaped = false;
14935
+ continue;
14936
+ }
14937
+ if (char === "\\") {
14938
+ escaped = true;
14939
+ continue;
14940
+ }
14941
+ if (char === quote) quote = void 0;
14942
+ continue;
14943
+ }
14944
+ if (char === "/" && nextChar === "/") {
14945
+ lineComment = true;
14946
+ index++;
14947
+ continue;
14948
+ }
14949
+ if (char === "/" && nextChar === "*") {
14950
+ blockComment = true;
14951
+ index++;
14952
+ continue;
14953
+ }
14954
+ if (depth === 1) {
14955
+ const propertyNameEndIndex = readObjectPropertyNameEndIndex(source, index, propertyName);
14956
+ if (propertyNameEndIndex !== -1) {
14957
+ const colonIndex = skipTrivia(source, propertyNameEndIndex);
14958
+ if (source[colonIndex] === ":") return skipTrivia(source, colonIndex + 1);
14959
+ }
14960
+ }
14961
+ if (char === "\"" || char === "'" || char === "`") {
14962
+ quote = char;
14963
+ continue;
14964
+ }
14965
+ if (char === "{") {
14966
+ depth++;
14967
+ continue;
14968
+ }
14969
+ if (char === "}") depth--;
14970
+ }
14971
+ return -1;
14972
+ }
14973
+ function hasEnabledTsconfigPathsValueAt(source, index) {
14974
+ const valueIndex = skipTrivia(source, index);
14975
+ return source[valueIndex] === "{" || isIdentifierAt(source, valueIndex, "true");
14976
+ }
14977
+ function hasResolveTsconfigPathsOption(source) {
14978
+ const configOpenIndex = findConfigObjectOpenIndex(source);
14979
+ if (configOpenIndex === -1) return false;
14980
+ const resolveValueIndex = findObjectPropertyValueIndex(source, configOpenIndex, "resolve");
14981
+ if (source[resolveValueIndex] !== "{") return false;
14982
+ const tsconfigPathsValueIndex = findObjectPropertyValueIndex(source, resolveValueIndex, "tsconfigPaths");
14983
+ return tsconfigPathsValueIndex !== -1 && hasEnabledTsconfigPathsValueAt(source, tsconfigPathsValueIndex);
14984
+ }
14744
14985
  function patchInitReactViteConfigContent(source) {
14745
14986
  if (source.includes("'@convex'") || source.includes("\"@convex\"")) return source.endsWith("\n") ? source : `${source}\n`;
14746
- if (source.includes("viteTsConfigPaths(") || source.includes("tsConfigPaths(")) return source.endsWith("\n") ? source : `${source}\n`;
14987
+ if (source.includes("viteTsConfigPaths(") || source.includes("tsConfigPaths(") || hasResolveTsconfigPathsOption(source)) return source.endsWith("\n") ? source : `${source}\n`;
14747
14988
  if (!source.includes("alias: {")) throw new Error("Could not patch vite.config.ts: expected a resolve.alias block.");
14748
14989
  const nextSource = source.replace("alias: {", `alias: {\n '@convex': path.resolve(__dirname, './convex/shared'),`);
14749
14990
  return nextSource.endsWith("\n") ? nextSource : `${nextSource}\n`;
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as promptForScaffoldTemplateSelection, A as resolveCodegenTrimSegments, At as highlighter, B as runConfiguredCodegen, C as isEntryPoint, Ct as formatDependencyInstallCommand, D as parseInitCommandArgs, E as parseBackendRunJson, Et as stripConvexCommandNoise, F as resolveRunDeps, G as runMigrationFlow, H as runDevSchemaBackfillIfNeeded, I as runAfterScaffoldScript, J as withWorkingDirectory, K as trackProcess, L as runAggregateBackfillFlow, M as resolveDocTopic, N as resolveInitProjectDir, O as readPackageVersions, P as resolveMigrationConfig, Q as promptForPluginSelection, R as runAggregatePruneFlow, S as isConvexDevPreRunConflictFlag, St as detectPackageManager, T as parseArgs, Tt as serializeEnvValue, U as runInitCommandFlow, V as runConvexInitIfNeeded, W as runMigrationCreate, X as collectPluginScaffoldTemplates, Y as createSpinner, Z as filterScaffoldTemplatePathMap, _ as formatInfoOutput, _t as applyPlanningDependencyInstall, a as cleanup, at as getPluginCatalogEntry, b as getDevAggregateBackfillStatePath, bt as resolveSupportedDependencyWarnings, c as createCommandEnv, ct as buildPluginInstallPlan, d as extractBackfillCliOptions, dt as collectInstalledPluginKeys, et as resolveAddTemplateDefaults, f as extractConcaveRunTargetArgs, ft as getPluginLockfilePath, g as formatDocsOutput, gt as applyDependencyHintsInstall, h as extractResetCliOptions, ht as resolveSchemaInstalledPlugins, i as buildInitializationPlan, it as resolveTemplatesByIdOrThrow, j as resolveConfiguredBackend, k as resolveBackfillConfig, kt as logger, l as ensureConvexGitignoreEntry, lt as resolvePluginScaffoldRoots, m as extractMigrationDownOptions, mt as readPluginLockfile, n as applyPluginInstallPlanFiles, nt as resolvePresetScaffoldTemplates, o as createBackendAdapter, ot as getSupportedPluginKeys, p as extractMigrationCliOptions, pt as getSchemaFilePath, q as withLocalCodegenEnv, r as assertNoRemovedDevPreRunFlag, rt as resolveTemplateSelectionSource, s as createBackendCommandEnv, st as isSupportedPluginKey, t as applyDependencyInstallPlan, tt as resolvePluginPreset, u as extractBackendRunTargetArgs, ut as assertSchemaFileExists, v as getAggregateBackfillDeploymentKey, vt as applyPluginDependencyInstall, w as isInitialized, wt as resolveAuthEnvState, x as hasRemoteConvexDeploymentEnv, xt as resolveProjectScaffoldContext, y as getConvexDeploymentCommandEnv, yt as inspectPluginDependencyInstall, z as runBackendFunction } from "./backend-core-CQmXi2Q0.mjs";
2
+ import { $ as promptForScaffoldTemplateSelection, A as resolveCodegenTrimSegments, At as highlighter, B as runConfiguredCodegen, C as isEntryPoint, Ct as formatDependencyInstallCommand, D as parseInitCommandArgs, E as parseBackendRunJson, Et as stripConvexCommandNoise, F as resolveRunDeps, G as runMigrationFlow, H as runDevSchemaBackfillIfNeeded, I as runAfterScaffoldScript, J as withWorkingDirectory, K as trackProcess, L as runAggregateBackfillFlow, M as resolveDocTopic, N as resolveInitProjectDir, O as readPackageVersions, P as resolveMigrationConfig, Q as promptForPluginSelection, R as runAggregatePruneFlow, S as isConvexDevPreRunConflictFlag, St as detectPackageManager, T as parseArgs, Tt as serializeEnvValue, U as runInitCommandFlow, V as runConvexInitIfNeeded, W as runMigrationCreate, X as collectPluginScaffoldTemplates, Y as createSpinner, Z as filterScaffoldTemplatePathMap, _ as formatInfoOutput, _t as applyPlanningDependencyInstall, a as cleanup, at as getPluginCatalogEntry, b as getDevAggregateBackfillStatePath, bt as resolveSupportedDependencyWarnings, c as createCommandEnv, ct as buildPluginInstallPlan, d as extractBackfillCliOptions, dt as collectInstalledPluginKeys, et as resolveAddTemplateDefaults, f as extractConcaveRunTargetArgs, ft as getPluginLockfilePath, g as formatDocsOutput, gt as applyDependencyHintsInstall, h as extractResetCliOptions, ht as resolveSchemaInstalledPlugins, i as buildInitializationPlan, it as resolveTemplatesByIdOrThrow, j as resolveConfiguredBackend, k as resolveBackfillConfig, kt as logger, l as ensureConvexGitignoreEntry, lt as resolvePluginScaffoldRoots, m as extractMigrationDownOptions, mt as readPluginLockfile, n as applyPluginInstallPlanFiles, nt as resolvePresetScaffoldTemplates, o as createBackendAdapter, ot as getSupportedPluginKeys, p as extractMigrationCliOptions, pt as getSchemaFilePath, q as withLocalCodegenEnv, r as assertNoRemovedDevPreRunFlag, rt as resolveTemplateSelectionSource, s as createBackendCommandEnv, st as isSupportedPluginKey, t as applyDependencyInstallPlan, tt as resolvePluginPreset, u as extractBackendRunTargetArgs, ut as assertSchemaFileExists, v as getAggregateBackfillDeploymentKey, vt as applyPluginDependencyInstall, w as isInitialized, wt as resolveAuthEnvState, x as hasRemoteConvexDeploymentEnv, xt as resolveProjectScaffoldContext, y as getConvexDeploymentCommandEnv, yt as inspectPluginDependencyInstall, z as runBackendFunction } from "./backend-core-CRJpuVnf.mjs";
3
3
  import fs, { existsSync, readFileSync } from "node:fs";
4
4
  import path, { delimiter, dirname, join, relative, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -39,6 +39,9 @@ declare function isAuthMutationError(error: unknown): error is AuthMutationError
39
39
  //#endregion
40
40
  //#region src/react/auth-mutations.d.ts
41
41
  type MutationOptionsHook<TData, TVariables = void> = (options?: Omit<UseMutationOptions<TData, DefaultError, TVariables>, 'mutationFn'>) => UseMutationOptions<TData, DefaultError, TVariables>;
42
+ type SignInMutationOptionsHook<TData, TVariables = void> = (options?: Omit<UseMutationOptions<TData, DefaultError, TVariables>, 'mutationFn'> & {
43
+ signInMethod?: string;
44
+ }) => UseMutationOptions<TData, DefaultError, TVariables>;
42
45
  type AnyAuthFn = (...args: never[]) => unknown;
43
46
  type MutationArgsWithFetchOptions = {
44
47
  fetchOptions?: Record<string, unknown>;
@@ -72,8 +75,9 @@ type AuthClient = {
72
75
  signOut?: AnyAuthFn;
73
76
  signIn?: {
74
77
  anonymous?: AnyAuthFn;
75
- social?: AnyAuthFn;
76
78
  email?: AnyAuthFn;
79
+ social?: AnyAuthFn;
80
+ [method: string]: AnyAuthFn | undefined;
77
81
  };
78
82
  signUp?: {
79
83
  email?: AnyAuthFn;
@@ -105,7 +109,7 @@ type AuthClient = {
105
109
  type AuthMutationsResult = {
106
110
  useSignOutMutationOptions: MutationOptionsHook<unknown, MutationArgsWithFetchOptions | void>;
107
111
  useSignInSocialMutationOptions: MutationOptionsHook<unknown, unknown>;
108
- useSignInMutationOptions: MutationOptionsHook<unknown, unknown>;
112
+ useSignInMutationOptions: SignInMutationOptionsHook<unknown, unknown>;
109
113
  useSignUpMutationOptions: MutationOptionsHook<unknown, unknown>;
110
114
  };
111
115
  declare function createAuthMutations(authClient: AuthClient): AuthMutationsResult;
@@ -1574,12 +1574,13 @@ function createAuthMutations(authClient) {
1574
1574
  const useSignInMutationOptions = ((options) => {
1575
1575
  const authStoreApi = useAuthStore();
1576
1576
  const convexQueryClient = useConvexQueryClient();
1577
+ const { signInMethod = "email", ...mutationOptions } = options ?? {};
1577
1578
  return {
1578
- ...options,
1579
+ ...mutationOptions,
1579
1580
  mutationFn: async (args) => {
1580
- const signInEmail = authClient.signIn?.email;
1581
- if (typeof signInEmail !== "function") throw new Error("Auth client does not expose signIn.email");
1582
- const res = await callAuthMethod(signInEmail, withDisabledSessionSignal(args));
1581
+ const signIn = authClient.signIn?.[signInMethod];
1582
+ if (typeof signIn !== "function") throw new Error(`Auth client does not expose signIn.${signInMethod}`);
1583
+ const res = await callAuthMethod(signIn, withDisabledSessionSignal(args));
1583
1584
  if (res?.error) throw toAuthMutationError(res.error);
1584
1585
  seedReturnedToken(authStoreApi, res);
1585
1586
  await hydrateReturnedSession(authClient, res);
@@ -148,12 +148,23 @@ declare function isAuthMutationError(error: unknown): error is AuthMutationError
148
148
  //#endregion
149
149
  //#region src/solid/auth-mutations.d.ts
150
150
  type MutationOptionsHook<TData, TVariables = void> = (options?: Omit<SolidMutationOptions<TData, DefaultError, TVariables>, 'mutationFn'>) => SolidMutationOptions<TData, DefaultError, TVariables>;
151
+ type SignInMethod<T extends AuthClient> = Extract<keyof T['signIn'], string>;
152
+ type EmailSignInMutationOptions<T extends AuthClient> = Omit<SolidMutationOptions<Awaited<ReturnType<T['signIn']['email']>>, DefaultError, Parameters<T['signIn']['email']>[0]>, 'mutationFn'> & {
153
+ signInMethod?: 'email';
154
+ };
155
+ type CustomSignInMutationOptions<T extends AuthClient, TMethod extends SignInMethod<T>> = Omit<SolidMutationOptions<Awaited<ReturnType<T['signIn'][TMethod]>>, DefaultError, Parameters<T['signIn'][TMethod]>[0]>, 'mutationFn'> & {
156
+ signInMethod: TMethod;
157
+ };
158
+ type SignInMutationOptionsHook<T extends AuthClient> = {
159
+ (options?: EmailSignInMutationOptions<T>): SolidMutationOptions<Awaited<ReturnType<T['signIn']['email']>>, DefaultError, Parameters<T['signIn']['email']>[0]>;
160
+ <TMethod extends Exclude<SignInMethod<T>, 'email'>>(options: CustomSignInMutationOptions<T, TMethod>): SolidMutationOptions<Awaited<ReturnType<T['signIn'][TMethod]>>, DefaultError, Parameters<T['signIn'][TMethod]>[0]>;
161
+ };
151
162
  type AnyFn = (...args: any[]) => Promise<any>;
152
163
  type AuthClient = {
153
164
  signOut: AnyFn;
154
- signIn: {
155
- social: AnyFn;
165
+ signIn: Record<string, AnyFn> & {
156
166
  email: AnyFn;
167
+ social: AnyFn;
157
168
  };
158
169
  signUp: {
159
170
  email: AnyFn;
@@ -162,7 +173,7 @@ type AuthClient = {
162
173
  type AuthMutationsResult<T extends AuthClient> = {
163
174
  useSignOutMutationOptions: MutationOptionsHook<Awaited<ReturnType<T['signOut']>>, Parameters<T['signOut']>[0] | void>;
164
175
  useSignInSocialMutationOptions: MutationOptionsHook<Awaited<ReturnType<T['signIn']['social']>>, Parameters<T['signIn']['social']>[0]>;
165
- useSignInMutationOptions: MutationOptionsHook<Awaited<ReturnType<T['signIn']['email']>>, Parameters<T['signIn']['email']>[0]>;
176
+ useSignInMutationOptions: SignInMutationOptionsHook<T>;
166
177
  useSignUpMutationOptions: MutationOptionsHook<Awaited<ReturnType<T['signUp']['email']>>, Parameters<T['signUp']['email']>[0]>;
167
178
  };
168
179
  /**
@@ -1728,10 +1728,13 @@ function createAuthMutations(authClient) {
1728
1728
  });
1729
1729
  const useSignInMutationOptions = ((options) => {
1730
1730
  const authStoreApi = useAuthStore();
1731
+ const { signInMethod = "email", ...mutationOptions } = options ?? {};
1731
1732
  return {
1732
- ...options,
1733
+ ...mutationOptions,
1733
1734
  mutationFn: async (args) => {
1734
- const res = await authClient.signIn.email(args);
1735
+ const signIn = authClient.signIn[signInMethod];
1736
+ if (typeof signIn !== "function") throw new Error(`Auth client does not expose signIn.${signInMethod}`);
1737
+ const res = await signIn(args);
1735
1738
  if (res?.error) throw new AuthMutationError(res.error);
1736
1739
  seedReturnedToken(authStoreApi, res);
1737
1740
  await ensureAuth(authStoreApi);
package/dist/watcher.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Dt as generateMeta, F as resolveRunDeps, Ot as getConvexConfig, j as resolveConfiguredBackend, kt as logger, q as withLocalCodegenEnv } from "./backend-core-CQmXi2Q0.mjs";
2
+ import { Dt as generateMeta, F as resolveRunDeps, Ot as getConvexConfig, j as resolveConfiguredBackend, kt as logger, q as withLocalCodegenEnv } from "./backend-core-CRJpuVnf.mjs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.15.7",
3
+ "version": "0.15.9",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -1,8 +1,7 @@
1
1
  ---
2
2
  name: kitcn
3
- description: ALWAYS use this skill when working with convex or kitcn. Covers both setup and e2e feature paths using cRPC + ORM + auth + React.
3
+ description: "Use for Convex/kitcn setup and feature work: cRPC, ORM, auth, React."
4
4
  sources: [www/content/docs/concepts.mdx, www/content/docs/orm/index.mdx, www/content/docs/orm/schema/relations.mdx, www/content/docs/orm/schema/triggers.mdx, www/content/docs/orm/queries/aggregates.mdx, www/content/docs/orm/queries/pagination.mdx, www/content/docs/server/error-handling.mdx, www/content/docs/server/http.mdx, www/content/docs/server/middlewares.mdx, www/content/docs/server/procedures.mdx, www/content/docs/server/server-side-calls.mdx, www/content/docs/react/queries.mdx, www/content/docs/react/mutations.mdx, www/content/docs/react/infinite-queries.mdx, www/content/docs/auth/client.mdx, www/content/docs/auth/server.mdx]
5
- metadata: { sources: [www/content/docs/concepts.mdx, www/content/docs/orm/index.mdx, www/content/docs/orm/schema/relations.mdx, www/content/docs/orm/schema/triggers.mdx, www/content/docs/orm/queries/aggregates.mdx, www/content/docs/orm/queries/pagination.mdx, www/content/docs/server/error-handling.mdx, www/content/docs/server/http.mdx, www/content/docs/server/middlewares.mdx, www/content/docs/server/procedures.mdx, www/content/docs/server/server-side-calls.mdx, www/content/docs/react/queries.mdx, www/content/docs/react/mutations.mdx, www/content/docs/react/infinite-queries.mdx, www/content/docs/auth/client.mdx, www/content/docs/auth/server.mdx] }
6
5
  ---
7
6
  # kitcn Core Skill (80% Path)
8
7
  Use this file first for everyday feature delivery in an already configured kitcn app.
@@ -25,7 +24,7 @@ Out of scope:
25
24
  4. Use `CRPCError` for expected failures.
26
25
  5. Prefer schema triggers for cross-row invariants, but move invariant maintenance to explicit mutation helpers if trigger execution is unstable (for example init/seed hangs or recursive write paths).
27
26
  6. Keep auth/rate-limit checks server-side.
28
- 7. **Inter-procedure calls**: `create<Module>Handler(ctx)` in queries/mutations (zero overhead) unless validation is relevant, `create<Module>Caller(ctx)` in actions/HTTP routes. In action context use `caller.actions.*` for action procedures and `caller.schedule.*` for scheduling. Import from `./generated/<module>.runtime`. Never call `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` directly for module procedures.
27
+ 7. **Inter-procedure calls**: use generated runtime helpers: `create<Module>Handler(ctx)` in queries/mutations, `create<Module>Caller(ctx)` in actions/HTTP routes, `caller.actions.*` for action procedures, and `caller.schedule.*` for scheduling. Never call `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` directly for module procedures.
29
28
  ## Shortcut Mode (tRPC + Drizzle Mental Model)
30
29
  Default assumption:
31
30
  - cRPC behavior is tRPC-like (builder chain + middleware + TanStack options).
@@ -50,9 +49,9 @@ Only remember these non-parity deltas:
50
49
  17. In RSC, `prefetch` hydrates client, `caller` is server-only and not hydrated, `preloadQuery` hydrates but can cause stale split ownership if also rendered client-side.
51
50
  18. Better Auth Next.js shortcut is `convexBetterAuth(...)`; generic server-only shortcut is `createCallerFactory(...)`.
52
51
  19. On the kitcn auth client path, use `createAuthMutations(authClient)` wrappers so logout unsubscribes auth queries before sign out. Raw Convex preset keeps a smaller plain `authClient`.
53
- 20. **NEVER** use `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` directly for module-to-module calls. Use `create<Module>Handler(ctx)` or `create<Module>Caller(ctx)` from `convex/functions/generated/<module>.runtime` instead.
54
- 21. **`create<Module>Handler(ctx)`** default choice for queries/mutations. Bypasses input validation, middleware, output validation → zero overhead. Query/mutation ctx only. Import from `./generated/<module>.runtime`.
55
- 22. **`create<Module>Caller(ctx)`** use in actions and HTTP routes (where handler is unavailable). Goes through validation + middleware. Root caller exposes query+mutation procedures. In `ActionCtx`, action procedures are under `caller.actions.*`; scheduling is under `caller.schedule.now|after|at` with `caller.schedule.cancel(id)`. Use `requireActionCtx(ctx)` only when the callback truly runs in `ActionCtx` and you need `caller.actions.*`. If the callback can run from `MutationCtx | ActionCtx` or generic scheduler-capable context, keep the seam honest: use `requireSchedulerCtx(ctx)` and `caller.schedule.*` instead of pretending the path is action-only. Import from `./generated/<module>.runtime`. Each caller/handler eagerly loads every procedure in its module (no lazy loading) — split large modules to keep bundles lean.
52
+ 20. **NEVER** use `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` directly for module-to-module calls. Use the generated runtime helpers from `convex/functions/generated/<module>.runtime`.
53
+ 21. **`create<Module>Handler(ctx)`** is the default in queries/mutations: zero overhead, query/mutation ctx only, and no redundant validation or middleware.
54
+ 22. **`create<Module>Caller(ctx)`** is for actions and HTTP routes. Action procedures live under `caller.actions.*`; scheduling lives under `caller.schedule.now|after|at|cancel`. Use `requireActionCtx(ctx)` only for true `ActionCtx` callbacks; use `requireSchedulerCtx(ctx)` when mutation or action contexts can schedule. Each caller/handler eagerly loads its module, so split large modules.
56
55
  23. API types (`Api`, `ApiInputs`, `ApiOutputs`, `Select`, `Insert`, `TableName`) import from `@convex/api` — no manual `inferApiInputs<typeof api>`.
57
56
  24. HTTP router must export as `httpRouter` (not `appRouter`) for codegen.
58
57
  25. Server wiring imports come from `convex/functions/generated/` directory: `getAuth`, `defineAuth` from `generated/auth`; `initCRPC`, `QueryCtx`, `MutationCtx`, `OrmCtx` from `generated/server`; `create<Module>Caller`, `create<Module>Handler` from `generated/<module>.runtime`. No manual `convex/lib/orm.ts`.
@@ -61,7 +60,7 @@ Only remember these non-parity deltas:
61
60
  28. Async mutation batching is the default (codegen wires it). Customize per call: `execute({ batchSize, delayMs })`. Opt into sync: `execute({ mode: 'sync' })` or `defineSchema(..., { defaults: { mutationExecutionMode: 'sync' } })`. Relevant defaults: `mutationBatchSize`, `mutationLeafBatchSize`, `mutationMaxRows`, `mutationScheduleCallCap`.
62
61
  29. Polymorphic unions are schema-first: use `actionType: discriminator({ variants, as? })` in `convexTable(...)`. Query config does not include a `polymorphic` option. Writes stay flat; reads synthesize nested `details` (or custom alias). Use `withVariants: true` to auto-load all `one()` relations on discriminator tables.
63
62
  30. Do not add manual ORM mutation batching loops in app/plugin code by default. Convex runtime batching already handles mutation execution. Prefer set-based deletes/updates over per-row loops. Only add explicit chunking when batching external side effects (for example Resend API calls) or bounded cleanup sweeps.
64
- ## Directory Boundary (Important)
63
+ ## Directory Boundary
65
64
  Use `references/setup/` when the task needs:
66
65
  1. Project/file structure setup → `setup/index.md` + `setup/server.md`
67
66
  2. Auth bootstrap → `setup/auth.md`
@@ -425,22 +425,6 @@ const canDelete = authClient.admin.checkRolePermission({
425
425
 
426
426
  ## API Reference
427
427
 
428
- | Operation | Method | Admin Required |
429
- |-----------|--------|----------------|
430
- | Create user | `authClient.admin.createUser` | Yes |
431
- | List users | `authClient.admin.listUsers` | Yes |
432
- | Set role | `authClient.admin.setRole` | Yes |
433
- | Set password | `authClient.admin.setUserPassword` | Yes |
434
- | Update user | `authClient.admin.updateUser` | Yes |
435
- | Ban user | `authClient.admin.banUser` | Yes |
436
- | Unban user | `authClient.admin.unbanUser` | Yes |
437
- | List sessions | `authClient.admin.listUserSessions` | Yes |
438
- | Revoke session | `authClient.admin.revokeUserSession` | Yes |
439
- | Revoke all sessions | `authClient.admin.revokeUserSessions` | Yes |
440
- | Impersonate | `authClient.admin.impersonateUser` | Yes |
441
- | Stop impersonating | `authClient.admin.stopImpersonating` | Yes |
442
- | Remove user | `authClient.admin.removeUser` | Yes |
443
- | Check permission | `authClient.admin.hasPermission` | No |
444
- | Check role permission | `authClient.admin.checkRolePermission` | No |
445
-
446
- Use Convex functions for custom admin operations. Use Better Auth client API for standard operations like user management, banning, and session management.
428
+ Use Better Auth client admin methods for standard user management, roles,
429
+ passwords, bans, sessions, impersonation, removal, and permission checks. Use
430
+ Convex functions only for custom admin operations.
@@ -1127,24 +1127,6 @@ await authClient.organization.setActiveTeam({ teamId });
1127
1127
 
1128
1128
  ## API Reference
1129
1129
 
1130
- | Operation | Method | Multi-table |
1131
- | ------------------ | --------------- | ----------- |
1132
- | Create org | Better Auth API | Yes |
1133
- | Update org | Better Auth API | No |
1134
- | Delete org | Better Auth API | Yes |
1135
- | List orgs | ORM | No |
1136
- | Check slug | ORM | No |
1137
- | Invite member | Better Auth API | Yes |
1138
- | Accept invite | Better Auth API | Yes |
1139
- | Reject invite | Better Auth API | Yes |
1140
- | Cancel invite | Better Auth API | Yes |
1141
- | List user invites | ORM | No |
1142
- | Add member | Better Auth API | Yes |
1143
- | Update role | Better Auth API | Yes |
1144
- | Remove member | Better Auth API | Yes |
1145
- | Leave org | Better Auth API | Yes |
1146
- | Create team | Better Auth API | Yes |
1147
- | Add team member | Better Auth API | Yes |
1148
- | Remove team member | Better Auth API | Yes |
1149
-
1150
- Use Better Auth API for multi-table operations. Use `ctx.orm` for simple single-table reads/updates.
1130
+ Use Better Auth API for multi-table org, invitation, member, role, and team
1131
+ operations. Use `ctx.orm` for simple single-table reads such as list orgs,
1132
+ check slug, and list user invitations.
@@ -561,19 +561,8 @@ Example-parity helper module:
561
561
 
562
562
  ## API Reference
563
563
 
564
- | Operation | Method | Type |
565
- |-----------|--------|------|
566
- | Checkout | `authClient.checkout` | Client |
567
- | Customer portal | `authClient.customer.portal` | Client |
568
- | Customer state | `authClient.customer.state` | Client |
569
- | List benefits | `authClient.customer.benefits.list` | Client |
570
- | List orders | `authClient.customer.orders.list` | Client |
571
- | List subscriptions | `authClient.customer.subscriptions.list` | Client |
572
- | Event ingestion | `authClient.usage.ingestion` | Client |
573
- | List meters | `authClient.usage.meters.list` | Client |
574
- | Create customer | `internal.polarCustomer.createCustomer` | Internal action |
575
- | Link customer ID | `internal.polarCustomer.updateUserPolarCustomerId` | Internal mutation |
576
- | Create subscription | `internal.polarSubscription.createSubscription` | Internal mutation |
577
- | Update subscription | `internal.polarSubscription.updateSubscription` | Internal mutation |
578
- | Cancel subscription | Convex action | User action |
579
- | Resume subscription | Convex action | User action |
564
+ Client operations: checkout, portal, customer state, benefits, orders,
565
+ subscriptions, usage ingestion, and meter listing.
566
+
567
+ Internal operations: create/link Polar customers and create/update
568
+ subscriptions. User-facing cancellation/resume flows should be Convex actions.
@@ -326,6 +326,15 @@ const signUp = useMutation(useSignUpMutationOptions({ onSuccess: () => router.pu
326
326
  signUp.mutate({ callbackURL: window.location.origin, email, name, password });
327
327
  ```
328
328
 
329
+ **Plugin sign-in methods** (requires the matching Better Auth client plugin):
330
+ ```ts
331
+ const signIn = useMutation(useSignInMutationOptions({
332
+ signInMethod: 'username',
333
+ onSuccess: () => router.push('/'),
334
+ }));
335
+ signIn.mutate({ callbackURL: window.location.origin, password, username });
336
+ ```
337
+
329
338
  ### Sign Out
330
339
 
331
340
  ```ts
@@ -492,12 +501,8 @@ Auth triggers (`defineAuth(...).triggers`) handle auth lifecycle events. DB trig
492
501
 
493
502
  Nested `{ create, update, delete, change }` per table, matching ORM `defineTriggers` pattern:
494
503
 
495
- | Hook | Signature | Return |
496
- |------|-----------|--------|
497
- | `create.before` | `(data, ctx) => void \| { data } \| false` | Merge / cancel |
498
- | `create.after` | `(doc, ctx) => void` | Side effects |
499
- | `update.before` | `(update, ctx) => void \| { data } \| false` | Merge / cancel |
500
- | `update.after` | `(newDoc, ctx) => void` | Sync changes |
501
- | `delete.before` | `(doc, ctx) => void \| { data } \| false` | Guard / cancel |
502
- | `delete.after` | `(doc, ctx) => void` | Cleanup |
503
- | `change` | `(change, ctx) => void` | Cross-operation |
504
+ - `create.before(data, ctx)` / `update.before(update, ctx)` /
505
+ `delete.before(doc, ctx)` may return `{ data }` or `false`.
506
+ - `create.after(doc, ctx)`, `update.after(newDoc, ctx)`, and
507
+ `delete.after(doc, ctx)` run side effects.
508
+ - `change(change, ctx)` handles cross-operation sync.
@@ -617,60 +617,32 @@ if (ctx.isAuthenticated) await ctx.caller.todos.create({ title: "New task" });
617
617
 
618
618
  ### Route Builder Patterns
619
619
 
620
- | Pattern | Use Case |
621
- | ---------------------------------------- | ------------------------ |
622
- | `publicRoute.get('/path').query()` | Public GET endpoint |
623
- | `authRoute.post('/path').mutation()` | Auth-required POST |
624
- | `optionalAuthRoute.get('/path').query()` | Optional auth endpoint |
625
- | `.params(z.object({id}))` | Path params `/todos/:id` |
626
- | `.searchParams(z.object({limit}))` | Query params `?limit=10` |
627
- | `.input(z.object({...}))` | JSON body (POST/PATCH) |
628
- | `.form(z.object({file, description}))` | FormData uploads |
629
- | `.output(z.object({...}))` | Response validation |
630
- | `.meta({ ratelimit: 'api/heavy' })` | Procedure metadata |
631
- | `.use(middleware)` | Custom middleware |
632
- | `router({ endpoint1, endpoint2 })` | Group endpoints |
620
+ - `publicRoute.get("/path").query()` for public GET.
621
+ - `authRoute.post("/path").mutation()` for authenticated writes.
622
+ - `optionalAuthRoute.get("/path").query()` for optional-auth reads.
623
+ - Chain `.params(...)`, `.searchParams(...)`, `.input(...)`, `.form(...)`,
624
+ `.output(...)`, `.meta(...)`, and `.use(...)` as needed.
625
+ - Use `router({ endpoint })` for feature-level endpoint groups.
633
626
 
634
627
  ### HTTP Methods
635
628
 
636
- | Method | Builder | Use Case | Has Body |
637
- | ------ | ---------------------- | ----------------- | -------- |
638
- | GET | `.get().query()` | Read operations | No |
639
- | POST | `.post().mutation()` | Create operations | Yes |
640
- | PATCH | `.patch().mutation()` | Partial updates | Yes |
641
- | DELETE | `.delete().mutation()` | Delete operations | No |
629
+ Use `.get().query()` for reads, `.post().mutation()` for creates,
630
+ `.patch().mutation()` for partial updates, and `.delete().mutation()` for
631
+ deletes. GET/DELETE should not carry JSON bodies.
642
632
 
643
633
  ### Error Codes
644
634
 
645
- | Code | HTTP Status | Use Case |
646
- | ----------------------- | ----------- | --------------------------------- |
647
- | `BAD_REQUEST` | 400 | Invalid request format |
648
- | `UNAUTHORIZED` | 401 | Missing or invalid authentication |
649
- | `FORBIDDEN` | 403 | Authenticated but not authorized |
650
- | `NOT_FOUND` | 404 | Resource doesn't exist |
651
- | `CONFLICT` | 409 | Resource conflict (duplicate) |
652
- | `UNPROCESSABLE_CONTENT` | 422 | Validation failed |
653
- | `TOO_MANY_REQUESTS` | 429 | Rate limit exceeded |
654
- | `INTERNAL_SERVER_ERROR` | 500 | Unexpected server error |
635
+ Map expected failures through `CRPCError`: `BAD_REQUEST` 400, `UNAUTHORIZED`
636
+ 401, `FORBIDDEN` 403, `NOT_FOUND` 404, `CONFLICT` 409,
637
+ `UNPROCESSABLE_CONTENT` 422, `TOO_MANY_REQUESTS` 429, and
638
+ `INTERNAL_SERVER_ERROR` 500.
655
639
 
656
640
  ### Input Args
657
641
 
658
- | Property | Type | Description |
659
- | -------------- | --------------------------------------- | ------------------------------------- |
660
- | `params` | `Record<string, string>` | Path parameters (`:id`) |
661
- | `searchParams` | `Record<string, string \| string[]>` | Query string params |
662
- | `form` | `z.infer<TForm>` | Typed FormData (if `.form()` defined) |
663
- | `fetch` | `typeof fetch` | Custom fetch function |
664
- | `init` | `RequestInit` | Request options |
665
- | `headers` | `Record<string, string> \| (() => ...)` | Headers (incl. cookies) |
666
- | `[key]` | `unknown` | JSON body fields at root |
642
+ Client args can include `params`, `searchParams`, `form`, custom `fetch`,
643
+ `init`, `headers`, and root JSON body fields.
667
644
 
668
645
  ### Client Methods
669
646
 
670
- | Method | Signature | Description |
671
- | -------------------- | --------------------- | ----------------------------------------- |
672
- | `queryOptions` | `(args?, queryOpts?)` | Options for `useQuery`/`useSuspenseQuery` |
673
- | `staticQueryOptions` | `(args?, queryOpts?)` | For event handlers/prefetching (no hooks) |
674
- | `mutationOptions` | `(mutationOpts?)` | Options for `useMutation` |
675
- | `queryKey` | `(args?)` | Get query key for cache operations |
676
- | `queryFilter` | `(args?, filters?)` | Filter for `invalidateQueries` |
647
+ Generated clients expose `queryOptions`, `staticQueryOptions`,
648
+ `mutationOptions`, `queryKey`, and `queryFilter`.
@@ -1120,56 +1120,34 @@ export default defineSchema(tables, {
1120
1120
 
1121
1121
  ### Column Types
1122
1122
 
1123
- All from `kitcn/orm`:
1124
-
1125
- | Builder | TS Type | Convex | Notes |
1126
- | ------------------------------- | ------------- | ---------------------- | ------------------------------------------ |
1127
- | `text()` | `string` | `v.string()` | |
1128
- | `textEnum(['a','b'] as const)` | `'a' \| 'b'` | `v.string()` | Runtime-validated |
1129
- | `integer()` | `number` | `v.number()` | Float64 |
1130
- | `boolean()` | `boolean` | `v.boolean()` | |
1131
- | `bigint()` | `bigint` | `v.int64()` | |
1132
- | `timestamp()` | `Date` | `v.number()` | `.defaultNow()` for createdAt |
1133
- | `timestamp({ mode: 'string' })` | `string` | `v.number()` | |
1134
- | `date()` | `string` | `v.string()` | YYYY-MM-DD, or `{ mode: 'date' }` → `Date` |
1135
- | `id('table')` | `Id<'table'>` | `v.id('table')` | Typed reference |
1136
- | `vector(dims)` | `number[]` | `v.array(v.float64())` | For vectorIndex |
1137
- | `bytes()` | `ArrayBuffer` | `v.bytes()` | |
1138
- | `unionOf(text(), integer())` | `string \| number` | `v.union(...)` | Builder-only scalar union sugar |
1139
- | `objectOf(text().notNull())` | `Record<string, string>` | `v.record(...)` | Homogeneous record values |
1140
- | `json<T>()` | `T` | `v.any()` | Type-only, no runtime validation |
1141
- | `custom(validator)` | inferred | any `v.*` | Full Convex validator |
1123
+ All come from `kitcn/orm`: `text`, `textEnum`, `integer`, `boolean`,
1124
+ `bigint`, `timestamp`, `date`, `id`, `vector`, `bytes`, `unionOf`, `objectOf`,
1125
+ `json`, and `custom`.
1126
+
1127
+ Key type notes: `timestamp()` stores Convex numbers and exposes `Date`;
1128
+ `timestamp({ mode: "string" })` exposes `string`; `date()` is YYYY-MM-DD unless
1129
+ `{ mode: "date" }`; `json<T>()` is type-only over `v.any()`; `custom(...)`
1130
+ keeps the provided Convex validator.
1142
1131
 
1143
1132
  ### Operators
1144
1133
 
1145
- | Category | Operators |
1146
- | ------------------- | ---------------------------------------------------------------------------- |
1147
- | Comparison | `eq`, `ne`, `gt`, `gte`, `lt`, `lte` |
1148
- | Range | `between` (inclusive), `notBetween` (strict outside) |
1149
- | Set | `in`, `notIn` |
1150
- | Null | `isNull`, `isNotNull` |
1151
- | Logical | `AND`, `OR`, `NOT` |
1152
- | String (post-fetch) | `like`, `ilike`, `notLike`, `notIlike`, `startsWith`, `endsWith`, `contains` |
1153
- | Array (post-fetch) | `arrayContains`, `arrayContained`, `arrayOverlaps` |
1134
+ - Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`
1135
+ - Range/set/null: `between`, `notBetween`, `in`, `notIn`, `isNull`, `isNotNull`
1136
+ - Logical: `AND`, `OR`, `NOT`
1137
+ - Post-fetch string/array: `like`, `ilike`, `notLike`, `notIlike`,
1138
+ `startsWith`, `endsWith`, `contains`, `arrayContains`, `arrayContained`,
1139
+ `arrayOverlaps`
1154
1140
 
1155
1141
  ### Select Composition Limitations
1156
1142
 
1157
- | Combination | Status |
1158
- | ------------------------- | ------------- |
1159
- | `select() + search` | Not supported |
1160
- | `select() + vectorSearch` | Not supported |
1161
- | `select() + offset` | Not supported |
1162
- | `select() + with` | Not supported |
1163
- | `select() + extras` | Not supported |
1164
- | `select() + columns` | Not supported |
1143
+ Do not combine `select()` with `search`, `vectorSearch`, `offset`, `with`,
1144
+ `extras`, or `columns`.
1165
1145
 
1166
1146
  ### Full-Scan Operator Workarounds
1167
1147
 
1168
- | Operator | Scalable workaround |
1169
- | ---------------------------------- | -------------------------------------------------- |
1170
- | `arrayContains/Contained/Overlaps` | Inverted/join table keyed by element |
1171
- | `contains` | `withSearchIndex` or tokenized denormalized field |
1172
- | `endsWith` | Store reversed column, use `startsWith` |
1173
- | `ilike`/`notIlike` | Lowercase column + `startsWith`/`like('prefix%')` |
1174
- | `notLike` | Indexed positive pre-filter + `notLike` post-fetch |
1175
- | `NOT` (general) | Rewrite to positive predicates; cap with `maxScan` |
1148
+ - Array membership/overlap: use an inverted or join table keyed by element.
1149
+ - `contains`: use `withSearchIndex` or tokenized denormalized fields.
1150
+ - `endsWith`: store a reversed column and query with `startsWith`.
1151
+ - `ilike` / `notIlike`: lowercase a query column and use prefix/like filters.
1152
+ - `notLike` and general `NOT`: rewrite to positive indexed predicates and cap
1153
+ fallback scans with `maxScan`.
@@ -657,11 +657,6 @@ Don't render `preloadQuery` data in BOTH Server and Client components — the se
657
657
 
658
658
  ### Infinite Query Return Value
659
659
 
660
- | Property | Type | Description |
661
- |----------|------|-------------|
662
- | `data` | `T[]` | Flattened array of all items |
663
- | `pages` | `T[][]` | Raw page arrays |
664
- | `fetchNextPage` | `(limit?) => void` | Load next page |
665
- | `hasNextPage` | `boolean` | More pages exist |
666
- | `status` | `PaginationStatus` | `'LoadingFirstPage' \| 'LoadingMore' \| 'CanLoadMore' \| 'Exhausted'` |
667
- | `isPlaceholderData` | `boolean` | Showing placeholder |
660
+ Return fields: flattened `data`, raw `pages`, `fetchNextPage(limit?)`,
661
+ `hasNextPage`, `status`, and `isPlaceholderData`. Status is one of
662
+ `LoadingFirstPage`, `LoadingMore`, `CanLoadMore`, or `Exhausted`.
@@ -728,58 +728,19 @@ Then sanity-check auth runtime paths:
728
728
  16. Phase A gate (Section 11.2) passes before any auth implementation.
729
729
  17. If auth enabled: Phase B auth sign-in gate (Section 11.3) passes before optional modules/plugins.
730
730
  18. No legacy Ents patterns in setup code.
731
- 19. NEVER use `@ts-nocheck` in app/convex source files.
731
+ 19. Do not use `@ts-nocheck` in app/convex source files.
732
732
 
733
733
  ## 13. Troubleshooting
734
734
 
735
735
  See the [Troubleshooting Reference](#troubleshooting-reference) at the bottom of this document for the full symptom/cause/fix matrix.
736
736
 
737
- ## Coverage Matrix
738
-
739
- Source coverage mapping used to build this runbook:
740
-
741
- | Source | Mapped In Setup |
742
- | ------------------------------------------------- | -------------------- |
743
- | `www/content/docs/cli/registry.mdx` | Sections 3, 11 |
744
- | `www/content/docs/quickstart.mdx` | Sections 3, 4, 11, 12 |
745
- | `www/content/docs/server/setup.mdx` | Section 5.3 |
746
- | `www/content/docs/auth/server.mdx` | Sections 6.1 - 6.10 |
747
- | `www/content/docs/auth/client.mdx` | Section 7.1 |
748
- | `www/content/docs/auth/server.mdx#triggers` | Section 6.3, 9.2 |
749
- | `www/content/docs/react/index.mdx` | Sections 7.2 - 7.4 |
750
- | `www/content/docs/nextjs/index.mdx` | Section 8.A |
751
- | `www/content/docs/tanstack-start.mdx` | Section 8.B |
752
- | `www/content/docs/server/http.mdx` | Sections 6.6, 9.6 |
753
- | `www/content/docs/server/server-side-calls.mdx` | Section 8.A.1, 8.B.3 |
754
- | `www/content/docs/plugins/ratelimit.mdx` | Section 9.4 |
755
- | `www/content/docs/orm/queries/aggregates.mdx` | Section 9.3 |
756
- | `www/content/docs/server/scheduling.mdx` | Section 9.5 |
757
- | `www/content/docs/orm/queries/index.mdx` | Sections 5, 12 |
758
- | `www/content/docs/orm/mutations/index.mdx` | Sections 5, 12 |
759
- | `www/content/docs/orm/triggers.mdx` | Sections 9.2, 9.3 |
760
- | `www/content/docs/orm/rls.mdx` | Section 9.1 |
761
- | `www/content/docs/auth/plugins/admin.mdx` | Section 10.1 |
762
- | `www/content/docs/auth/plugins/organizations.mdx` | Section 10.2 |
763
- | `www/content/docs/auth/plugins/polar.mdx` | Section 10.3 |
764
- | `www/content/docs/cli/backend.mdx` | Section 11 |
765
-
766
- ### Template Coverage (Recreation Target)
767
-
768
- This runbook + references map to the canonical template shape as follows:
769
-
770
- | Example Group | Primary Setup Section | Additional Reference |
771
- | --------------------------------------------------------------------------------------------------------- | ------------------------------- | ---------------------------------------- |
772
- | Core infra (`schema.ts`, `functions/generated/`, `crpc.ts`, `http.ts`) | Sections 5, 6.6, 9.6 | `orm.md`, `http.md` |
773
- | Shared contracts (`shared/api.ts`, `shared/auth-shared.ts`, `shared/polar-shared.ts`) | Sections 5.4, 6.3.2, 10.2, 10.3 | `auth-organizations.md` |
774
- | Auth core (`auth.config.ts`, `auth.ts`) | Section 6 | `auth.md` |
775
- | Auth plugins (`admin.ts`, `organization.ts`, `polar*`) | Section 10 | `auth-admin.md`, `auth-organizations.md` |
776
- | Feature modules (`user.ts`, `projects.ts`, `tags.ts`, `todoComments.ts`, `public.ts`, `items/queries.ts`) | Sections 5, 6.3.1, 9 | core `SKILL.md`, `orm.md` |
777
- | HTTP routers (`routers/health.ts`, `routers/todos.ts`, `routers/examples.ts`) | Section 9.6 | `http.md` |
778
- | Aggregates + rate limits (`aggregates.ts`, `lib/plugins/ratelimit/plugin.ts`) | Sections 9.3, 9.4 | `aggregates.md`, `orm.md` |
779
- | Scheduling + internals (`todoInternal.ts`, delayed jobs) | Sections 9.5, 11.1 | `scheduling.md` |
780
- | Email + Resend (`functions/plugins/email.tsx`, `lib/plugins/resend/*`) | Section 9.7 | `auth-organizations.md` |
781
- | Dev bootstrap (`init.ts`, `seed.ts`, `reset.ts`) | Section 11.1 | `testing.md` (for verification) |
782
- | Generated outputs (`functions/_generated/*`, `functions/generated/`, `shared/api.ts`) | Section 5.5 | n/a (generated by CLI) |
737
+ ## Coverage Notes
738
+
739
+ This setup runbook compresses the CLI registry, quickstart, server setup,
740
+ auth, React, Next.js, TanStack Start, HTTP, scheduling, aggregate, ORM,
741
+ RLS/trigger, plugin, and backend CLI docs. Use the feature references for
742
+ domain depth: `orm.md`, `http.md`, `react.md`, `aggregates.md`,
743
+ `scheduling.md`, `testing.md`, `auth*.md`, and `create-plugins.md`.
783
744
 
784
745
  ## Troubleshooting Reference
785
746