@polardbx/pxbaas 0.0.0-stage → 0.1.0-beta.1

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 (264) hide show
  1. package/bin/pxbaas.js +13 -0
  2. package/dist/app/preflight.d.ts +38 -0
  3. package/dist/app/preflight.d.ts.map +1 -0
  4. package/dist/app/preflight.js +79 -0
  5. package/dist/app/preflight.js.map +1 -0
  6. package/dist/app/spec-lint.d.ts +45 -0
  7. package/dist/app/spec-lint.d.ts.map +1 -0
  8. package/dist/app/spec-lint.js +407 -0
  9. package/dist/app/spec-lint.js.map +1 -0
  10. package/dist/app/templates.d.ts +143 -0
  11. package/dist/app/templates.d.ts.map +1 -0
  12. package/dist/app/templates.js +151 -0
  13. package/dist/app/templates.js.map +1 -0
  14. package/dist/cli/root.d.ts +3 -0
  15. package/dist/cli/root.d.ts.map +1 -0
  16. package/dist/cli/root.js +69 -0
  17. package/dist/cli/root.js.map +1 -0
  18. package/dist/commands/app/index.d.ts +8 -0
  19. package/dist/commands/app/index.d.ts.map +1 -0
  20. package/dist/commands/app/index.js +1267 -0
  21. package/dist/commands/app/index.js.map +1 -0
  22. package/dist/commands/auth/index.d.ts +3 -0
  23. package/dist/commands/auth/index.d.ts.map +1 -0
  24. package/dist/commands/auth/index.js +198 -0
  25. package/dist/commands/auth/index.js.map +1 -0
  26. package/dist/commands/completion/index.d.ts +3 -0
  27. package/dist/commands/completion/index.d.ts.map +1 -0
  28. package/dist/commands/completion/index.js +10 -0
  29. package/dist/commands/completion/index.js.map +1 -0
  30. package/dist/commands/data/index.d.ts +3 -0
  31. package/dist/commands/data/index.d.ts.map +1 -0
  32. package/dist/commands/data/index.js +245 -0
  33. package/dist/commands/data/index.js.map +1 -0
  34. package/dist/commands/db/index.d.ts +14 -0
  35. package/dist/commands/db/index.d.ts.map +1 -0
  36. package/dist/commands/db/index.js +355 -0
  37. package/dist/commands/db/index.js.map +1 -0
  38. package/dist/commands/doctor/index.d.ts +3 -0
  39. package/dist/commands/doctor/index.d.ts.map +1 -0
  40. package/dist/commands/doctor/index.js +305 -0
  41. package/dist/commands/doctor/index.js.map +1 -0
  42. package/dist/commands/functions/delete.d.ts +3 -0
  43. package/dist/commands/functions/delete.d.ts.map +1 -0
  44. package/dist/commands/functions/delete.js +55 -0
  45. package/dist/commands/functions/delete.js.map +1 -0
  46. package/dist/commands/functions/deploy.d.ts +3 -0
  47. package/dist/commands/functions/deploy.d.ts.map +1 -0
  48. package/dist/commands/functions/deploy.js +118 -0
  49. package/dist/commands/functions/deploy.js.map +1 -0
  50. package/dist/commands/functions/index.d.ts +3 -0
  51. package/dist/commands/functions/index.d.ts.map +1 -0
  52. package/dist/commands/functions/index.js +15 -0
  53. package/dist/commands/functions/index.js.map +1 -0
  54. package/dist/commands/functions/list.d.ts +6 -0
  55. package/dist/commands/functions/list.d.ts.map +1 -0
  56. package/dist/commands/functions/list.js +63 -0
  57. package/dist/commands/functions/list.js.map +1 -0
  58. package/dist/commands/functions/new.d.ts +3 -0
  59. package/dist/commands/functions/new.d.ts.map +1 -0
  60. package/dist/commands/functions/new.js +57 -0
  61. package/dist/commands/functions/new.js.map +1 -0
  62. package/dist/commands/gen/index.d.ts +3 -0
  63. package/dist/commands/gen/index.d.ts.map +1 -0
  64. package/dist/commands/gen/index.js +320 -0
  65. package/dist/commands/gen/index.js.map +1 -0
  66. package/dist/commands/instance/index.d.ts +8 -0
  67. package/dist/commands/instance/index.d.ts.map +1 -0
  68. package/dist/commands/instance/index.js +361 -0
  69. package/dist/commands/instance/index.js.map +1 -0
  70. package/dist/commands/login/index.d.ts +3 -0
  71. package/dist/commands/login/index.d.ts.map +1 -0
  72. package/dist/commands/login/index.js +185 -0
  73. package/dist/commands/login/index.js.map +1 -0
  74. package/dist/commands/login/login.d.ts +3 -0
  75. package/dist/commands/login/login.d.ts.map +1 -0
  76. package/dist/commands/login/login.js +185 -0
  77. package/dist/commands/login/login.js.map +1 -0
  78. package/dist/commands/logout/index.d.ts +3 -0
  79. package/dist/commands/logout/index.d.ts.map +1 -0
  80. package/dist/commands/logout/index.js +41 -0
  81. package/dist/commands/logout/index.js.map +1 -0
  82. package/dist/commands/profile/import-env.d.ts +13 -0
  83. package/dist/commands/profile/import-env.d.ts.map +1 -0
  84. package/dist/commands/profile/import-env.js +81 -0
  85. package/dist/commands/profile/import-env.js.map +1 -0
  86. package/dist/commands/profile/index.d.ts +3 -0
  87. package/dist/commands/profile/index.d.ts.map +1 -0
  88. package/dist/commands/profile/index.js +109 -0
  89. package/dist/commands/profile/index.js.map +1 -0
  90. package/dist/commands/rest/index.d.ts +3 -0
  91. package/dist/commands/rest/index.d.ts.map +1 -0
  92. package/dist/commands/rest/index.js +102 -0
  93. package/dist/commands/rest/index.js.map +1 -0
  94. package/dist/commands/skill/index.d.ts +11 -0
  95. package/dist/commands/skill/index.d.ts.map +1 -0
  96. package/dist/commands/skill/index.js +153 -0
  97. package/dist/commands/skill/index.js.map +1 -0
  98. package/dist/commands/status/index.d.ts +3 -0
  99. package/dist/commands/status/index.d.ts.map +1 -0
  100. package/dist/commands/status/index.js +59 -0
  101. package/dist/commands/status/index.js.map +1 -0
  102. package/dist/commands/storage/index.d.ts +3 -0
  103. package/dist/commands/storage/index.d.ts.map +1 -0
  104. package/dist/commands/storage/index.js +198 -0
  105. package/dist/commands/storage/index.js.map +1 -0
  106. package/dist/commands/whoami/index.d.ts +3 -0
  107. package/dist/commands/whoami/index.d.ts.map +1 -0
  108. package/dist/commands/whoami/index.js +82 -0
  109. package/dist/commands/whoami/index.js.map +1 -0
  110. package/dist/credentials/commit.d.ts +38 -0
  111. package/dist/credentials/commit.d.ts.map +1 -0
  112. package/dist/credentials/commit.js +57 -0
  113. package/dist/credentials/commit.js.map +1 -0
  114. package/dist/credentials/credential-store.d.ts +57 -0
  115. package/dist/credentials/credential-store.d.ts.map +1 -0
  116. package/dist/credentials/credential-store.js +180 -0
  117. package/dist/credentials/credential-store.js.map +1 -0
  118. package/dist/credentials/env-file.d.ts +44 -0
  119. package/dist/credentials/env-file.d.ts.map +1 -0
  120. package/dist/credentials/env-file.js +118 -0
  121. package/dist/credentials/env-file.js.map +1 -0
  122. package/dist/credentials/formatter.d.ts +39 -0
  123. package/dist/credentials/formatter.d.ts.map +1 -0
  124. package/dist/credentials/formatter.js +79 -0
  125. package/dist/credentials/formatter.js.map +1 -0
  126. package/dist/credentials/index.d.ts +11 -0
  127. package/dist/credentials/index.d.ts.map +1 -0
  128. package/dist/credentials/index.js +11 -0
  129. package/dist/credentials/index.js.map +1 -0
  130. package/dist/credentials/jwt-introspect.d.ts +32 -0
  131. package/dist/credentials/jwt-introspect.d.ts.map +1 -0
  132. package/dist/credentials/jwt-introspect.js +64 -0
  133. package/dist/credentials/jwt-introspect.js.map +1 -0
  134. package/dist/credentials/masker.d.ts +20 -0
  135. package/dist/credentials/masker.d.ts.map +1 -0
  136. package/dist/credentials/masker.js +37 -0
  137. package/dist/credentials/masker.js.map +1 -0
  138. package/dist/credentials/profile.d.ts +83 -0
  139. package/dist/credentials/profile.d.ts.map +1 -0
  140. package/dist/credentials/profile.js +184 -0
  141. package/dist/credentials/profile.js.map +1 -0
  142. package/dist/credentials/tenant-guard.d.ts +16 -0
  143. package/dist/credentials/tenant-guard.d.ts.map +1 -0
  144. package/dist/credentials/tenant-guard.js +53 -0
  145. package/dist/credentials/tenant-guard.js.map +1 -0
  146. package/dist/credentials/tty-guard.d.ts +19 -0
  147. package/dist/credentials/tty-guard.d.ts.map +1 -0
  148. package/dist/credentials/tty-guard.js +47 -0
  149. package/dist/credentials/tty-guard.js.map +1 -0
  150. package/dist/db/apply-schema.d.ts +57 -0
  151. package/dist/db/apply-schema.d.ts.map +1 -0
  152. package/dist/db/apply-schema.js +192 -0
  153. package/dist/db/apply-schema.js.map +1 -0
  154. package/dist/db/sql-file.d.ts +49 -0
  155. package/dist/db/sql-file.d.ts.map +1 -0
  156. package/dist/db/sql-file.js +167 -0
  157. package/dist/db/sql-file.js.map +1 -0
  158. package/dist/instance/provision.d.ts +89 -0
  159. package/dist/instance/provision.d.ts.map +1 -0
  160. package/dist/instance/provision.js +139 -0
  161. package/dist/instance/provision.js.map +1 -0
  162. package/dist/instance/zero-store.d.ts +47 -0
  163. package/dist/instance/zero-store.d.ts.map +1 -0
  164. package/dist/instance/zero-store.js +91 -0
  165. package/dist/instance/zero-store.js.map +1 -0
  166. package/dist/main.d.ts +3 -0
  167. package/dist/main.d.ts.map +1 -0
  168. package/dist/main.js +46 -0
  169. package/dist/main.js.map +1 -0
  170. package/dist/skill/assets.d.ts +38 -0
  171. package/dist/skill/assets.d.ts.map +1 -0
  172. package/dist/skill/assets.js +111 -0
  173. package/dist/skill/assets.js.map +1 -0
  174. package/dist/skill/hint.d.ts +39 -0
  175. package/dist/skill/hint.d.ts.map +1 -0
  176. package/dist/skill/hint.js +109 -0
  177. package/dist/skill/hint.js.map +1 -0
  178. package/dist/skill/hosts.d.ts +21 -0
  179. package/dist/skill/hosts.d.ts.map +1 -0
  180. package/dist/skill/hosts.js +38 -0
  181. package/dist/skill/hosts.js.map +1 -0
  182. package/dist/skill/installer.d.ts +88 -0
  183. package/dist/skill/installer.d.ts.map +1 -0
  184. package/dist/skill/installer.js +203 -0
  185. package/dist/skill/installer.js.map +1 -0
  186. package/dist/skill/ownership.d.ts +35 -0
  187. package/dist/skill/ownership.d.ts.map +1 -0
  188. package/dist/skill/ownership.js +52 -0
  189. package/dist/skill/ownership.js.map +1 -0
  190. package/package.json +63 -3
  191. package/skills/pxbaas-app-spec/SKILL.md +163 -0
  192. package/skills/pxbaas-app-spec/references/deploy-options.md +157 -0
  193. package/skills/pxbaas-app-spec/references/guardrails-pitfalls.md +89 -0
  194. package/skills/pxbaas-app-spec/references/runtime-contract.md +151 -0
  195. package/skills/pxbaas-app-spec/references/ssr-session.md +121 -0
  196. package/skills/pxbaas-app-spec/references/templates-examples.md +308 -0
  197. package/skills/pxbaas-cli/SKILL.md +168 -0
  198. package/skills/pxbaas-cli/references/api-reference.md +68 -0
  199. package/skills/pxbaas-cli/references/app-deploy.md +143 -0
  200. package/skills/pxbaas-cli/references/auth-and-credentials.md +88 -0
  201. package/skills/pxbaas-cli/references/data-postgrest.md +85 -0
  202. package/skills/pxbaas-cli/references/db-and-meta.md +85 -0
  203. package/skills/pxbaas-cli/references/edge-functions.md +71 -0
  204. package/skills/pxbaas-cli/references/multi-tenant-apps.md +107 -0
  205. package/skills/pxbaas-cli/references/provision.md +86 -0
  206. package/skills/pxbaas-cli/references/safety-and-two-phase.md +49 -0
  207. package/skills/pxbaas-cli/references/storage.md +61 -0
  208. package/skills/pxbaas-cli/references/troubleshooting.md +73 -0
  209. package/templates/webapp/api/index.ts +55 -0
  210. package/templates/webapp/csr-bff/README.md +81 -0
  211. package/templates/webapp/csr-bff/backend/index.ts +168 -0
  212. package/templates/webapp/csr-bff/db/schema.sql +69 -0
  213. package/templates/webapp/csr-bff/frontend/dist/admin.html +101 -0
  214. package/templates/webapp/csr-bff/frontend/dist/article.html +44 -0
  215. package/templates/webapp/csr-bff/frontend/dist/blog.js +206 -0
  216. package/templates/webapp/csr-bff/frontend/dist/blogger.html +53 -0
  217. package/templates/webapp/csr-bff/frontend/dist/index.html +70 -0
  218. package/templates/webapp/csr-bff/frontend/dist/login.html +56 -0
  219. package/templates/webapp/csr-bff/frontend/dist/profile.html +59 -0
  220. package/templates/webapp/csr-bff/frontend/dist/signup.html +78 -0
  221. package/templates/webapp/csr-bff/frontend/dist/style.css +27 -0
  222. package/templates/webapp/manifest.json +296 -0
  223. package/templates/webapp/mpa/about.html +29 -0
  224. package/templates/webapp/mpa/app.js +42 -0
  225. package/templates/webapp/mpa/index.html +42 -0
  226. package/templates/webapp/mpa/index.ts +60 -0
  227. package/templates/webapp/mpa/style.css +42 -0
  228. package/templates/webapp/react-vite/frontend/index.html +12 -0
  229. package/templates/webapp/react-vite/frontend/package-lock.json +1826 -0
  230. package/templates/webapp/react-vite/frontend/package.json +23 -0
  231. package/templates/webapp/react-vite/frontend/src/App.tsx +34 -0
  232. package/templates/webapp/react-vite/frontend/src/main.tsx +13 -0
  233. package/templates/webapp/react-vite/frontend/src/style.css +46 -0
  234. package/templates/webapp/react-vite/frontend/tsconfig.json +20 -0
  235. package/templates/webapp/react-vite/frontend/vite.config.ts +10 -0
  236. package/templates/webapp/react-vite-hono/backend/index.ts +21 -0
  237. package/templates/webapp/react-vite-hono/frontend/index.html +12 -0
  238. package/templates/webapp/react-vite-hono/frontend/package-lock.json +1826 -0
  239. package/templates/webapp/react-vite-hono/frontend/package.json +23 -0
  240. package/templates/webapp/react-vite-hono/frontend/src/App.tsx +47 -0
  241. package/templates/webapp/react-vite-hono/frontend/src/main.tsx +13 -0
  242. package/templates/webapp/react-vite-hono/frontend/src/style.css +66 -0
  243. package/templates/webapp/react-vite-hono/frontend/tsconfig.json +20 -0
  244. package/templates/webapp/react-vite-hono/frontend/vite.config.ts +10 -0
  245. package/templates/webapp/spa/index.ts +119 -0
  246. package/templates/webapp/ssr-auth/backend/index.ts +133 -0
  247. package/templates/webapp/ssr-auth/frontend/dist/index.html +15 -0
  248. package/templates/webapp/ssr-blog/README.md +111 -0
  249. package/templates/webapp/ssr-blog/backend/index.ts +764 -0
  250. package/templates/webapp/ssr-blog/db/schema.sql +71 -0
  251. package/templates/webapp/ssr-blog/frontend/dist/index.html +39 -0
  252. package/templates/webapp/ssr-frameworks/README.md +64 -0
  253. package/templates/webapp/ssr-frameworks/backend/index.ts +241 -0
  254. package/templates/webapp/ssr-frameworks/frontend/dist/index.html +31 -0
  255. package/templates/webapp/ssr-hono/backend/index.ts +92 -0
  256. package/templates/webapp/ssr-hono/frontend/dist/index.html +12 -0
  257. package/templates/webapp/ssr-shop/README.md +80 -0
  258. package/templates/webapp/ssr-shop/backend/index.ts +491 -0
  259. package/templates/webapp/ssr-shop/db/schema.sql +120 -0
  260. package/templates/webapp/ssr-shop/frontend/dist/index.html +12 -0
  261. package/templates/webapp/vanilla-static/frontend/app.js +6 -0
  262. package/templates/webapp/vanilla-static/frontend/index.html +19 -0
  263. package/templates/webapp/vanilla-static/frontend/style.css +43 -0
  264. package/README.md +0 -3
