zitejs 0.10.0-start.7 → 0.10.0-start.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.
Files changed (64) hide show
  1. package/dist/cjs/auth/index.d.ts +2 -2
  2. package/dist/cjs/check/index.d.ts +33 -1
  3. package/dist/cjs/check/index.js +136 -86
  4. package/dist/cjs/check/start/describeRules.d.ts +35 -0
  5. package/dist/cjs/check/start/describeRules.js +89 -0
  6. package/dist/cjs/check/start/problem.d.ts +11 -0
  7. package/dist/cjs/check/start/problem.js +5 -0
  8. package/dist/cjs/check/start/sourceRules.d.ts +3 -0
  9. package/dist/cjs/check/start/sourceRules.js +441 -0
  10. package/dist/cjs/cli.js +1 -1
  11. package/dist/cjs/sync/lib.js +4 -7
  12. package/dist/cjs/vite/index.js +8 -3
  13. package/dist/cjs/vite/index.test.js +10 -2
  14. package/dist/esm/auth/index.d.ts +2 -2
  15. package/dist/esm/check/index.d.ts +33 -1
  16. package/dist/esm/check/index.js +135 -88
  17. package/dist/esm/check/start/describeRules.d.ts +35 -0
  18. package/dist/esm/check/start/describeRules.js +86 -0
  19. package/dist/esm/check/start/problem.d.ts +11 -0
  20. package/dist/esm/check/start/problem.js +1 -0
  21. package/dist/esm/check/start/sourceRules.d.ts +3 -0
  22. package/dist/esm/check/start/sourceRules.js +438 -0
  23. package/dist/esm/cli.js +1 -1
  24. package/dist/esm/start/airtable/arrayFields.d.ts +10 -0
  25. package/dist/esm/start/airtable/arrayFields.js +30 -0
  26. package/dist/esm/start/airtable/dispatch.d.ts +54 -0
  27. package/dist/esm/start/airtable/dispatch.js +465 -0
  28. package/dist/esm/start/airtable/formulas.d.ts +69 -0
  29. package/dist/esm/start/airtable/formulas.js +235 -0
  30. package/dist/esm/start/airtable/index.d.ts +11 -0
  31. package/dist/esm/start/airtable/index.js +70 -0
  32. package/dist/esm/start/data/baseRunner.d.ts +92 -0
  33. package/dist/esm/start/data/baseRunner.js +83 -0
  34. package/dist/esm/start/data/dispatch.d.ts +16 -0
  35. package/dist/esm/start/data/dispatch.js +198 -0
  36. package/dist/esm/start/data/index.d.ts +18 -0
  37. package/dist/esm/start/data/index.js +76 -0
  38. package/dist/esm/start/data/sqlNameMappings.d.ts +58 -0
  39. package/dist/esm/start/data/sqlNameMappings.js +92 -0
  40. package/dist/esm/start/data/transformations.d.ts +128 -0
  41. package/dist/esm/start/data/transformations.js +318 -0
  42. package/dist/esm/start/data/types.d.ts +91 -0
  43. package/dist/esm/start/data/types.js +14 -0
  44. package/dist/esm/start/describe.d.ts +5 -0
  45. package/dist/esm/start/describe.js +8 -1
  46. package/dist/esm/start/errors.d.ts +5 -0
  47. package/dist/esm/start/errors.js +5 -0
  48. package/dist/esm/start/factories.test-d.d.ts +1 -0
  49. package/dist/esm/start/factories.test-d.js +20 -0
  50. package/dist/esm/start/index.d.ts +7 -4
  51. package/dist/esm/start/index.js +2 -5
  52. package/dist/esm/start/router.d.ts +1 -0
  53. package/dist/esm/start/router.js +7 -3
  54. package/dist/esm/start/server.js +54 -5
  55. package/dist/esm/start/types.d.ts +40 -0
  56. package/dist/esm/start/version.d.ts +1 -1
  57. package/dist/esm/start/version.js +1 -1
  58. package/dist/esm/start/vite.js +2 -1
  59. package/dist/esm/start/workflow.d.ts +3 -0
  60. package/dist/esm/start/workflow.test-d.js +5 -0
  61. package/dist/esm/sync/lib.js +4 -7
  62. package/dist/esm/vite/index.js +8 -3
  63. package/dist/esm/vite/index.test.js +10 -2
  64. package/package.json +1 -1
