gencow 0.1.80 → 0.1.82

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/bin/gencow.mjs CHANGED
@@ -2,16 +2,14 @@
2
2
  /**
3
3
  * @gencow/cli — Gencow CLI
4
4
  *
5
- * Like `npx convex dev` but for Gencow projects.
6
- *
7
5
  * Commands:
8
6
  * gencow dev — push schema → start server with hot-reload
9
- * gencow db:push — push schema.ts changes to DB (Convex-like, no migration files)
7
+ * gencow db:push — push schema.ts changes to DB (instant, no migration files)
10
8
  * gencow db:generate — generate SQL migration files from schema.ts
11
9
  * gencow db:migrate — apply pending migrations
12
10
  * gencow db:reset — backup + reset DB (safe reset)
13
11
  * gencow db:restore — restore DB from backup
14
- * gencow db:studio — open Drizzle Studio (like Convex dashboard)
12
+ * gencow db:studio — open Drizzle Studio (visual DB browser)
15
13
  * gencow dashboard — open /_admin in browser
16
14
  * gencow backup — manage database backups (list/create/restore/delete/download)
17
15
  * gencow help — show this help
@@ -1351,7 +1349,7 @@ ${hasPrompt ? `
1351
1349
  async "db:studio"() {
1352
1350
  const config = loadConfig();
1353
1351
  log(`\n${BOLD}${CYAN}Gencow DB Studio${RESET}\n`);
1354
- info("Opening Drizzle Studio (Convex Dashboard equivalent)...");
1352
+ info("Opening Drizzle Studio...");
1355
1353
  runInServer("pnpm db:studio", buildEnv(config));
1356
1354
  },
1357
1355
 
@@ -1739,12 +1737,14 @@ ${BOLD}Examples:${RESET}
1739
1737
  }
1740
1738
 
1741
1739
  // 1-0. Pre-deploy dependency audit (informational — user deps auto-installed)
1740
+ // + Phase B: filter package.json to backend-only deps
1741
+ let auditResult = null;
1742
1742
  if (!forceDeploy) {
1743
1743
  try {
1744
1744
  const { auditDeployDependencies, formatAuditError } = await import("../lib/deploy-auditor.mjs");
1745
1745
  const entryPoint = resolve(process.cwd(), "gencow", "index.ts");
1746
1746
  if (existsSync(entryPoint)) {
1747
- const auditResult = await auditDeployDependencies(entryPoint);
1747
+ auditResult = await auditDeployDependencies(entryPoint);
1748
1748
  const auditMsg = formatAuditError(auditResult);
1749
1749
  if (auditMsg) log(auditMsg);
1750
1750
  }
@@ -1753,13 +1753,61 @@ ${BOLD}Examples:${RESET}
1753
1753
  }
1754
1754
  }
1755
1755
 
1756
+ // Generate filtered package.json with only backend runtime deps
1757
+ let useFilteredPkg = false;
1758
+ const filteredPkgPath = resolve(process.cwd(), ".gencow", "deploy-package.json");
1759
+ if (auditResult?.runtimeDeps?.length >= 0) {
1760
+ try {
1761
+ const projectPkg = JSON.parse(readFileSync(resolve(process.cwd(), "package.json"), "utf8"));
1762
+ const allDeps = { ...projectPkg.dependencies, ...projectPkg.devDependencies };
1763
+ const runtimeDeps = {};
1764
+ for (const dep of auditResult.runtimeDeps) {
1765
+ if (allDeps[dep]) runtimeDeps[dep] = allDeps[dep];
1766
+ }
1767
+ const filteredPkg = { name: projectPkg.name || "gencow-app", dependencies: runtimeDeps };
1768
+ writeFileSync(filteredPkgPath, JSON.stringify(filteredPkg, null, 2));
1769
+ useFilteredPkg = true;
1770
+
1771
+ const totalDeps = Object.keys(allDeps).length;
1772
+ const runtimeCount = Object.keys(runtimeDeps).length;
1773
+ if (totalDeps > runtimeCount) {
1774
+ info(`${DIM}package.json 필터링: ${runtimeCount}/${totalDeps} 패키지만 서버에 설치됩니다.${RESET}`);
1775
+ }
1776
+ } catch {
1777
+ // Fallback: use original package.json
1778
+ useFilteredPkg = false;
1779
+ }
1780
+ }
1781
+
1756
1782
  try {
1757
- exec(`tar -czf "${tmpBundle}" ${filesToPack.join(" ")}`, { cwd: process.cwd() });
1783
+ if (useFilteredPkg) {
1784
+ // macOS-safe: stage files in temp dir with filtered package.json
1785
+ const otherFiles = filesToPack.filter(f => f !== "package.json");
1786
+ const tmpDir = resolve(process.cwd(), ".gencow", "deploy-staging");
1787
+ mkdirSync(tmpDir, { recursive: true });
1788
+ writeFileSync(resolve(tmpDir, "package.json"), readFileSync(filteredPkgPath, "utf8"));
1789
+ for (const f of otherFiles) {
1790
+ const src = resolve(process.cwd(), f);
1791
+ const dst = resolve(tmpDir, f);
1792
+ if (f.endsWith("/")) {
1793
+ exec(`cp -r "${src}" "${dst}"`, { cwd: process.cwd() });
1794
+ } else if (existsSync(src)) {
1795
+ exec(`cp "${src}" "${dst}"`, { cwd: process.cwd() });
1796
+ }
1797
+ }
1798
+ exec(`tar -czf "${tmpBundle}" .`, { cwd: tmpDir });
1799
+ exec(`rm -rf "${tmpDir}"`, { cwd: process.cwd() });
1800
+ } else {
1801
+ exec(`tar -czf "${tmpBundle}" ${filesToPack.join(" ")}`, { cwd: process.cwd() });
1802
+ }
1758
1803
  } catch (e) {
1759
1804
  error(`패키징 실패: ${e.message}`);
1760
1805
  process.exit(1);
1761
1806
  }
1762
1807
 
1808
+ // Clean up temp filtered package.json
1809
+ try { if (useFilteredPkg) unlinkSync(filteredPkgPath); } catch {}
1810
+
1763
1811
  const bundleSize = statSync(tmpBundle).size;
1764
1812
  success(`번들 생성: ${(bundleSize / 1024).toFixed(1)} KB`);
1765
1813
 
@@ -2011,13 +2059,14 @@ ${BOLD}Examples:${RESET}
2011
2059
  if (shouldDeployBackend) {
2012
2060
  log(` ${BOLD}── 백엔드 배포 ──────────────────────${RESET}\n`);
2013
2061
 
2014
- // 1-0. Pre-deploy dependency audit (informational user deps auto-installed)
2062
+ // 1-0. Pre-deploy dependency audit + Phase B: filter package.json
2063
+ let auditResult = null;
2015
2064
  if (!forceDeploy) {
2016
2065
  try {
2017
2066
  const { auditDeployDependencies, formatAuditError } = await import("../lib/deploy-auditor.mjs");
2018
2067
  const entryPoint = resolve(backendRoot, "gencow", "index.ts");
2019
2068
  if (existsSync(entryPoint)) {
2020
- const auditResult = await auditDeployDependencies(entryPoint);
2069
+ auditResult = await auditDeployDependencies(entryPoint);
2021
2070
  const auditMsg = formatAuditError(auditResult);
2022
2071
  if (auditMsg) log(auditMsg);
2023
2072
  }
@@ -2037,12 +2086,57 @@ ${BOLD}Examples:${RESET}
2037
2086
  if (existsSync(resolve(backendRoot, "package-lock.json"))) backendFiles.push("package-lock.json");
2038
2087
  if (existsSync(resolve(backendRoot, "tsconfig.json"))) backendFiles.push("tsconfig.json");
2039
2088
 
2089
+ // Generate filtered package.json with only backend runtime deps
2090
+ let useFilteredPkg = false;
2091
+ const filteredPkgPath = resolve(backendRoot, ".gencow", "deploy-package.json");
2092
+ if (auditResult?.runtimeDeps?.length >= 0) {
2093
+ try {
2094
+ const projectPkg = JSON.parse(readFileSync(resolve(backendRoot, "package.json"), "utf8"));
2095
+ const allDeps = { ...projectPkg.dependencies, ...projectPkg.devDependencies };
2096
+ const runtimeDeps = {};
2097
+ for (const dep of auditResult.runtimeDeps) {
2098
+ if (allDeps[dep]) runtimeDeps[dep] = allDeps[dep];
2099
+ }
2100
+ const filteredPkg = { name: projectPkg.name || "gencow-app", dependencies: runtimeDeps };
2101
+ writeFileSync(filteredPkgPath, JSON.stringify(filteredPkg, null, 2));
2102
+ useFilteredPkg = true;
2103
+
2104
+ const totalDeps = Object.keys(allDeps).length;
2105
+ const runtimeCount = Object.keys(runtimeDeps).length;
2106
+ if (totalDeps > runtimeCount) {
2107
+ info(`${DIM}package.json 필터링: ${runtimeCount}/${totalDeps} 패키지만 서버에 설치됩니다.${RESET}`);
2108
+ }
2109
+ } catch {
2110
+ useFilteredPkg = false;
2111
+ }
2112
+ }
2113
+
2040
2114
  try {
2041
- exec(`tar -czf "${tmpBackendBundle}" ${backendFiles.join(" ")}`, { cwd: backendRoot });
2115
+ if (useFilteredPkg) {
2116
+ const otherFiles = backendFiles.filter(f => f !== "package.json");
2117
+ // macOS-safe: stage files in temp dir
2118
+ const tmpDir = resolve(backendRoot, ".gencow", "deploy-staging");
2119
+ mkdirSync(tmpDir, { recursive: true });
2120
+ writeFileSync(resolve(tmpDir, "package.json"), readFileSync(filteredPkgPath, "utf8"));
2121
+ for (const f of otherFiles) {
2122
+ const src = resolve(backendRoot, f);
2123
+ const dst = resolve(tmpDir, f);
2124
+ if (f.endsWith("/")) {
2125
+ exec(`cp -r "${src}" "${dst}"`, { cwd: backendRoot });
2126
+ } else if (existsSync(src)) {
2127
+ exec(`cp "${src}" "${dst}"`, { cwd: backendRoot });
2128
+ }
2129
+ }
2130
+ exec(`tar -czf "${tmpBackendBundle}" .`, { cwd: tmpDir });
2131
+ exec(`rm -rf "${tmpDir}"`, { cwd: backendRoot });
2132
+ } else {
2133
+ exec(`tar -czf "${tmpBackendBundle}" ${backendFiles.join(" ")}`, { cwd: backendRoot });
2134
+ }
2042
2135
  } catch (e) {
2043
2136
  error(`백엔드 패키징 실패: ${e.message}`);
2044
2137
  process.exit(1);
2045
2138
  }
2139
+ try { if (useFilteredPkg) unlinkSync(filteredPkgPath); } catch {}
2046
2140
 
2047
2141
  const backendBundleSize = statSync(tmpBackendBundle).size;
2048
2142
  success(`백엔드 번들 생성: ${(backendBundleSize / 1024).toFixed(1)} KB`);
@@ -2837,7 +2931,7 @@ process.exit(0);
2837
2931
  // Save current app to creds
2838
2932
  saveCreds({ ...creds, currentApp: name });
2839
2933
 
2840
- // ── Scaffold local project files (Convex-like) ──────────
2934
+ // ── Scaffold local project files ────────────────────
2841
2935
  const cwd = process.cwd();
2842
2936
  const config = loadConfig();
2843
2937
 
package/core/index.js CHANGED
@@ -1822,23 +1822,348 @@ function intervalToPattern(options) {
1822
1822
  function defineAuth(config) {
1823
1823
  return config;
1824
1824
  }
1825
+
1826
+ // ../core/src/table.ts
1827
+ import { pgTable } from "drizzle-orm/pg-core";
1828
+ import { eq } from "drizzle-orm";
1829
+ function isOwnerFilter(opts) {
1830
+ return "_ownerColumn" in opts;
1831
+ }
1832
+ if (!globalThis.__gencow_tableAccessRegistry) {
1833
+ globalThis.__gencow_tableAccessRegistry = /* @__PURE__ */ new Map();
1834
+ }
1835
+ var tableAccessRegistry = globalThis.__gencow_tableAccessRegistry;
1836
+ function gencowTable(name, columns, options) {
1837
+ if (!options || typeof options.filter !== "function" && !isOwnerFilter(options)) {
1838
+ throw new Error(
1839
+ `[gencow] gencowTable("${name}") requires a filter option. Use ownerFilter("userId") for simple user isolation, or { filter: () => true } for public tables.`
1840
+ );
1841
+ }
1842
+ const table = pgTable(name, columns);
1843
+ let filter;
1844
+ if (isOwnerFilter(options)) {
1845
+ const columnName = options._ownerColumn;
1846
+ const col = table[columnName];
1847
+ if (!col) {
1848
+ throw new Error(
1849
+ `[gencow] ownerFilter("${columnName}"): column "${columnName}" not found on table "${name}". Available columns: ${Object.keys(table).filter((k) => !k.startsWith("_") && !k.startsWith("$")).join(", ")}`
1850
+ );
1851
+ }
1852
+ filter = (ctx) => {
1853
+ const user = ctx.auth.requireAuth();
1854
+ return eq(col, user.id);
1855
+ };
1856
+ } else {
1857
+ filter = options.filter;
1858
+ }
1859
+ tableAccessRegistry.set(table, {
1860
+ filter,
1861
+ fieldAccess: options.fieldAccess,
1862
+ tableName: name
1863
+ });
1864
+ return table;
1865
+ }
1866
+ function ownerFilter(columnName = "userId") {
1867
+ return {
1868
+ _ownerColumn: columnName,
1869
+ // Placeholder filter — replaced by gencowTable()
1870
+ filter: () => {
1871
+ throw new Error("[gencow] ownerFilter placeholder should not be called directly");
1872
+ }
1873
+ };
1874
+ }
1875
+ function getTableAccessMeta(table) {
1876
+ return tableAccessRegistry.get(table);
1877
+ }
1878
+ function isGencowTable(table) {
1879
+ return tableAccessRegistry.has(table);
1880
+ }
1881
+ function getAllGencowTables() {
1882
+ return new Map(tableAccessRegistry);
1883
+ }
1884
+
1885
+ // ../core/src/scoped-db.ts
1886
+ import { and } from "drizzle-orm";
1887
+ function createScopedDb(db, ctx) {
1888
+ return new Proxy(db, {
1889
+ get(target, prop) {
1890
+ const propStr = typeof prop === "string" ? prop : "";
1891
+ if (propStr === "execute") {
1892
+ return () => {
1893
+ throw new Error(
1894
+ "[gencow] ctx.db.execute() is not allowed. Use ctx.db.select().from(table) for type-safe queries with automatic access control. If you need raw SQL, use ctx.unsafeDb.execute()."
1895
+ );
1896
+ };
1897
+ }
1898
+ if (propStr === "$client" || propStr === "_") {
1899
+ throw new Error(
1900
+ `[gencow] ctx.db.${propStr} is not allowed. Direct database client access bypasses access control. Use ctx.unsafeDb if you need direct access.`
1901
+ );
1902
+ }
1903
+ if (propStr === "select") {
1904
+ return (...selectArgs) => {
1905
+ const selectResult = target.select(...selectArgs);
1906
+ return wrapSelectChain(selectResult, ctx);
1907
+ };
1908
+ }
1909
+ if (propStr === "update") {
1910
+ return (table) => {
1911
+ const updateResult = target.update(table);
1912
+ return wrapWriteChain(updateResult, table, ctx);
1913
+ };
1914
+ }
1915
+ if (propStr === "delete") {
1916
+ return (table) => {
1917
+ const deleteResult = target.delete(table);
1918
+ return wrapWriteChain(deleteResult, table, ctx);
1919
+ };
1920
+ }
1921
+ if (propStr === "query") {
1922
+ return wrapRelationalQuery(target.query, ctx);
1923
+ }
1924
+ const value = target[prop];
1925
+ if (typeof value === "function") {
1926
+ return value.bind(target);
1927
+ }
1928
+ return value;
1929
+ }
1930
+ });
1931
+ }
1932
+ function wrapSelectChain(selectResult, ctx) {
1933
+ return new Proxy(selectResult, {
1934
+ get(target, prop) {
1935
+ const propStr = typeof prop === "string" ? prop : "";
1936
+ if (propStr === "from") {
1937
+ return (table, ...restArgs) => {
1938
+ const fromResult = target.from(table, ...restArgs);
1939
+ const meta = getTableAccessMeta(table);
1940
+ if (meta) {
1941
+ return wrapFromChain(fromResult, ctx, [{ table, meta }]);
1942
+ }
1943
+ return wrapFromChain(fromResult, ctx, []);
1944
+ };
1945
+ }
1946
+ const value = target[prop];
1947
+ if (typeof value === "function") {
1948
+ return value.bind(target);
1949
+ }
1950
+ return value;
1951
+ }
1952
+ });
1953
+ }
1954
+ function wrapFromChain(chain, ctx, pendingFilters) {
1955
+ return new Proxy(chain, {
1956
+ get(target, prop) {
1957
+ const propStr = typeof prop === "string" ? prop : "";
1958
+ if (["leftJoin", "rightJoin", "innerJoin", "fullJoin"].includes(propStr)) {
1959
+ return (joinTable, ...joinArgs) => {
1960
+ const joinResult = target[propStr](joinTable, ...joinArgs);
1961
+ const joinMeta = getTableAccessMeta(joinTable);
1962
+ const newFilters = joinMeta ? [...pendingFilters, { table: joinTable, meta: joinMeta }] : pendingFilters;
1963
+ return wrapFromChain(joinResult, ctx, newFilters);
1964
+ };
1965
+ }
1966
+ if (propStr === "where") {
1967
+ return (...whereArgs) => {
1968
+ const combinedFilter = buildCombinedFilter(pendingFilters, ctx);
1969
+ if (combinedFilter) {
1970
+ const userWhere = whereArgs[0];
1971
+ const merged = userWhere ? and(userWhere, combinedFilter) : combinedFilter;
1972
+ const result = target.where(merged);
1973
+ return wrapFromChain(result, ctx, []);
1974
+ }
1975
+ return wrapFromChain(target.where(...whereArgs), ctx, []);
1976
+ };
1977
+ }
1978
+ if (propStr === "then" || propStr === "execute") {
1979
+ if (pendingFilters.length > 0) {
1980
+ const combinedFilter = buildCombinedFilter(pendingFilters, ctx);
1981
+ if (combinedFilter) {
1982
+ const filtered = target.where(combinedFilter);
1983
+ return filtered[prop].bind(filtered);
1984
+ }
1985
+ }
1986
+ const value2 = target[prop];
1987
+ return typeof value2 === "function" ? value2.bind(target) : value2;
1988
+ }
1989
+ const value = target[prop];
1990
+ if (typeof value === "function") {
1991
+ return (...args) => {
1992
+ const result = value.apply(target, args);
1993
+ if (result && typeof result === "object" && typeof result.then === "function") {
1994
+ return wrapFromChain(result, ctx, pendingFilters);
1995
+ }
1996
+ if (result && typeof result === "object" && "where" in result) {
1997
+ return wrapFromChain(result, ctx, pendingFilters);
1998
+ }
1999
+ return result;
2000
+ };
2001
+ }
2002
+ return value;
2003
+ }
2004
+ });
2005
+ }
2006
+ function wrapWriteChain(chain, table, ctx) {
2007
+ const meta = getTableAccessMeta(table);
2008
+ if (!meta) {
2009
+ return chain;
2010
+ }
2011
+ return new Proxy(chain, {
2012
+ get(target, prop) {
2013
+ const propStr = typeof prop === "string" ? prop : "";
2014
+ if (propStr === "where") {
2015
+ return (...whereArgs) => {
2016
+ const filterResult = evaluateFilterSync(meta, ctx);
2017
+ if (typeof filterResult === "boolean") {
2018
+ if (!filterResult) {
2019
+ return target.where(whereArgs[0]);
2020
+ }
2021
+ return target.where(...whereArgs);
2022
+ }
2023
+ const userWhere = whereArgs[0];
2024
+ const merged = userWhere ? and(userWhere, filterResult) : filterResult;
2025
+ return target.where(merged);
2026
+ };
2027
+ }
2028
+ if (propStr === "then" || propStr === "execute" || propStr === "returning") {
2029
+ const filterResult = evaluateFilterSync(meta, ctx);
2030
+ if (filterResult && typeof filterResult !== "boolean") {
2031
+ const filtered = target.where(filterResult);
2032
+ const value3 = filtered[prop];
2033
+ return typeof value3 === "function" ? value3.bind(filtered) : value3;
2034
+ }
2035
+ const value2 = target[prop];
2036
+ return typeof value2 === "function" ? value2.bind(target) : value2;
2037
+ }
2038
+ const value = target[prop];
2039
+ if (typeof value === "function") {
2040
+ return value.bind(target);
2041
+ }
2042
+ return value;
2043
+ }
2044
+ });
2045
+ }
2046
+ function wrapRelationalQuery(queryObj, ctx) {
2047
+ if (!queryObj) return queryObj;
2048
+ return new Proxy(queryObj, {
2049
+ get(target, tableName) {
2050
+ const tableProxy = target[tableName];
2051
+ if (!tableProxy || typeof tableProxy !== "object") return tableProxy;
2052
+ return new Proxy(tableProxy, {
2053
+ get(tableTarget, method) {
2054
+ const methodStr = typeof method === "string" ? method : "";
2055
+ if (methodStr === "findMany" || methodStr === "findFirst") {
2056
+ return (args = {}) => {
2057
+ const meta = findMetaByTableName(String(tableName));
2058
+ if (meta) {
2059
+ const filterResult = evaluateFilterSync(meta, ctx);
2060
+ if (filterResult && typeof filterResult !== "boolean") {
2061
+ args.where = args.where ? and(args.where, filterResult) : filterResult;
2062
+ } else if (filterResult === false) {
2063
+ args.where = args.where;
2064
+ }
2065
+ }
2066
+ return tableTarget[method](args);
2067
+ };
2068
+ }
2069
+ const value = tableTarget[method];
2070
+ if (typeof value === "function") {
2071
+ return value.bind(tableTarget);
2072
+ }
2073
+ return value;
2074
+ }
2075
+ });
2076
+ }
2077
+ });
2078
+ }
2079
+ function buildCombinedFilter(pendingFilters, ctx) {
2080
+ const sqlConditions = [];
2081
+ for (const { meta } of pendingFilters) {
2082
+ const result = evaluateFilterSync(meta, ctx);
2083
+ if (result === false) {
2084
+ const { sql: sqlTag } = __require("drizzle-orm");
2085
+ return sqlTag`1 = 0`;
2086
+ }
2087
+ if (result === true) {
2088
+ continue;
2089
+ }
2090
+ if (result) {
2091
+ sqlConditions.push(result);
2092
+ }
2093
+ }
2094
+ if (sqlConditions.length === 0) return null;
2095
+ if (sqlConditions.length === 1) return sqlConditions[0];
2096
+ return and(...sqlConditions) ?? null;
2097
+ }
2098
+ function evaluateFilterSync(meta, ctx) {
2099
+ const result = meta.filter(ctx);
2100
+ if (result instanceof Promise) {
2101
+ throw new Error(
2102
+ `[gencow] Async filter on table "${meta.tableName}" is not supported in synchronous context. Use synchronous filters for schema-level access control.`
2103
+ );
2104
+ }
2105
+ return result;
2106
+ }
2107
+ function findMetaByTableName(name) {
2108
+ for (const [, meta] of globalThis.__gencow_tableAccessRegistry || []) {
2109
+ if (meta.tableName === name) return meta;
2110
+ }
2111
+ return void 0;
2112
+ }
2113
+ function applyFieldAccess(result, table, ctx) {
2114
+ const meta = getTableAccessMeta(table);
2115
+ if (!meta?.fieldAccess) return result;
2116
+ const fieldAccess = meta.fieldAccess;
2117
+ const maskedFields = [];
2118
+ for (const [field, rule] of Object.entries(fieldAccess)) {
2119
+ try {
2120
+ if (!rule.read(ctx)) {
2121
+ maskedFields.push(field);
2122
+ }
2123
+ } catch {
2124
+ maskedFields.push(field);
2125
+ }
2126
+ }
2127
+ if (maskedFields.length === 0) return result;
2128
+ const maskRow = (row) => {
2129
+ if (!row || typeof row !== "object") return row;
2130
+ const masked = { ...row };
2131
+ for (const field of maskedFields) {
2132
+ if (field in masked) {
2133
+ masked[field] = null;
2134
+ }
2135
+ }
2136
+ return masked;
2137
+ };
2138
+ if (Array.isArray(result)) {
2139
+ return result.map(maskRow);
2140
+ }
2141
+ return maskRow(result);
2142
+ }
1825
2143
  export {
1826
2144
  GencowValidationError,
2145
+ applyFieldAccess,
1827
2146
  buildRealtimeCtx,
1828
2147
  createScheduler,
2148
+ createScopedDb,
1829
2149
  cronJobs,
1830
2150
  defineAuth,
1831
2151
  deregisterClient,
2152
+ gencowTable,
2153
+ getAllGencowTables,
1832
2154
  getQueryDef,
1833
2155
  getQueryHandler,
1834
2156
  getRegisteredHttpActions,
1835
2157
  getRegisteredMutations,
1836
2158
  getRegisteredQueries,
1837
2159
  getSchedulerInfo,
2160
+ getTableAccessMeta,
1838
2161
  handleWsMessage,
1839
2162
  httpAction,
1840
2163
  invalidateQueries,
2164
+ isGencowTable,
1841
2165
  mutation,
2166
+ ownerFilter,
1842
2167
  parseArgs,
1843
2168
  query,
1844
2169
  registerClient,