package/bin/pxbaas.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { fileURLToPath } from 'node:url';
4
+ import { dirname, join } from 'node:path';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ // Import and run the CLI
10
+ import(join(__dirname, '..', 'dist', 'main.js')).catch((err) => {
11
+ console.error('Failed to start CLI:', err);
12
+ process.exit(1);
13
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Preflight guardrails for `pxbaas app deploy`.
3
+ *
4
+ * These checks encode the edge-function sandbox constraints (see doc 02 and the
5
+ * sandbox webapp evaluation): 5-function quota, no root-absolute asset refs
6
+ * (they escape the /functions/v1/ prefix onto Studio), and cross-machine sharing
7
+ * requires a public endpoint (sandbox URLs are internal).
8
+ */
9
+ export interface QuotaCheck {
10
+ used: number;
11
+ limit: number;
12
+ ok: boolean;
13
+ near: boolean;
14
+ }
15
+ export interface PreflightInput {
16
+ source: string;
17
+ endpoint: string;
18
+ functionsCount: number;
19
+ quotaLimit?: number;
20
+ verifyJwt: boolean;
21
+ entrypointExists: boolean;
22
+ sourceBytes?: number;
23
+ }
24
+ export interface PreflightResult {
25
+ quota: QuotaCheck;
26
+ rootAbsoluteRefs: string[];
27
+ publicReachable: boolean;
28
+ warnings: string[];
29
+ blockers: string[];
30
+ }
31
+ /** Detect root-absolute references that would escape the /functions/v1/ prefix. */
32
+ export declare function scanRootAbsoluteRefs(source: string): string[];
33
+ /** True when the endpoint host is publicly reachable (not loopback / RFC1918). */
34
+ export declare function isPublicEndpoint(endpoint: string): boolean;
35
+ export declare function checkQuota(used: number, limit?: number): QuotaCheck;
36
+ /** Run all preflight checks and collect warnings/blockers. */
37
+ export declare function runPreflight(input: PreflightInput): PreflightResult;
38
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../src/app/preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAY7D;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAY1D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,UAAU,CAE9D;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CAiDnE"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Preflight guardrails for `pxbaas app deploy`.
3
+ *
4
+ * These checks encode the edge-function sandbox constraints (see doc 02 and the
5
+ * sandbox webapp evaluation): 5-function quota, no root-absolute asset refs
6
+ * (they escape the /functions/v1/ prefix onto Studio), and cross-machine sharing
7
+ * requires a public endpoint (sandbox URLs are internal).
8
+ */
9
+ /** Detect root-absolute references that would escape the /functions/v1/ prefix. */
10
+ export function scanRootAbsoluteRefs(source) {
11
+ const patterns = [
12
+ /(href|src|action)\s*=\s*["']\/(?!\/)[^"']*["']/gi,
13
+ /fetch\(\s*["'`]\/(?!\/)[^"'`]*["'`]/gi,
14
+ /url\(\s*\/(?!\/)[^)]*\)/gi,
15
+ ];
16
+ const hits = [];
17
+ for (const re of patterns) {
18
+ const m = source.match(re);
19
+ if (m)
20
+ hits.push(...m);
21
+ }
22
+ return hits;
23
+ }
24
+ /** True when the endpoint host is publicly reachable (not loopback / RFC1918). */
25
+ export function isPublicEndpoint(endpoint) {
26
+ const host = endpoint
27
+ .replace(/^https?:\/\//, "")
28
+ .split("/")[0]
29
+ .split(":")[0]
30
+ .toLowerCase();
31
+ if (!host)
32
+ return false;
33
+ if (["localhost", "127.0.0.1", "::1", "0.0.0.0"].includes(host))
34
+ return false;
35
+ if (/^10\./.test(host))
36
+ return false;
37
+ if (/^192\.168\./.test(host))
38
+ return false;
39
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(host))
40
+ return false;
41
+ return true;
42
+ }
43
+ export function checkQuota(used, limit = 5) {
44
+ return { used, limit, ok: used < limit, near: used === limit - 1 };
45
+ }
46
+ /** Run all preflight checks and collect warnings/blockers. */
47
+ export function runPreflight(input) {
48
+ const quota = checkQuota(input.functionsCount, input.quotaLimit ?? 5);
49
+ const rootAbsoluteRefs = scanRootAbsoluteRefs(input.source);
50
+ const publicReachable = isPublicEndpoint(input.endpoint);
51
+ const warnings = [];
52
+ const blockers = [];
53
+ if (!input.entrypointExists) {
54
+ blockers.push("Entrypoint file not found. Run `pxbaas app new <name>` first.");
55
+ }
56
+ if (!quota.ok) {
57
+ blockers.push(`Edge Function quota reached (${quota.used}/${quota.limit}). Remove an existing function (\`pxbaas app remove\` / \`pxbaas functions delete\`) or request a higher quota.`);
58
+ }
59
+ else if (quota.near) {
60
+ warnings.push(`Approaching the Edge Function quota (${quota.used}/${quota.limit}).`);
61
+ }
62
+ if (rootAbsoluteRefs.length > 0) {
63
+ // Root-absolute refs are a hard spec violation and are reported as a BLOCKER
64
+ // by spec-lint (pxbaas-app-spec). We still surface the raw list here for data,
65
+ // but do not double-report it as a preflight warning.
66
+ }
67
+ if (!publicReachable) {
68
+ warnings.push(`Endpoint ${input.endpoint} is not publicly reachable (loopback/private). The share URL will NOT work cross-machine.`);
69
+ }
70
+ if (!input.verifyJwt) {
71
+ warnings.push("verify_jwt=false: the share URL is public and the slug is enumerable. Do not co-locate secrets or sensitive logic in this function.");
72
+ }
73
+ const bytes = input.sourceBytes ?? Buffer.byteLength(input.source, "utf8");
74
+ if (bytes > 1_000_000) {
75
+ warnings.push(`Single-file bundle is large (${Math.round(bytes / 1024)}KB). Worker memory is limited (~150MB); consider hosting static assets via Storage/CDN instead.`);
76
+ }
77
+ return { quota, rootAbsoluteRefs, publicReachable, warnings, blockers };
78
+ }
79
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/app/preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /** Static compliance checks for legacy edge-function apps and manifest-v2 webapps. */
2
+ import type { BackendFramework } from "./templates.js";
3
+ export type Severity = "blocker" | "warning";
4
+ export interface Finding {
5
+ rule: string;
6
+ severity: Severity;
7
+ message: string;
8
+ specRef: string;
9
+ }
10
+ export interface SpecLintResult {
11
+ passed: boolean;
12
+ blockers: Finding[];
13
+ warnings: Finding[];
14
+ }
15
+ export interface ArtifactSource {
16
+ path: string;
17
+ source: string;
18
+ }
19
+ export interface SpecLintOptions {
20
+ verifyJwt?: boolean;
21
+ mode?: string;
22
+ declaredFiles?: string[];
23
+ existingFiles?: string[];
24
+ auxiliarySources?: string[];
25
+ frontendFiles?: string[];
26
+ frontendSources?: ArtifactSource[];
27
+ frontendConfigSource?: string;
28
+ frontendProjectSources?: string[];
29
+ requireHashRouter?: boolean;
30
+ backendSource?: string;
31
+ backendFramework?: BackendFramework;
32
+ honoVersion?: string | null;
33
+ /** Capability ssrLibs: curated SSR renderer allow-list (name@version) (W9/D7). */
34
+ ssrLibs?: string[];
35
+ secrets?: string[];
36
+ egressPolicy?: string;
37
+ ssrFallback?: boolean;
38
+ ssrProbePath?: string;
39
+ backendSession?: string;
40
+ sessionMode?: string;
41
+ sessionHeaders?: string[];
42
+ }
43
+ /** Lint source and artifact metadata while preserving legacy spa/api/mpa behavior. */
44
+ export declare function lintAppSource(source: string, options?: SpecLintOptions): SpecLintResult;
45
+ //# sourceMappingURL=spec-lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-lint.d.ts","sourceRoot":"","sources":["../../src/app/spec-lint.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAmaD,sFAAsF;AACtF,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC5B,cAAc,CA6GhB"}
@@ -0,0 +1,407 @@
1
+ /** Static compliance checks for legacy edge-function apps and manifest-v2 webapps. */
2
+ import { scanRootAbsoluteRefs } from "./preflight.js";
3
+ const SPEC = "pxbaas-app-spec";
4
+ const BINARY_ASSET_RE = /\.(png|jpe?g|gif|webp|ico|bmp|tiff?|woff2?|ttf|otf|eot|pdf|zip|gz|tgz|mp4|webm|mp3|wav|avif|wasm)$/i;
5
+ const NODE_PATTERNS = [
6
+ { re: /\brequire\s*\(/, hint: "require()" },
7
+ { re: /(?:from\s+|import\s*)["']node:/, hint: "node: import" },
8
+ {
9
+ re: /\bfrom\s+["'](?:fs|path|http|https|os|crypto|child_process|express|koa|fastify|axios)["']/,
10
+ hint: "Node/builtin import",
11
+ },
12
+ {
13
+ re: /\bprocess\.(?:env|exit|argv|stdin|stdout|stderr)\b/,
14
+ hint: "process.*",
15
+ },
16
+ { re: /\b__dirname\b|\b__filename\b/, hint: "__dirname/__filename" },
17
+ ];
18
+ /**
19
+ * Platform-injected public env keys readable by App candidate workers.
20
+ * Mirrors edge-runtime `mysql/builtin-functions/main/app-env.ts`
21
+ * APP_PUBLIC_ENV_KEYS (MR #30497903). Role contract: SUPABASE_INTERNAL_URL is the
22
+ * only legal data-plane fetch base, SUPABASE_ANON_KEY the data-plane credential,
23
+ * SUPABASE_URL a render-only public origin (never fetch through it).
24
+ */
25
+ const APP_PUBLIC_ENV_KEYS = new Set([
26
+ "SUPABASE_URL",
27
+ "SUPABASE_ANON_KEY",
28
+ "SUPABASE_INTERNAL_URL",
29
+ ]);
30
+ /**
31
+ * Strip line and block comments while preserving string and template literals,
32
+ * so keyword rules (Deno.env, Set-Cookie, Node APIs, ...) do not false-positive
33
+ * on explanatory comments. Regex literals are not lexed: a slash only begins a
34
+ * comment when followed by another slash or an asterisk.
35
+ */
36
+ function stripComments(src) {
37
+ let out = "";
38
+ let i = 0;
39
+ const n = src.length;
40
+ let state = "code";
41
+ while (i < n) {
42
+ const c = src[i];
43
+ const c2 = src[i + 1];
44
+ if (state === "code") {
45
+ if (c === "/" && c2 === "/") {
46
+ state = "line";
47
+ i += 2;
48
+ continue;
49
+ }
50
+ if (c === "/" && c2 === "*") {
51
+ state = "block";
52
+ i += 2;
53
+ continue;
54
+ }
55
+ if (c === "'") {
56
+ state = "sq";
57
+ out += c;
58
+ i++;
59
+ continue;
60
+ }
61
+ if (c === '"') {
62
+ state = "dq";
63
+ out += c;
64
+ i++;
65
+ continue;
66
+ }
67
+ if (c === "`") {
68
+ state = "tpl";
69
+ out += c;
70
+ i++;
71
+ continue;
72
+ }
73
+ out += c;
74
+ i++;
75
+ continue;
76
+ }
77
+ if (state === "line") {
78
+ if (c === "\n") {
79
+ state = "code";
80
+ out += c;
81
+ }
82
+ i++;
83
+ continue;
84
+ }
85
+ if (state === "block") {
86
+ if (c === "*" && c2 === "/") {
87
+ state = "code";
88
+ i += 2;
89
+ continue;
90
+ }
91
+ if (c === "\n")
92
+ out += c;
93
+ i++;
94
+ continue;
95
+ }
96
+ // string / template states: copy verbatim, honour backslash escapes
97
+ if (c === "\\") {
98
+ out += c + (c2 ?? "");
99
+ i += 2;
100
+ continue;
101
+ }
102
+ if ((state === "sq" && c === "'") ||
103
+ (state === "dq" && c === '"') ||
104
+ (state === "tpl" && c === "`")) {
105
+ state = "code";
106
+ }
107
+ out += c;
108
+ i++;
109
+ continue;
110
+ }
111
+ return out;
112
+ }
113
+ function finding(rule, message, ref) {
114
+ return {
115
+ rule,
116
+ severity: "blocker",
117
+ message,
118
+ specRef: `${SPEC}/references/${ref}`,
119
+ };
120
+ }
121
+ function lintBackend(source, options, blockers, warnings) {
122
+ const code = stripComments(source);
123
+ if (!/Deno\.serve\s*\(/.test(code)) {
124
+ blockers.push(finding("deno-serve", "Missing top-level Deno.serve(...). The webapp backend must use the Deno HTTP server contract.", "runtime-contract.md"));
125
+ }
126
+ for (const { re, hint } of NODE_PATTERNS) {
127
+ if (re.test(code)) {
128
+ blockers.push(finding("no-node-api", `Node.js API detected (${hint}). The backend runtime is Deno.`, "runtime-contract.md"));
129
+ break;
130
+ }
131
+ }
132
+ // Custom Secrets are unsupported in the first webapp release.
133
+ if ((options.secrets?.length ?? 0) > 0) {
134
+ blockers.push(finding("custom-secrets-not-supported", "Custom Secrets are not supported by the first webapp release. Remove the backend.secrets entries from app.json.", "guardrails-pitfalls.md"));
135
+ }
136
+ // Deno.env: only the platform public three-key whitelist is readable. Any
137
+ // other key, or dynamic/toObject access that could expose the whole env, is a
138
+ // blocker. Matched on comment-stripped code so documented examples do not trip it.
139
+ const envOffenders = new Set();
140
+ let sawUnverifiableEnv = false;
141
+ for (const match of code.matchAll(/Deno\.env\.(get|toObject|set|delete)\s*\(([^)]*)\)/g)) {
142
+ const method = match[1];
143
+ const argRaw = match[2].trim();
144
+ if (method === "toObject") {
145
+ sawUnverifiableEnv = true;
146
+ continue;
147
+ }
148
+ const literal = argRaw.match(/^["']([^"']+)["']/);
149
+ if (literal) {
150
+ if (!APP_PUBLIC_ENV_KEYS.has(literal[1]))
151
+ envOffenders.add(literal[1]);
152
+ }
153
+ else {
154
+ sawUnverifiableEnv = true;
155
+ }
156
+ }
157
+ if (envOffenders.size > 0 || sawUnverifiableEnv) {
158
+ const detail = envOffenders.size > 0
159
+ ? [...envOffenders].slice(0, 3).join(", ")
160
+ : "dynamic key or Deno.env.toObject()";
161
+ blockers.push(finding("deno-env-not-allowed", `Only the platform public env keys are readable (${[...APP_PUBLIC_ENV_KEYS].join(", ")}). Offending Deno.env access: ${detail}.`, "guardrails-pitfalls.md"));
162
+ }
163
+ if ((options.egressPolicy ?? "deny") !== "deny") {
164
+ blockers.push(finding("egress-deny", 'The first webapp release requires backend.egressPolicy="deny".', "runtime-contract.md"));
165
+ }
166
+ const importSpecifiers = [
167
+ ...code.matchAll(/(?:from\s*|import\s*(?:\(\s*)?)["']([^"']+)["']/g),
168
+ ].map((match) => match[1]);
169
+ const remoteImports = importSpecifiers.filter((value) => /^(?:https?:|jsr:|npm:)/.test(value));
170
+ const ssrLibs = options.ssrLibs ?? [];
171
+ const isAllowedSsrImport = (value) => ssrLibs.some((e) => value === `npm:${e}` || value.startsWith(`npm:${e}/`));
172
+ const honoExpected = options.backendFramework === "hono" && options.honoVersion
173
+ ? `npm:hono@${options.honoVersion}`
174
+ : null;
175
+ // Hono (D7): the hono-version rule governs ONLY the Hono import itself.
176
+ if (options.backendFramework === "hono") {
177
+ if (!honoExpected || !importSpecifiers.includes(honoExpected)) {
178
+ blockers.push(finding("hono-version", honoExpected
179
+ ? `Hono must use the exact platform import ${honoExpected}.`
180
+ : "Hono is not available because the instance did not report an exact offline-ready version.", "runtime-contract.md"));
181
+ }
182
+ }
183
+ // Off-list remote imports: anything except the exact Hono import and the
184
+ // capability-curated SSR renderers (npm:<name>@<version>[/subpath]).
185
+ const offList = remoteImports.filter((value) => {
186
+ if (honoExpected && value === honoExpected)
187
+ return false;
188
+ if (options.backendFramework === "hono" && /^npm:hono@/.test(value))
189
+ return false; // wrong-version Hono is reported by hono-version above
190
+ if (value.startsWith("npm:") && isAllowedSsrImport(value))
191
+ return false;
192
+ return true;
193
+ });
194
+ const npmOffList = offList.filter((value) => value.startsWith("npm:"));
195
+ const otherOffList = offList.filter((value) => !value.startsWith("npm:"));
196
+ if (npmOffList.length > 0) {
197
+ blockers.push(ssrLibs.length > 0
198
+ ? finding("ssr-lib-not-allowed", `npm import(s) not in this instance's capability ssrLibs: ${npmOffList.slice(0, 3).join(", ")}. Allowed SSR renderers: ${ssrLibs.map((e) => `npm:${e}`).join(", ")} (a /subpath such as /server or /web is allowed).`, "runtime-contract.md")
199
+ : finding("no-remote-import", `Remote/npm/jsr import(s) are not allowed: ${npmOffList.slice(0, 3).join(", ")}. ` +
200
+ "This instance reported an EMPTY capabilities.ssrLibs allow-list, so every npm: import is blocked. " +
201
+ "ssrLibs is a declaration baked from SSR_LIBS_LIST (/etc/supabase/ssr-libs); an empty value usually means " +
202
+ "the AIO image was built without it even though the sandbox caches the renderers. Fix the instance " +
203
+ "(bake SSR_LIBS_LIST or set APP_SSR_LIBS, then restart edge-proxy/studio) rather than working around it " +
204
+ "with --skip-spec-check; Hono itself is gated by hono-version/honoOfflineReady, not by ssrLibs.", "runtime-contract.md"));
205
+ }
206
+ if (otherOffList.length > 0) {
207
+ blockers.push(finding("no-remote-import", `Remote http/https/jsr import(s) are not allowed: ${otherOffList.slice(0, 3).join(", ")}.`, "runtime-contract.md"));
208
+ }
209
+ const hasCors = /Access-Control-Allow-Origin/i.test(code);
210
+ const hasOptions = /OPTIONS/.test(code);
211
+ if (!hasCors || !hasOptions) {
212
+ warnings.push({
213
+ rule: "cors-options",
214
+ severity: "warning",
215
+ message: `Missing ${!hasCors ? "CORS headers" : ""}${!hasCors && !hasOptions ? " and " : ""}${!hasOptions ? "OPTIONS handling" : ""}. Browser calls to the backend may fail.`,
216
+ specRef: `${SPEC}/references/guardrails-pitfalls.md`,
217
+ });
218
+ }
219
+ }
220
+ function lintWebappFrontend(options, blockers) {
221
+ const files = options.frontendFiles ?? [];
222
+ const normalized = files.map((file) => file.replace(/\\/g, "/"));
223
+ const forbiddenEnv = normalized.filter((file) => /(^|\/)\.env(?:\.|$)/.test(file));
224
+ const sourceMaps = normalized.filter((file) => /\.map$/i.test(file));
225
+ const nodeModules = normalized.filter((file) => /(^|\/)node_modules\//.test(file));
226
+ const sourceDirs = normalized.filter((file) => /(^|\/)src\//.test(file));
227
+ const serviceWorkers = normalized.filter((file) => /(^|\/)(?:service-worker|sw)\.(?:js|mjs|ts)$/i.test(file));
228
+ if (forbiddenEnv.length > 0)
229
+ blockers.push(finding("no-env-files", `Frontend artifacts must not include .env files: ${forbiddenEnv.slice(0, 5).join(", ")}.`, "guardrails-pitfalls.md"));
230
+ if (sourceMaps.length > 0)
231
+ blockers.push(finding("no-source-maps", `Frontend artifacts must not include source maps: ${sourceMaps.slice(0, 5).join(", ")}.`, "guardrails-pitfalls.md"));
232
+ if (nodeModules.length > 0)
233
+ blockers.push(finding("no-node-modules", "Upload the built frontend output, not node_modules.", "guardrails-pitfalls.md"));
234
+ if (sourceDirs.length > 0)
235
+ blockers.push(finding("no-frontend-source", "Upload the prebuilt frontend directory, not a source directory.", "templates-examples.md"));
236
+ if (serviceWorkers.length > 0)
237
+ blockers.push(finding("no-service-worker", `Service Worker files are not supported: ${serviceWorkers.slice(0, 5).join(", ")}.`, "guardrails-pitfalls.md"));
238
+ const frontendSource = (options.frontendSources ?? [])
239
+ .map((file) => file.source)
240
+ .join("\n");
241
+ const projectSource = (options.frontendProjectSources ?? []).join("\n");
242
+ if (/navigator\.serviceWorker|serviceWorker\.register\s*\(/.test(`${frontendSource}\n${projectSource}`)) {
243
+ blockers.push(finding("no-service-worker", "Service Worker registration is not supported by the first webapp release.", "guardrails-pitfalls.md"));
244
+ }
245
+ if (options.frontendConfigSource !== undefined &&
246
+ !/\bbase\s*:\s*["']\.\/["']/.test(options.frontendConfigSource)) {
247
+ blockers.push(finding("vite-relative-base", 'Vite must set base: "./" so assets remain under the App mount.', "templates-examples.md"));
248
+ }
249
+ if (options.frontendConfigSource !== undefined &&
250
+ /\bsourcemap\s*:\s*(?:true|["'](?:inline|hidden)["'])/.test(options.frontendConfigSource)) {
251
+ blockers.push(finding("no-source-maps", "Vite source maps must be disabled for uploaded frontend artifacts.", "guardrails-pitfalls.md"));
252
+ }
253
+ if (options.requireHashRouter && !/\bHashRouter\b/.test(projectSource)) {
254
+ blockers.push(finding("react-hash-router", "React webapps must use HashRouter; history fallback is not supported.", "templates-examples.md"));
255
+ }
256
+ }
257
+ /** SSR (W5): authoring guards for fallback=worker apps (DX-2 marker, D16 self-contained). */
258
+ function lintSsr(backendSource, options, blockers, warnings) {
259
+ const code = stripComments(backendSource);
260
+ const probe = options.ssrProbePath;
261
+ if (typeof probe !== "string" || !probe.startsWith("/") || probe.includes("..")) {
262
+ blockers.push(finding("ssr-probe-declared", 'manifest.ssrProbePath is required (safe logical path, e.g. "/page") when frontend.fallback="worker".', "runtime-contract.md"));
263
+ }
264
+ if (/from\s+["']\.\//.test(code) || /import\s*\(\s*["']\.\//.test(code)) {
265
+ blockers.push(finding("ssr-self-contained", "SSR worker must be single-file self-contained: relative module imports fail at boot on the current runtime (D16). Inline helpers or import platform-pinned packages only.", "runtime-contract.md"));
266
+ }
267
+ // The marker may be written with escaped quotes inside a double-quoted JS
268
+ // string (e.g. "<div ... data-ssr=\"v1\">"), so match an optional backslash
269
+ // before each quote rather than a naive substring.
270
+ if (!/data-ssr=\\?["']v1\\?["']/.test(code)) {
271
+ blockers.push(finding("ssr-marker-present", 'SSR page output must include the hydration root marker <div id="__ssr" data-ssr="v1"> so the publish probe can verify rendering (DX-2).', "runtime-contract.md"));
272
+ }
273
+ if (/\bwindow\b|\bdocument\b/.test(code)) {
274
+ warnings.push({
275
+ ...finding("ssr-no-browser-globals", "SSR worker references window/document: server render must not touch browser globals at import or render time.", "runtime-contract.md"),
276
+ severity: "warning",
277
+ });
278
+ }
279
+ }
280
+ /** Lint source and artifact metadata while preserving legacy spa/api/mpa behavior. */
281
+ export function lintAppSource(source, options = {}) {
282
+ const blockers = [];
283
+ const warnings = [];
284
+ const mode = options.mode ?? "spa";
285
+ const verifyJwt = options.verifyJwt ?? false;
286
+ const isWebapp = mode === "webapp";
287
+ const backendSource = options.backendSource ?? source;
288
+ // Backend lint runs for legacy apps and for webapps with a declared framework.
289
+ // A webapp backend missing `framework` is rejected earlier by manifest
290
+ // validation (requireWebappManifestValue, R2-09), so it never reaches a state
291
+ // where these checks would be silently skipped.
292
+ if (!isWebapp || options.backendFramework)
293
+ lintBackend(backendSource, options, blockers, warnings);
294
+ if (isWebapp)
295
+ lintWebappFrontend(options, blockers);
296
+ const scannedSources = isWebapp
297
+ ? [
298
+ ...(options.frontendSources ?? []).map((file) => file.source),
299
+ ...(options.frontendProjectSources ?? []),
300
+ // R2-08: also scan SSR backend output for root-absolute refs (href="/x",
301
+ // fetch("/x"), url(/x)) that would escape the /apps/{mount} prefix. Comments
302
+ // are stripped first so documented examples do not false-positive; server-side
303
+ // fetches use the injected internal base (base + "/rest/..."), not root-absolute
304
+ // literals, so legitimate SSR data access is unaffected.
305
+ ...(options.backendSource ? [stripComments(options.backendSource)] : []),
306
+ ]
307
+ : [source, ...(options.auxiliarySources ?? [])];
308
+ const rootAbs = scanRootAbsoluteRefs(scannedSources.join("\n"));
309
+ if (rootAbs.length > 0) {
310
+ blockers.push(finding("no-root-absolute", `Root-absolute reference(s) found: ${rootAbs.slice(0, 3).join(", ")}. Use mount-relative URLs.`, "guardrails-pitfalls.md"));
311
+ }
312
+ if (mode === "mpa") {
313
+ const existing = new Set(options.existingFiles ?? []);
314
+ const missing = (options.declaredFiles ?? []).filter((file) => !existing.has(file));
315
+ if (missing.length > 0)
316
+ blockers.push(finding("mpa-assets-exist", `app.json declares missing page(s)/asset(s): ${missing.join(", ")}.`, "templates-examples.md"));
317
+ }
318
+ if (isWebapp && options.ssrFallback)
319
+ lintSsr(backendSource, options, blockers, warnings);
320
+ if (isWebapp)
321
+ lintSession(backendSource, options, blockers, warnings);
322
+ if (mode === "mpa" || isWebapp) {
323
+ const files = isWebapp
324
+ ? (options.frontendFiles ?? [])
325
+ : (options.existingFiles ?? []);
326
+ const binary = files.filter((file) => BINARY_ASSET_RE.test(file));
327
+ if (binary.length > 0)
328
+ blockers.push(finding("no-binary-assets", `Binary assets are not supported by the text-only release: ${binary.slice(0, 5).join(", ")}. Put binary assets in Storage instead.`, "guardrails-pitfalls.md"));
329
+ }
330
+ if (!isWebapp) {
331
+ const servesHtml = /text\/html/i.test(source);
332
+ const hasEscape = /\besc\s*\(|escapeHtml|encodeHTML|replace\(\s*\/&\/g/.test(source);
333
+ if (servesHtml && !hasEscape)
334
+ warnings.push({
335
+ rule: "escape-reflected",
336
+ severity: "warning",
337
+ message: "Serves text/html but no HTML-escaping helper was found.",
338
+ specRef: `${SPEC}/references/guardrails-pitfalls.md`,
339
+ });
340
+ if (/<script[^>]+src=["']https?:\/\//i.test(source) ||
341
+ /<link[^>]+href=["']https?:\/\//i.test(source))
342
+ warnings.push({
343
+ rule: "no-external-cdn",
344
+ severity: "warning",
345
+ message: "External CDN core assets were detected; bundle or inline them.",
346
+ specRef: `${SPEC}/references/guardrails-pitfalls.md`,
347
+ });
348
+ if (!verifyJwt &&
349
+ /service_role|serviceRoleKey|SERVICE_ROLE|dbPassword|DASHBOARD_PASSWORD|secret\s*[:=]/i.test(source))
350
+ warnings.push({
351
+ rule: "no-secrets-public",
352
+ severity: "warning",
353
+ message: "A public function appears to reference a secret.",
354
+ specRef: `${SPEC}/references/guardrails-pitfalls.md`,
355
+ });
356
+ }
357
+ return { passed: blockers.length === 0, blockers, warnings };
358
+ }
359
+ /** 方案 C: session-contract authoring guards for webapp backends. */
360
+ function lintSession(backendSource, options, blockers, warnings) {
361
+ const session = options.backendSession ?? "none";
362
+ const src = stripComments(backendSource ?? "");
363
+ if (session === "proxy-injected") {
364
+ // Worker must NOT read the client cookie: /apps strips it, so any cookie the
365
+ // worker sees is a proxy-jar artifact. Identity comes from injected headers.
366
+ if (/headers?\s*(?:\.get\s*\(\s*["']cookie["']|\[\s*["']cookie["']\s*\])/i.test(src))
367
+ blockers.push(finding("session-no-cookie-read", 'backend.session="proxy-injected" must not read the Cookie header; use the injected X-App-User-* headers.', "ssr-session.md"));
368
+ if (/set-cookie/i.test(src))
369
+ blockers.push(finding("session-no-set-cookie", 'backend.session="proxy-injected" must not issue Set-Cookie; the proxy owns the session cookie.', "ssr-session.md"));
370
+ if (/[?&](sid|session_token|access_token)=/i.test(src))
371
+ blockers.push(finding("session-no-url-token", "Do not carry the user token in URLs (?sid=/&token=); the proxy injects X-App-User-Token.", "ssr-session.md"));
372
+ const headers = (options.sessionHeaders ?? []).map((h) => h.toLowerCase());
373
+ const used = headers.filter((h) => src.toLowerCase().includes(h));
374
+ if (used.length === 0)
375
+ warnings.push({
376
+ rule: "session-use-injected-header",
377
+ severity: "warning",
378
+ message: 'backend.session="proxy-injected" but no capabilities.sessionHeaders reference found; read X-App-User-Token/X-App-User-Id.',
379
+ specRef: `${SPEC}/references/ssr-session.md`,
380
+ });
381
+ // Any X-App-User-* header not in the capability whitelist is a forgery risk / typo.
382
+ const referenced = [
383
+ ...new Set((src.toLowerCase().match(/x-app-user-[a-z-]+/g) ?? [])),
384
+ ];
385
+ const unknown = referenced.filter((h) => !headers.includes(h));
386
+ if (unknown.length > 0)
387
+ blockers.push(finding("session-header-name-whitelist", `Unknown injected session header(s): ${unknown.join(", ")}. Use only capabilities.sessionHeaders.`, "ssr-session.md"));
388
+ if (/JWT_SECRET/i.test(src))
389
+ warnings.push({
390
+ rule: "session-env-secret",
391
+ severity: "warning",
392
+ message: "proxy-injected sessions are verified by the proxy; the worker needs no JWT signing secret.",
393
+ specRef: `${SPEC}/references/ssr-session.md`,
394
+ });
395
+ }
396
+ if (session === "browser-side") {
397
+ if (/headers?\s*(?:\.get\s*\(\s*["'](cookie|authorization)["']|\[\s*["'](cookie|authorization)["']\s*\])/i
398
+ .test(src))
399
+ warnings.push({
400
+ rule: "session-browser-side-no-worker-auth",
401
+ severity: "warning",
402
+ message: 'backend.session="browser-side": authentication belongs in the browser (localStorage + Authorization to /auth,/rest), not the worker.',
403
+ specRef: `${SPEC}/references/ssr-session.md`,
404
+ });
405
+ }
406
+ }
407
+ //# sourceMappingURL=spec-lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-lint.js","sourceRoot":"","sources":["../../src/app/spec-lint.ts"],"names":[],"mappings":"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"}