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.
- package/dist/{backend-core-CQmXi2Q0.mjs → backend-core-CRJpuVnf.mjs} +252 -11
- package/dist/cli.mjs +1 -1
- package/dist/react/index.d.ts +6 -2
- package/dist/react/index.js +5 -4
- package/dist/solid/index.d.ts +14 -3
- package/dist/solid/index.js +5 -2
- package/dist/watcher.mjs +1 -1
- package/package.json +1 -1
- package/skills/kitcn/SKILL.md +6 -7
- package/skills/kitcn/references/features/auth-admin.md +3 -19
- package/skills/kitcn/references/features/auth-organizations.md +3 -21
- package/skills/kitcn/references/features/auth-polar.md +5 -16
- package/skills/kitcn/references/features/auth.md +14 -9
- package/skills/kitcn/references/features/http.md +17 -45
- package/skills/kitcn/references/features/orm.md +22 -44
- package/skills/kitcn/references/features/react.md +3 -8
- package/skills/kitcn/references/setup/index.md +8 -47
|
@@ -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$
|
|
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$
|
|
7381
|
+
const skipWhitespace$2 = (source, start) => {
|
|
7382
7382
|
let index = start;
|
|
7383
|
-
while (index < source.length && WHITESPACE_RE$
|
|
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$
|
|
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-
|
|
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";
|
package/dist/react/index.d.ts
CHANGED
|
@@ -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:
|
|
112
|
+
useSignInMutationOptions: SignInMutationOptionsHook<unknown, unknown>;
|
|
109
113
|
useSignUpMutationOptions: MutationOptionsHook<unknown, unknown>;
|
|
110
114
|
};
|
|
111
115
|
declare function createAuthMutations(authClient: AuthClient): AuthMutationsResult;
|
package/dist/react/index.js
CHANGED
|
@@ -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
|
-
...
|
|
1579
|
+
...mutationOptions,
|
|
1579
1580
|
mutationFn: async (args) => {
|
|
1580
|
-
const
|
|
1581
|
-
if (typeof
|
|
1582
|
-
const res = await callAuthMethod(
|
|
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);
|
package/dist/solid/index.d.ts
CHANGED
|
@@ -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:
|
|
176
|
+
useSignInMutationOptions: SignInMutationOptionsHook<T>;
|
|
166
177
|
useSignUpMutationOptions: MutationOptionsHook<Awaited<ReturnType<T['signUp']['email']>>, Parameters<T['signUp']['email']>[0]>;
|
|
167
178
|
};
|
|
168
179
|
/**
|
package/dist/solid/index.js
CHANGED
|
@@ -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
|
-
...
|
|
1733
|
+
...mutationOptions,
|
|
1733
1734
|
mutationFn: async (args) => {
|
|
1734
|
-
const
|
|
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-
|
|
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
package/skills/kitcn/SKILL.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kitcn
|
|
3
|
-
description:
|
|
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
|
|
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
|
|
54
|
-
21. **`create<Module>Handler(ctx)`**
|
|
55
|
-
22. **`create<Module>Caller(ctx)`**
|
|
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
|
|
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
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
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
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
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
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
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
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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.
|
|
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
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
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
|
|