@@ -67,7 +67,7 @@ export declare const signIn: {
67
67
  }, FetchOptions["throw"] extends true ? true : false>>;
68
68
  } & {
69
69
  social: <FetchOptions extends import("@better-auth/core").ClientFetchOption<Partial<{
70
- provider: "salesforce" | "slack" | "linear" | "notion" | "linkedin" | "github" | "dropbox" | (string & {}) | "huggingface" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "spotify" | "twitch" | "twitter" | "kick" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "zoom" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
70
+ provider: "salesforce" | "slack" | "linear" | "notion" | "linkedin" | "github" | "dropbox" | "line" | (string & {}) | "huggingface" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "spotify" | "twitch" | "twitter" | "kick" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "zoom" | "kakao" | "naver" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
71
71
  callbackURL?: string | undefined;
72
72
  newUserCallbackURL?: string | undefined;
73
73
  errorCallbackURL?: string | undefined;
@@ -91,7 +91,7 @@ export declare const signIn: {
91
91
  loginHint?: string | undefined;
92
92
  additionalData?: Record<string, any> | undefined;
93
93
  }> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth/react").Prettify<{
94
- provider: "salesforce" | "slack" | "linear" | "notion" | "linkedin" | "github" | "dropbox" | (string & {}) | "huggingface" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "spotify" | "twitch" | "twitter" | "kick" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "zoom" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
94
+ provider: "salesforce" | "slack" | "linear" | "notion" | "linkedin" | "github" | "dropbox" | "line" | (string & {}) | "huggingface" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "spotify" | "twitch" | "twitter" | "kick" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "zoom" | "kakao" | "naver" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
95
95
  callbackURL?: string | undefined;
96
96
  newUserCallbackURL?: string | undefined;
97
97
  errorCallbackURL?: string | undefined;
@@ -1 +1,33 @@
1
- export declare function runCheck(): Promise<void>;
1
+ import { type Problem } from './start/problem.js';
2
+ type Step = {
3
+ name: string;
4
+ ok: boolean;
5
+ output?: string;
6
+ };
7
+ /** One app's check, as `--json` reports it. */
8
+ export type AppCheck = {
9
+ path: string;
10
+ runtime: 'classic' | 'start';
11
+ ok: boolean;
12
+ steps: Step[];
13
+ problems: Problem[];
14
+ };
15
+ /**
16
+ * While `--json` checks, stdout carries only the report: app code that logs as
17
+ * it's described in-process goes to stderr instead.
18
+ */
19
+ export declare const withStdoutOnStderr: <T>(run: () => Promise<T>) => Promise<T>;
20
+ /** Prints as it goes, or with `--json` stays quiet and reports everything at the end. */
21
+ export declare class Reporter {
22
+ private readonly json;
23
+ readonly apps: AppCheck[];
24
+ constructor(json: boolean);
25
+ app(path: string, runtime: AppCheck['runtime'], heading: boolean): AppCheck;
26
+ step(app: AppCheck, name: string, result: {
27
+ ok: boolean;
28
+ output?: string;
29
+ }): boolean;
30
+ problems(app: AppCheck, problems: Problem[]): void;
31
+ }
32
+ export declare function runCheck(args?: string[]): Promise<void>;
33
+ export {};
@@ -33,11 +33,13 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Reporter = exports.withStdoutOnStderr = void 0;
36
37
  exports.runCheck = runCheck;
37
38
  const child_process_1 = require("child_process");
38
39
  const fs_1 = require("fs");
39
40
  const path_1 = require("path");
40
41
  const sourceRoots_js_1 = require("../sourceRoots.js");
42
+ const problem_js_1 = require("./start/problem.js");
41
43
  /**
42
44
  * An argument array, not a command string, so no shell is involved.
43
45
  *
@@ -93,41 +95,134 @@ function bundleFailures(output) {
93
95
  }
94
96
  const indent = (output) => output.trim().split('\n').map(l => ` ${l}`).join('\n');
95
97
  /**
96
- * A Start app: `vite build` first, since it regenerates the route tree tsc
97
- * reads, then tsc, then describe, which reports what the platform's build
98
- * refuses, read the same way.
98
+ * While `--json` checks, stdout carries only the report: app code that logs as
99
+ * it's described in-process goes to stderr instead.
99
100
  */
100
- async function checkStartApp(appPath) {
101
- process.stdout.write(' vite build ... ');
102
- const vite = run('npx', ['vite', 'build'], appPath);
103
- console.log(vite.ok ? '✓' : '✗');
104
- if (!vite.ok) {
105
- console.log(indent(vite.output));
101
+ const withStdoutOnStderr = async (run) => {
102
+ const write = process.stdout.write;
103
+ process.stdout.write = process.stderr.write.bind(process.stderr);
104
+ try {
105
+ return await run();
106
+ }
107
+ finally {
108
+ process.stdout.write = write;
109
+ }
110
+ };
111
+ exports.withStdoutOnStderr = withStdoutOnStderr;
112
+ /** Prints as it goes, or with `--json` stays quiet and reports everything at the end. */
113
+ class Reporter {
114
+ json;
115
+ apps = [];
116
+ constructor(json) {
117
+ this.json = json;
118
+ }
119
+ app(path, runtime, heading) {
120
+ const app = { path, runtime, ok: true, steps: [], problems: [] };
121
+ this.apps.push(app);
122
+ if (heading && !this.json)
123
+ console.log(`\n── ${path} ──`);
124
+ return app;
125
+ }
126
+ step(app, name, result) {
127
+ const output = result.output?.trim();
128
+ app.steps.push({ name, ok: result.ok, ...(output && !result.ok && { output }) });
129
+ if (!result.ok)
130
+ app.ok = false;
131
+ if (!this.json) {
132
+ console.log(` ${name} ... ${result.ok ? '✓' : '✗'}`);
133
+ if (!result.ok && output)
134
+ console.log(indent(output));
135
+ }
136
+ return result.ok;
137
+ }
138
+ problems(app, problems) {
139
+ app.problems.push(...problems);
140
+ if (problems.some(p => p.severity === 'error'))
141
+ app.ok = false;
142
+ if (!this.json && problems.length)
143
+ console.log(problems.map(p => ` ${(0, problem_js_1.formatProblem)(p)}`).join('\n'));
144
+ }
145
+ }
146
+ exports.Reporter = Reporter;
147
+ const SKIPPED_DIRS = new Set(['node_modules', 'dist', '.output', '.tanstack', '.wrangler']);
148
+ /** The app's own source, by app-relative path. */
149
+ function readAppSources(appPath) {
150
+ const sources = {};
151
+ const visit = (dir) => {
152
+ for (const entry of (0, fs_1.readdirSync)(dir, { withFileTypes: true })) {
153
+ if (SKIPPED_DIRS.has(entry.name))
154
+ continue;
155
+ const full = (0, path_1.join)(dir, entry.name);
156
+ if (entry.isDirectory())
157
+ visit(full);
158
+ else if (/\.[cm]?[jt]sx?$/.test(entry.name))
159
+ sources[(0, path_1.relative)(appPath, full)] = (0, fs_1.readFileSync)(full, 'utf-8');
160
+ }
161
+ };
162
+ const src = (0, path_1.join)(appPath, 'src');
163
+ if ((0, fs_1.existsSync)(src))
164
+ visit(src);
165
+ return sources;
166
+ }
167
+ const isInternalApp = (appPath) => {
168
+ try {
169
+ return JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(appPath, 'zite.config.json'), 'utf-8'))?.accessMode === 'internal';
170
+ }
171
+ catch {
106
172
  return false;
107
173
  }
108
- process.stdout.write(' tsc --noEmit ... ');
174
+ };
175
+ /**
176
+ * A Start app: `vite build` first, since it regenerates the route tree tsc
177
+ * reads, then tsc, then describe, which reports what the platform's build
178
+ * refuses, read the same way, then the source hints.
179
+ */
180
+ async function checkStartApp(reporter, app, appPath) {
181
+ if (!reporter.step(app, 'vite build', run('npx', ['vite', 'build'], appPath)))
182
+ return;
109
183
  // --pretty for `file:line:col - error` lines, the shape the platform re-roots.
110
- const tsc = run('npx', ['tsc', '--noEmit', '--pretty', '-p', 'tsconfig.app.json'], appPath);
111
- console.log(tsc.ok ? '✓' : '✗');
112
- if (!tsc.ok)
113
- console.log(indent(tsc.output));
114
- process.stdout.write(' describe ... ');
184
+ reporter.step(app, 'tsc --noEmit', run('npx', ['tsc', '--noEmit', '--pretty', '-p', 'tsconfig.app.json'], appPath));
185
+ const { describedProblems } = await Promise.resolve().then(() => __importStar(require('./start/describeRules.js')));
186
+ const { sourceProblems } = await Promise.resolve().then(() => __importStar(require('./start/sourceRules.js')));
115
187
  try {
116
188
  const { describeBuiltApp } = await Promise.resolve().then(() => __importStar(require('../start/describeBuilt.js')));
117
- const { descriptionProblems } = await Promise.resolve().then(() => __importStar(require('../start/problems.js')));
118
- const problems = descriptionProblems((await describeBuiltApp(appPath)));
119
- console.log(problems.length ? '✗' : '✓');
120
- if (problems.length)
121
- console.log(problems.map(p => ` ${p}`).join('\n'));
122
- return tsc.ok && problems.length === 0;
189
+ const description = (await describeBuiltApp(appPath));
190
+ const problems = describedProblems(description, { internal: isInternalApp(appPath) });
191
+ reporter.step(app, 'describe', { ok: !problems.some(p => p.severity === 'error') });
192
+ reporter.problems(app, problems);
123
193
  }
124
194
  catch (err) {
125
- console.log('✗');
126
- console.log(` ${err instanceof Error ? err.message : String(err)}`);
127
- return false;
195
+ reporter.step(app, 'describe', { ok: false, output: err instanceof Error ? err.message : String(err) });
196
+ }
197
+ const hints = sourceProblems(readAppSources(appPath));
198
+ reporter.step(app, 'source', { ok: !hints.some(p => p.severity === 'error') });
199
+ reporter.problems(app, hints);
200
+ }
201
+ function checkClassicApp(reporter, app, root, dir, appPath) {
202
+ // Only tsconfig.app.json compiles anything. The app's tsconfig.json is a
203
+ // solution-style config — `"files": []` plus a reference — so
204
+ // `tsc --noEmit -p tsconfig.json` type-checks zero files and exits 0. It
205
+ // used to be the fallback, which meant an app missing tsconfig.app.json
206
+ // reported a passing typecheck it never ran.
207
+ const tsconfigAppPath = (0, path_1.join)(appPath, 'tsconfig.app.json');
208
+ reporter.step(app, 'tsc --noEmit', (0, fs_1.existsSync)(tsconfigAppPath)
209
+ ? run('npx', ['tsc', '--noEmit', '-p', tsconfigAppPath], '.')
210
+ : { ok: false, output: `no ${tsconfigAppPath}` });
211
+ // Endpoints never reach vite — they are bundled separately for the lambda,
212
+ // against a different resolver. tsc and vite both pass on an endpoint whose
213
+ // `zitejs/*` alias has no generated file behind it; only the bundler knows.
214
+ if ((0, sourceRoots_js_1.listEndpointNames)(root, appPath).length > 0) {
215
+ const bundle = run('npx', ['zitejs', 'bundle', '--app', dir], '.');
216
+ const failures = bundle.ok ? bundleFailures(bundle.output) : [bundle.output];
217
+ reporter.step(app, 'bundle endpoints', { ok: failures.length === 0, output: failures.join('\n') });
218
+ }
219
+ if ((0, fs_1.existsSync)((0, path_1.join)(appPath, 'vite.config.ts'))) {
220
+ reporter.step(app, 'vite build', run('npx', ['vite', 'build'], appPath));
128
221
  }
129
222
  }
130
- async function runCheck() {
223
+ async function runCheck(args = process.argv.slice(3)) {
224
+ const json = args.includes('--json');
225
+ const reporter = new Reporter(json);
131
226
  const { isStartAppDir } = await Promise.resolve().then(() => __importStar(require('../start/entries.js')));
132
227
  // Run inside a Start app, its own zitejs checks just that app: the workspace
133
228
  // root's is a classic release that doesn't know Start.
@@ -137,72 +232,27 @@ async function runCheck() {
137
232
  console.error('No apps or automations found under apps/ or automations/.');
138
233
  process.exit(1);
139
234
  }
140
- let allPassed = inStartApp ? await checkStartApp('.') : true;
141
- for (const { root, dir: app, path: appPath } of appDirs) {
142
- console.log(`\n── ${appPath} ──`);
143
- if (isStartAppDir(appPath)) {
144
- if (!(await checkStartApp(appPath)))
145
- allPassed = false;
146
- continue;
147
- }
148
- // Only tsconfig.app.json compiles anything. The app's tsconfig.json is a
149
- // solution-style config — `"files": []` plus a reference — so
150
- // `tsc --noEmit -p tsconfig.json` type-checks zero files and exits 0. It
151
- // used to be the fallback, which meant an app missing tsconfig.app.json
152
- // reported a passing typecheck it never ran.
153
- const tsconfigAppPath = (0, path_1.join)(appPath, 'tsconfig.app.json');
154
- if (!(0, fs_1.existsSync)(tsconfigAppPath)) {
155
- console.log(` tsc --noEmit ... ✗ (no ${tsconfigAppPath})`);
156
- allPassed = false;
157
- }
158
- else {
159
- process.stdout.write(' tsc --noEmit ... ');
160
- const tsc = run('npx', ['tsc', '--noEmit', '-p', tsconfigAppPath], '.');
161
- if (tsc.ok) {
162
- console.log('✓');
235
+ const checkAll = async () => {
236
+ if (inStartApp)
237
+ await checkStartApp(reporter, reporter.app('.', 'start', false), '.');
238
+ for (const { root, dir, path: appPath } of appDirs) {
239
+ if (isStartAppDir(appPath)) {
240
+ await checkStartApp(reporter, reporter.app(appPath, 'start', true), appPath);
163
241
  }
164
242
  else {
165
- console.log('✗');
166
- console.log(tsc.output.trim().split('\n').map(l => ` ${l}`).join('\n'));
167
- allPassed = false;
243
+ checkClassicApp(reporter, reporter.app(appPath, 'classic', true), root, dir, appPath);
168
244
  }
169
245
  }
170
- // Endpoints never reach vite — they are bundled separately for the lambda,
171
- // against a different resolver. tsc and vite both pass on an endpoint whose
172
- // `zitejs/*` alias has no generated file behind it; only the bundler knows.
173
- if ((0, sourceRoots_js_1.listEndpointNames)(root, appPath).length > 0) {
174
- process.stdout.write(' bundle endpoints ... ');
175
- const bundle = run('npx', ['zitejs', 'bundle', '--app', app], '.');
176
- const failures = bundle.ok ? bundleFailures(bundle.output) : [bundle.output];
177
- if (failures.length === 0) {
178
- console.log('✓');
179
- }
180
- else {
181
- console.log('✗');
182
- console.log(failures.map(l => ` ${l}`).join('\n'));
183
- allPassed = false;
184
- }
185
- }
186
- const viteConfig = (0, path_1.join)(appPath, 'vite.config.ts');
187
- if ((0, fs_1.existsSync)(viteConfig)) {
188
- process.stdout.write(' vite build ... ');
189
- const vite = run('npx', ['vite', 'build'], appPath);
190
- if (vite.ok) {
191
- console.log('✓');
192
- }
193
- else {
194
- console.log('✗');
195
- console.log(vite.output.trim().split('\n').map(l => ` ${l}`).join('\n'));
196
- allPassed = false;
197
- }
198
- }
199
- }
200
- console.log('');
201
- if (allPassed) {
202
- console.log('All apps pass.');
246
+ };
247
+ await (json ? (0, exports.withStdoutOnStderr)(checkAll) : checkAll());
248
+ const allPassed = reporter.apps.every(app => app.ok);
249
+ if (json) {
250
+ process.stdout.write(`${JSON.stringify({ ok: allPassed, apps: reporter.apps })}\n`);
203
251
  }
204
252
  else {
205
- console.log('Some apps failed.');
206
- process.exit(1);
253
+ console.log('');
254
+ console.log(allPassed ? 'All apps pass.' : 'Some apps failed.');
207
255
  }
256
+ if (!allPassed)
257
+ process.exit(1);
208
258
  }
@@ -0,0 +1,35 @@
1
+ import type { Problem } from "./problem.js";
2
+ type Access = {
3
+ kind: string;
4
+ roles?: string[];
5
+ };
6
+ export type CheckedDescription = {
7
+ functions: Array<{
8
+ id: string;
9
+ name?: string;
10
+ file?: string;
11
+ access: Access;
12
+ input?: unknown;
13
+ problems: string[];
14
+ }>;
15
+ routes: Array<{
16
+ path: string;
17
+ file?: string;
18
+ description?: string;
19
+ methods: Record<string, Access>;
20
+ problems: string[];
21
+ }>;
22
+ pages?: Array<{
23
+ path: string;
24
+ file?: string;
25
+ }>;
26
+ workflows?: Array<{
27
+ id: string;
28
+ file: string;
29
+ problems: string[];
30
+ }>;
31
+ };
32
+ export declare function describedProblems(description: CheckedDescription, { internal }: {
33
+ internal: boolean;
34
+ }): Problem[];
35
+ export {};
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describedProblems = describedProblems;
4
+ // The host, TanStack and Cloudflare answer these before the app does.
5
+ const RESERVED_PATHS = [
6
+ /^\/_zite/,
7
+ /^\/__zite/,
8
+ /^\/_serverFn(\/|$)/,
9
+ /^\/cdn-cgi(\/|$)/,
10
+ /^\/auth(\/|$)/,
11
+ /^\/api\/auth(\/|$)/,
12
+ /^\/manifest\.webmanifest$/,
13
+ ];
14
+ const OWNER_INPUTS = ["userId", "ownerId"];
15
+ /** `access-missing: no signedIn…`, or a route's `GET: access-missing: …`, as a named problem. */
16
+ const describeProblem = (problem, subject, file) => {
17
+ const match = /^(?:(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|ANY): )?([a-z][a-z-]*): (.*)$/s.exec(problem);
18
+ const [, method, rule, message] = match ?? [undefined, undefined, "describe", problem];
19
+ return {
20
+ rule: rule ?? "describe",
21
+ severity: "error",
22
+ ...(file && { file }),
23
+ message: `${subject}${method ? ` ${method}` : ""}: ${message ?? problem}`,
24
+ };
25
+ };
26
+ const inputProperties = (input) => {
27
+ const properties = input?.properties;
28
+ return properties && typeof properties === "object" ? Object.keys(properties) : [];
29
+ };
30
+ function describedProblems(description, { internal }) {
31
+ const problems = [];
32
+ for (const fn of description.functions) {
33
+ const subject = `function ${fn.name ?? fn.id}`;
34
+ problems.push(...fn.problems.map((p) => describeProblem(p, subject, fn.file)));
35
+ if (internal && fn.access.kind === "anyone") {
36
+ problems.push({
37
+ rule: "public-in-internal",
38
+ severity: "error",
39
+ ...(fn.file && { file: fn.file }),
40
+ message: `${subject} is a publicFn, and this internal app signs everyone in; make it a signedInFn`,
41
+ });
42
+ }
43
+ const owner = fn.access.kind === "signedIn" && inputProperties(fn.input).find((p) => OWNER_INPUTS.includes(p));
44
+ if (owner) {
45
+ problems.push({
46
+ rule: "owner-from-input",
47
+ severity: "warning",
48
+ ...(fn.file && { file: fn.file }),
49
+ message: `${subject} takes ${owner} as input, which any caller can set; use context.user.id`,
50
+ });
51
+ }
52
+ }
53
+ for (const route of description.routes) {
54
+ const subject = `route ${route.path}`;
55
+ problems.push(...route.problems.map((p) => describeProblem(p, subject, route.file)));
56
+ const publicMethods = Object.entries(route.methods).filter(([, access]) => access.kind === "anyone");
57
+ if (internal && publicMethods.length > 0) {
58
+ problems.push({
59
+ rule: "public-in-internal",
60
+ severity: "error",
61
+ ...(route.file && { file: route.file }),
62
+ message: `${subject} lets anyone call ${publicMethods.map(([m]) => m).join(", ")}, and this internal app signs everyone in; use signedIn`,
63
+ });
64
+ }
65
+ if (!route.description) {
66
+ problems.push({
67
+ rule: "description-missing",
68
+ severity: "warning",
69
+ ...(route.file && { file: route.file }),
70
+ message: `${subject} has no description; add staticData: { description } for the editor`,
71
+ });
72
+ }
73
+ }
74
+ for (const workflow of description.workflows ?? []) {
75
+ problems.push(...workflow.problems.map((p) => describeProblem(p, `workflow ${workflow.id}`, workflow.file)));
76
+ }
77
+ const paths = new Map([...description.routes, ...(description.pages ?? [])].map((r) => [r.path, r.file]));
78
+ for (const [path, file] of paths) {
79
+ if (RESERVED_PATHS.some((reserved) => reserved.test(path))) {
80
+ problems.push({
81
+ rule: "reserved-path",
82
+ severity: "error",
83
+ ...(file && { file }),
84
+ message: `${path} is the platform's; give the route another path`,
85
+ });
86
+ }
87
+ }
88
+ return problems;
89
+ }
@@ -0,0 +1,11 @@
1
+ export type Severity = "error" | "warning";
2
+ /** One finding of `zitejs check`, named by its rule. Errors fail the check; warnings only report. */
3
+ export type Problem = {
4
+ rule: string;
5
+ severity: Severity;
6
+ /** App-relative. */
7
+ file?: string;
8
+ line?: number;
9
+ message: string;
10
+ };
11
+ export declare const formatProblem: ({ rule, severity, file, line, message }: Problem) => string;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatProblem = void 0;
4
+ const formatProblem = ({ rule, severity, file, line, message }) => `${severity} ${rule}${file ? ` ${file}${line ? `:${line}` : ""}` : ""}: ${message}`;
5
+ exports.formatProblem = formatProblem;
@@ -0,0 +1,3 @@
1
+ import type { Problem } from "./problem.js";
2
+ /** Every source hint for one Start app, given its files by app-relative path. */
3
+ export declare function sourceProblems(sources: Record<string, string>): Problem[];