@zackbart/connecta 0.28.1 → 0.29.0

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 (319) hide show
  1. package/CHANGELOG.md +788 -5
  2. package/README.md +62 -42
  3. package/bin/connecta.mjs +110 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  12. package/dist/auth/clerk-sdk/client.js +5 -0
  13. package/dist/auth/clerk-sdk/generated.js +1845 -0
  14. package/dist/auth/clerk-transport.js +19 -0
  15. package/dist/auth/clerk.d.ts +17 -7
  16. package/dist/auth/clerk.js +189 -107
  17. package/dist/auth/cloudflare-access.js +25 -26
  18. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  19. package/dist/auth/downstream-client-metadata.js +133 -0
  20. package/dist/auth/downstream-oauth.js +1584 -1580
  21. package/dist/auth/downstream-revocation.js +106 -0
  22. package/dist/auth/oauth-token-response.js +231 -0
  23. package/dist/auth/oauth-v2-migration.js +116 -0
  24. package/dist/auth/static-oauth.js +93 -71
  25. package/dist/auth-elicitation.js +283 -0
  26. package/dist/branding.d.ts +8 -16
  27. package/dist/branding.js +26 -59
  28. package/dist/byte-read-response.js +39 -0
  29. package/dist/call-admission.js +12 -16
  30. package/dist/catalog-cache.js +739 -0
  31. package/dist/catalog-drift.d.ts +50 -15
  32. package/dist/catalog-drift.js +365 -128
  33. package/dist/catalog-fingerprint.js +2 -4
  34. package/dist/catalog-freshness.js +13 -0
  35. package/dist/catalog-limits.js +2 -2
  36. package/dist/catalog-service.js +368 -224
  37. package/dist/catalog.js +43 -84
  38. package/dist/concurrency.js +3 -4
  39. package/dist/config-defaults.d.ts +39 -0
  40. package/dist/config-defaults.js +46 -0
  41. package/dist/config-schema.d.ts +181 -0
  42. package/dist/config-schema.js +435 -0
  43. package/dist/config-value-sources.js +102 -0
  44. package/dist/config.d.ts +631 -0
  45. package/dist/config.js +503 -0
  46. package/dist/connector-access.d.ts +1 -0
  47. package/dist/connector-access.js +13 -15
  48. package/dist/connector-caller.d.ts +8 -0
  49. package/dist/connector-caller.js +15 -6
  50. package/dist/connector-scope.js +1 -1
  51. package/dist/connectors/api-connector.d.ts +59 -7
  52. package/dist/connectors/api-connector.js +106 -19
  53. package/dist/connectors/api.js +4 -1
  54. package/dist/connectors/guarded-fetch.d.ts +144 -0
  55. package/dist/connectors/guarded-fetch.js +84 -35
  56. package/dist/connectors/negotiation-cache.js +46 -0
  57. package/dist/connectors/option-shapes.js +27 -0
  58. package/dist/connectors/remote-mcp.d.ts +30 -4
  59. package/dist/connectors/remote-mcp.js +1774 -320
  60. package/dist/connectors/resource-uri.js +335 -0
  61. package/dist/credential-contract.d.ts +10 -0
  62. package/dist/credential-rules.js +1 -3
  63. package/dist/credential-url.js +108 -0
  64. package/dist/credentials.d.ts +6 -1
  65. package/dist/credentials.js +27 -18
  66. package/dist/d1.d.ts +130 -0
  67. package/dist/d1.js +290 -0
  68. package/dist/describe-config.d.ts +165 -0
  69. package/dist/describe-config.js +315 -0
  70. package/dist/described.js +106 -0
  71. package/dist/downstream-input-context.js +119 -0
  72. package/dist/downstream-input.js +323 -0
  73. package/dist/errors.d.ts +97 -20
  74. package/dist/errors.js +158 -80
  75. package/dist/execute.js +453 -305
  76. package/dist/executor-admission.d.ts +1 -0
  77. package/dist/executor-admission.js +11 -15
  78. package/dist/executor-contract.d.ts +20 -0
  79. package/dist/executor-contract.js +48 -0
  80. package/dist/executor-result.js +24 -9
  81. package/dist/executors/quickjs-child.js +3 -4
  82. package/dist/executors/quickjs-runtime.js +147 -59
  83. package/dist/executors/quickjs.js +29 -35
  84. package/dist/favicon.js +1 -2
  85. package/dist/fix-prompt.js +1 -3
  86. package/dist/guest-runtime.js +188 -0
  87. package/dist/guest-types.d.ts +176 -0
  88. package/dist/guest-types.js +1 -0
  89. package/dist/html-security.js +24 -0
  90. package/dist/identity.js +1 -3
  91. package/dist/inbound-credential.js +52 -0
  92. package/dist/index.d.ts +24 -256
  93. package/dist/index.js +65 -478
  94. package/dist/invocation-auth.js +69 -0
  95. package/dist/invocation.js +230 -73
  96. package/dist/json-schema.d.ts +1 -1
  97. package/dist/mcp-client-context.js +35 -0
  98. package/dist/mcp-result.js +11 -7
  99. package/dist/meta-output.js +76 -0
  100. package/dist/meta-tool-names.d.ts +2 -0
  101. package/dist/meta-tool-names.js +3 -0
  102. package/dist/meta-tools.js +285 -209
  103. package/dist/module-contracts.d.ts +8 -23
  104. package/dist/node.d.ts +0 -2
  105. package/dist/node.js +2 -2
  106. package/dist/oauth-callback-outcome.js +1 -3
  107. package/dist/oauth-handoff.js +117 -0
  108. package/dist/oauth-sealing.js +20 -0
  109. package/dist/operator-record.d.ts +137 -0
  110. package/dist/operator-record.js +420 -0
  111. package/dist/operator-ui/assets.js +31 -0
  112. package/dist/operator-ui/contract.d.ts +72 -0
  113. package/dist/operator-ui/contract.js +1 -0
  114. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  115. package/dist/operator-ui/generated.js +5 -4
  116. package/dist/operator-ui/model.d.ts +12 -87
  117. package/dist/operator-ui/model.js +2 -9
  118. package/dist/operator-ui/setup-commands.js +1 -3
  119. package/dist/operator-ui/view.d.ts +323 -0
  120. package/dist/operator-ui/view.js +62 -189
  121. package/dist/page-styles.js +2 -3
  122. package/dist/program-source.js +14 -2
  123. package/dist/{exempt-writes.js → program-writes.js} +55 -18
  124. package/dist/provider.d.ts +142 -0
  125. package/dist/provider.js +187 -0
  126. package/dist/providers/_shared/google/result-size.js +57 -0
  127. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  128. package/dist/providers/_shared/google/service-account.js +500 -0
  129. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  130. package/dist/providers/_shared/google/workspace.js +518 -0
  131. package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
  132. package/dist/providers/basecamp/index.js +997 -0
  133. package/dist/providers/basecamp/skill.generated.js +9 -0
  134. package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
  135. package/dist/providers/{breeze.js → breeze/index.js} +184 -140
  136. package/dist/providers/breeze/skill.generated.js +9 -0
  137. package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
  138. package/dist/providers/{ccb.js → ccb/index.js} +271 -116
  139. package/dist/providers/ccb/skill.generated.js +9 -0
  140. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  141. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  142. package/dist/providers/cloudflare/skill.generated.js +10 -0
  143. package/dist/providers/docs/index.d.ts +54 -0
  144. package/dist/providers/docs/index.js +1237 -0
  145. package/dist/providers/docs/skill.generated.js +9 -0
  146. package/dist/providers/drive/index.d.ts +53 -0
  147. package/dist/providers/drive/index.js +1523 -0
  148. package/dist/providers/drive/skill.generated.js +9 -0
  149. package/dist/providers/forms/index.d.ts +54 -0
  150. package/dist/providers/forms/index.js +1217 -0
  151. package/dist/providers/forms/skill.generated.js +11 -0
  152. package/dist/providers/github/auth.d.ts +32 -0
  153. package/dist/providers/github/auth.js +361 -0
  154. package/dist/providers/github/hosted.js +218 -0
  155. package/dist/providers/github/index.d.ts +13 -0
  156. package/dist/providers/github/index.js +140 -0
  157. package/dist/providers/github/key.js +100 -0
  158. package/dist/providers/github/rest.js +321 -0
  159. package/dist/providers/github/scope.d.ts +29 -0
  160. package/dist/providers/github/scope.js +124 -0
  161. package/dist/providers/github/skill.generated.js +8 -0
  162. package/dist/providers/gmail/index.d.ts +51 -0
  163. package/dist/providers/gmail/index.js +1436 -0
  164. package/dist/providers/gmail/skill.generated.js +9 -0
  165. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  166. package/dist/providers/linear/index.js +352 -0
  167. package/dist/providers/linear/skill.generated.js +8 -0
  168. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  169. package/dist/providers/mixpanel/index.js +416 -0
  170. package/dist/providers/mixpanel/skill.generated.js +9 -0
  171. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  172. package/dist/providers/{notion.js → notion/index.js} +226 -239
  173. package/dist/providers/notion/skill.generated.js +10 -0
  174. package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
  175. package/dist/providers/{overflow.js → overflow/index.js} +74 -111
  176. package/dist/providers/overflow/skill.generated.js +8 -0
  177. package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
  178. package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
  179. package/dist/providers/planning-center/skill.generated.js +10 -0
  180. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  181. package/dist/providers/revenuecat/index.js +557 -0
  182. package/dist/providers/revenuecat/skill.generated.js +11 -0
  183. package/dist/providers/sheets/index.d.ts +54 -0
  184. package/dist/providers/sheets/index.js +1237 -0
  185. package/dist/providers/sheets/skill.generated.js +10 -0
  186. package/dist/providers/slides/index.d.ts +53 -0
  187. package/dist/providers/slides/index.js +2645 -0
  188. package/dist/providers/slides/skill.generated.js +9 -0
  189. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  190. package/dist/providers/stripe/index.js +266 -0
  191. package/dist/providers/stripe/skill.generated.js +11 -0
  192. package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
  193. package/dist/providers/{tithely.js → tithely/index.js} +60 -91
  194. package/dist/providers/tithely/skill.generated.js +8 -0
  195. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  196. package/dist/providers/vercel/index.js +1038 -0
  197. package/dist/providers/vercel/mcp-ownership.js +212 -0
  198. package/dist/providers/vercel/skill.generated.js +11 -0
  199. package/dist/registry.d.ts +108 -171
  200. package/dist/registry.js +513 -925
  201. package/dist/request-state.js +21 -0
  202. package/dist/resource-read.js +100 -0
  203. package/dist/result-shapes.js +17 -49
  204. package/dist/retired-toolkits.js +1 -1
  205. package/dist/routes/access-tokens.js +3 -6
  206. package/dist/routes/activity-context.js +21 -0
  207. package/dist/routes/activity-disclosure.js +40 -0
  208. package/dist/routes/activity.js +59 -21
  209. package/dist/routes/actor-labels.js +3 -50
  210. package/dist/routes/connect.js +221 -0
  211. package/dist/routes/credentials.js +15 -27
  212. package/dist/routes/mcp.js +356 -130
  213. package/dist/routes/oauth-client-metadata.js +15 -0
  214. package/dist/routes/oauth-management.js +45 -107
  215. package/dist/routes/oauth.js +110 -57
  216. package/dist/routes/operator.js +3 -3
  217. package/dist/routes/shared.d.ts +25 -64
  218. package/dist/routes/shared.js +160 -80
  219. package/dist/routes/skills.js +30 -0
  220. package/dist/routes/ui-config.js +225 -0
  221. package/dist/routes/ui-data.js +40 -35
  222. package/dist/routes/ui.js +66 -56
  223. package/dist/runtime/admission.js +4 -2
  224. package/dist/runtime/call-admission.js +3 -1
  225. package/dist/runtime/connector-scope.js +1 -4
  226. package/dist/runtime/run.js +10 -39
  227. package/dist/runtime/services.js +12 -117
  228. package/dist/runtime/shared-read.js +1 -3
  229. package/dist/runtime/storage.js +8 -1
  230. package/dist/sent-secrets.d.ts +52 -0
  231. package/dist/sent-secrets.js +474 -0
  232. package/dist/server.js +28 -71
  233. package/dist/skills.js +406 -174
  234. package/dist/sqlite.d.ts +48 -0
  235. package/dist/sqlite.js +166 -0
  236. package/dist/storage/keys.js +428 -0
  237. package/dist/storage/memory.js +7 -0
  238. package/dist/storage/sql.d.ts +66 -0
  239. package/dist/storage/sql.js +534 -0
  240. package/dist/timeout.js +4 -2
  241. package/dist/tool-name.js +17 -0
  242. package/dist/tool-safety.d.ts +9 -35
  243. package/dist/tool-safety.js +20 -40
  244. package/dist/types.d.ts +320 -54
  245. package/dist/types.js +0 -1
  246. package/dist/ui.d.ts +7 -19
  247. package/dist/ui.js +76 -90
  248. package/dist/url-safety.js +3 -6
  249. package/dist/usage-guide.js +137 -0
  250. package/dist/validate.d.ts +7 -0
  251. package/dist/validate.js +309 -47
  252. package/dist/version.d.ts +1 -7
  253. package/dist/version.js +3 -7
  254. package/dist/worker.d.ts +11 -0
  255. package/dist/worker.js +434 -0
  256. package/documentation/architecture.md +664 -231
  257. package/documentation/auth.md +936 -546
  258. package/documentation/code-mode.md +501 -312
  259. package/documentation/meta-tools.md +449 -200
  260. package/documentation/operator-tests.md +93 -0
  261. package/documentation/provider-migration-0.29.md +60 -0
  262. package/examples/worker/AGENTS.md +34 -12
  263. package/examples/worker/README.md +286 -255
  264. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  265. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  266. package/examples/worker/src/connecta.config.ts +151 -0
  267. package/examples/worker/src/index.ts +14 -197
  268. package/examples/worker/wrangler.jsonc +15 -35
  269. package/package.json +120 -54
  270. package/templates/node/.dockerignore +1 -2
  271. package/templates/node/.env.example +20 -21
  272. package/templates/node/AGENTS.md +21 -17
  273. package/templates/node/Dockerfile +3 -5
  274. package/templates/node/README.md +133 -58
  275. package/templates/node/docker-compose.yml +11 -12
  276. package/templates/node/package.json +4 -2
  277. package/templates/node/src/connecta.config.ts +119 -0
  278. package/templates/node/src/index.ts +9 -154
  279. package/templates/node/src/provision-token.ts +17 -0
  280. package/AGENTS.md +0 -170
  281. package/dist/artifacts/connector.d.ts +0 -58
  282. package/dist/artifacts/connector.js +0 -730
  283. package/dist/artifacts/document.js +0 -86
  284. package/dist/artifacts/guide.js +0 -140
  285. package/dist/artifacts/html-scan.js +0 -329
  286. package/dist/artifacts/json.js +0 -78
  287. package/dist/artifacts/kv-store.d.ts +0 -20
  288. package/dist/artifacts/kv-store.js +0 -140
  289. package/dist/artifacts/markdown.js +0 -478
  290. package/dist/artifacts/module.d.ts +0 -37
  291. package/dist/artifacts/module.js +0 -66
  292. package/dist/artifacts/operations.d.ts +0 -197
  293. package/dist/artifacts/operations.js +0 -1002
  294. package/dist/artifacts/refresh.d.ts +0 -55
  295. package/dist/artifacts/refresh.js +0 -236
  296. package/dist/artifacts/routes.js +0 -206
  297. package/dist/artifacts/types.d.ts +0 -214
  298. package/dist/artifacts/types.js +0 -22
  299. package/dist/artifacts/validate.d.ts +0 -62
  300. package/dist/artifacts/validate.js +0 -651
  301. package/dist/artifacts.d.ts +0 -6
  302. package/dist/artifacts.js +0 -9
  303. package/dist/auth/bearer.d.ts +0 -11
  304. package/dist/auth/bearer.js +0 -50
  305. package/dist/providers/basecamp.js +0 -445
  306. package/dist/providers/linear.js +0 -217
  307. package/dist/providers/mixpanel.js +0 -247
  308. package/dist/providers/revenuecat.js +0 -317
  309. package/dist/providers/stripe.js +0 -253
  310. package/dist/providers/vercel.js +0 -1253
  311. package/dist/storage/file.d.ts +0 -15
  312. package/dist/storage/file.js +0 -455
  313. package/ethos.md +0 -93
  314. package/examples/worker/src/cloudflare-kv.ts +0 -43
  315. package/examples/worker/src/d1-activity-row.ts +0 -155
  316. package/examples/worker/src/d1-activity.ts +0 -147
  317. package/examples/worker/src/d1-storage.ts +0 -138
  318. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  319. package/templates/node/src/file-activity.ts +0 -182
@@ -1,651 +0,0 @@
1
- // Static validation for artifact pages and documents.
2
- //
3
- // The viewer's CSP and sandbox are what keep a page in its frame; this is the
4
- // lint that tells an agent, before it saves, what that frame will refuse — a
5
- // relative URL, a script from an origin the CSP does not name, an element that
6
- // cannot work there — in a message it can act on from the message alone. Every
7
- // finding names a line where there is one, quotes the source only through the
8
- // shared echo bound, and says what to do instead.
9
- import { boundedEchoText } from "../errors.js";
10
- import { lineLocator, scanHtml } from "./html-scan.js";
11
- import { jsonProblem, scriptSafeJson, utf8Bytes } from "./json.js";
12
- import { FRAME_OVERHEAD_BYTES } from "./document.js";
13
- import { markdownPage, MarkdownNestingError } from "./markdown.js";
14
- import { DEFAULT_ARTIFACT_ALLOWLIST, DEFAULT_ARTIFACT_LIMITS, } from "./types.js";
15
- /** An artifact id: the URL slug. No leading `_`, so `_api` and `_frame` stay free. */
16
- export const ARTIFACT_ID = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
17
- /** A document name: what a page reads as `artifact.data.<name>`. */
18
- const DOCUMENT_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
19
- /** Plain-object document maps must never resolve a name through their prototype. */
20
- export function validDocumentName(name) {
21
- return typeof name === "string" && DOCUMENT_NAME.test(name) &&
22
- !Object.hasOwn(Object.prototype, name) && name !== "prototype";
23
- }
24
- const MAX_REPORTED = 20;
25
- const QUOTE_BYTES = 120;
26
- const quote = (text) => boundedEchoText(text, QUOTE_BYTES);
27
- const count = (n) => n.toLocaleString("en-US");
28
- const kib = (bytes) => bytes % (1024 * 1024) === 0
29
- ? `${bytes / (1024 * 1024)} MiB`
30
- : bytes % 1024 === 0
31
- ? `${bytes / 1024} KiB`
32
- : `${count(bytes)} bytes`;
33
- /** Fill in defaults; a deployment may only tighten a limit. Throws on anything else. */
34
- export function resolveLimits(partial = {}) {
35
- if (partial === null || typeof partial !== "object") {
36
- throw new TypeError("artifacts: limits must be an object");
37
- }
38
- const limits = { ...DEFAULT_ARTIFACT_LIMITS };
39
- for (const [key, value] of Object.entries(partial)) {
40
- if (!(key in DEFAULT_ARTIFACT_LIMITS)) {
41
- throw new TypeError(`artifacts: unknown limit "${key}"`);
42
- }
43
- const ceiling = DEFAULT_ARTIFACT_LIMITS[key];
44
- if (value === undefined)
45
- continue;
46
- if (!Number.isInteger(value) || value < 1 || value > ceiling) {
47
- throw new TypeError(`artifacts: limits.${key} must be a whole number from 1 to ${ceiling}; ` +
48
- "limits can be tightened, not raised");
49
- }
50
- limits[key] = value;
51
- }
52
- return limits;
53
- }
54
- /** Normalize an allowlist: every entry an exact `https:` origin. Throws on anything else. */
55
- export function resolveAllowlist(partial = {}) {
56
- if (partial === null || typeof partial !== "object") {
57
- throw new TypeError("artifacts: allowlist must be an object");
58
- }
59
- const resolved = {
60
- scripts: DEFAULT_ARTIFACT_ALLOWLIST.scripts,
61
- styles: DEFAULT_ARTIFACT_ALLOWLIST.styles,
62
- fonts: DEFAULT_ARTIFACT_ALLOWLIST.fonts,
63
- };
64
- for (const [key, list] of Object.entries(partial)) {
65
- if (!(key in resolved)) {
66
- throw new TypeError(`artifacts: unknown allowlist field "${key}"`);
67
- }
68
- if (list === undefined)
69
- continue;
70
- if (!Array.isArray(list)) {
71
- throw new TypeError(`artifacts: allowlist.${key} must be an array of origins`);
72
- }
73
- const origins = list.map((entry) => {
74
- let origin;
75
- try {
76
- origin = typeof entry === "string" ? new URL(entry).origin : undefined;
77
- }
78
- catch {
79
- origin = undefined;
80
- }
81
- if (origin === undefined || origin !== entry || !origin.startsWith("https://")) {
82
- throw new TypeError(`artifacts: allowlist.${key} entries must be exact https: origins ` +
83
- "like https://cdn.jsdelivr.net, with no path or trailing slash");
84
- }
85
- return origin;
86
- });
87
- resolved[key] = Object.freeze([...new Set(origins)]);
88
- }
89
- return resolved;
90
- }
91
- /** The URL with the characters a browser ignores removed, for scheme checks. */
92
- function normalizedUrl(value) {
93
- // A URL parser strips leading and trailing C0 controls and spaces, and
94
- // tabs and newlines anywhere, so `java\tscript:` is still a scheme.
95
- let start = 0;
96
- let end = value.length;
97
- while (start < end && value.charCodeAt(start) <= 0x20)
98
- start++;
99
- while (end > start && value.charCodeAt(end - 1) <= 0x20)
100
- end--;
101
- return value.slice(start, end).replace(/[\t\n\r]/g, "");
102
- }
103
- function schemeOf(value) {
104
- return /^([A-Za-z][A-Za-z0-9+.-]*):/.exec(normalizedUrl(value))?.[1]?.toLowerCase();
105
- }
106
- function httpsOrigin(value) {
107
- const normalized = normalizedUrl(value);
108
- if (schemeOf(normalized) !== "https")
109
- return undefined;
110
- try {
111
- const url = new URL(normalized);
112
- return { origin: url.origin, credentials: Boolean(url.username || url.password), url };
113
- }
114
- catch {
115
- return undefined;
116
- }
117
- }
118
- /**
119
- * The URLs in a `srcset`, split the way the standard splits them: a URL is a
120
- * run of non-space characters, so the commas inside a `data:` URL stay put.
121
- */
122
- function srcsetUrls(value) {
123
- const urls = [];
124
- let i = 0;
125
- while (i < value.length) {
126
- while (i < value.length && /[\s,]/.test(value[i] ?? ""))
127
- i++;
128
- const start = i;
129
- while (i < value.length && !/\s/.test(value[i] ?? ""))
130
- i++;
131
- let url = value.slice(start, i);
132
- if (url.endsWith(",")) {
133
- url = url.replace(/,+$/, "");
134
- }
135
- else {
136
- // Skip the descriptors, up to the comma that ends this candidate.
137
- let depth = 0;
138
- while (i < value.length && (value[i] !== "," || depth > 0)) {
139
- if (value[i] === "(")
140
- depth++;
141
- else if (value[i] === ")")
142
- depth = Math.max(0, depth - 1);
143
- i++;
144
- }
145
- }
146
- if (url)
147
- urls.push(url);
148
- }
149
- return urls;
150
- }
151
- /** Whether a CDN URL names an exact version. `@latest` and bare package paths do not. */
152
- function pinned(url) {
153
- const path = url.pathname.replace(/%40/gi, "@");
154
- if (/@latest\b/i.test(path))
155
- return false;
156
- if (url.hostname === "cdnjs.cloudflare.com") {
157
- return /^\/ajax\/libs\/[^/]+\/\d/.test(path);
158
- }
159
- return /@v?\d/.test(path);
160
- }
161
- const PINNED_EXAMPLE = "https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js";
162
- const EMBEDDING = {
163
- iframe: "pages cannot embed other pages",
164
- frame: "pages cannot embed other pages",
165
- frameset: "pages cannot embed other pages",
166
- portal: "pages cannot embed other pages",
167
- object: "pages cannot embed plugins or other documents",
168
- embed: "pages cannot embed plugins or other documents",
169
- applet: "pages cannot embed plugins or other documents",
170
- form: "pages cannot submit forms; use inputs without a <form> and read them from a script",
171
- base: "it would change how every URL on the page resolves",
172
- };
173
- const FORBIDDEN_ATTRIBUTES = {
174
- srcdoc: "it embeds another document",
175
- ping: "it sends a request when a link is followed, and pages have no network",
176
- formaction: "pages cannot submit forms",
177
- action: "pages cannot submit forms",
178
- };
179
- /** Attributes that fetch what they name. */
180
- const RESOURCE_ATTRIBUTES = new Set(["src", "poster", "background", "data", "lowsrc", "dynsrc"]);
181
- /** Attributes a reader follows. */
182
- const NAVIGATION_ATTRIBUTES = new Set(["cite", "longdesc"]);
183
- const NETWORK = /\b(fetch\s*\(|XMLHttpRequest\b|WebSocket\b|EventSource\b|sendBeacon\b|importScripts\s*\()/;
184
- const DATA_READS = [
185
- /\bartifact\s*\.\s*data\s*\.\s*([A-Za-z_$][A-Za-z0-9_$]*)/g,
186
- /\bartifact\s*\.\s*data\s*\[\s*["']([^"'\\]{1,64})["']\s*\]/g,
187
- ];
188
- /** Every static finding for a page's source. */
189
- export function checkView(input, context) {
190
- const findings = { errors: [], warnings: [] };
191
- const { source, kind } = input;
192
- const { limits } = context;
193
- if (typeof source !== "string" || !source.trim()) {
194
- findings.errors.push({
195
- code: "E_EMPTY",
196
- severity: "error",
197
- message: kind === "markdown"
198
- ? "The source is empty. Write the Markdown the page should show."
199
- : 'The source is empty. Write a complete page, e.g. <!doctype html><main id="artifact-root">…</main>.',
200
- });
201
- return findings;
202
- }
203
- const bytes = utf8Bytes(source);
204
- if (bytes > limits.sourceBytes) {
205
- findings.errors.push({
206
- code: "E_TOO_LARGE",
207
- severity: "error",
208
- message: `The source is ${count(bytes)} bytes; the limit is ${count(limits.sourceBytes)} (${kib(limits.sourceBytes)}). ` +
209
- "Move data into documents, or trim the page.",
210
- });
211
- return findings;
212
- }
213
- if (kind === "markdown") {
214
- let rendered;
215
- try {
216
- // The served page also carries themeCss (≤~0.5 KB), which FRAME_OVERHEAD_BYTES absorbs.
217
- rendered = utf8Bytes(markdownPage(source, input.title ?? "")) + input.dataBytes + FRAME_OVERHEAD_BYTES;
218
- }
219
- catch (error) {
220
- if (!(error instanceof MarkdownNestingError))
221
- throw error;
222
- findings.errors.push({ code: "E_NESTING", severity: "error", message: error.message });
223
- return findings;
224
- }
225
- if (rendered > limits.renderedBytes) {
226
- findings.errors.push({
227
- code: "E_TOO_LARGE",
228
- severity: "error",
229
- message: `The rendered page would be ${count(rendered)} bytes; the limit is ${count(limits.renderedBytes)} ` +
230
- `(${kib(limits.renderedBytes)}). Shorten the Markdown.`,
231
- });
232
- }
233
- checkMarkdownImages(source, findings);
234
- return findings;
235
- }
236
- const rendered = bytes + input.dataBytes + FRAME_OVERHEAD_BYTES;
237
- if (rendered > limits.renderedBytes) {
238
- findings.errors.push({
239
- code: "E_TOO_LARGE",
240
- severity: "error",
241
- message: `The page plus its documents would be ${count(rendered)} bytes; the limit is ` +
242
- `${count(limits.renderedBytes)} (${kib(limits.renderedBytes)}). Trim the page or its documents.`,
243
- });
244
- }
245
- checkHtml(input, context, findings);
246
- return findings;
247
- }
248
- function checkMarkdownImages(source, findings) {
249
- const locate = lineLocator(source);
250
- const image = /!\[[^\]]*\]\(\s*<?([^)\s>]+)/g;
251
- let match;
252
- while ((match = image.exec(source)) !== null) {
253
- const url = match[1] ?? "";
254
- if (/^data:image\//i.test(url))
255
- continue;
256
- const { line } = locate(match.index);
257
- findings.warnings.push({
258
- code: "W_IMAGE",
259
- severity: "warning",
260
- line,
261
- message: `Line ${line}: the image ${quote(url)} will not load; pages have no network. ` +
262
- "Embed it as a data:image/png;base64,… URL.",
263
- });
264
- }
265
- }
266
- function checkHtml(input, context, findings) {
267
- const { source } = input;
268
- const { allowlist } = context;
269
- const tokens = scanHtml(source);
270
- const locate = lineLocator(source);
271
- const at = (offset) => locate(offset);
272
- const error = (code, offset, message) => {
273
- if (offset === undefined) {
274
- findings.errors.push({ code, severity: "error", message });
275
- return;
276
- }
277
- const { line, column } = at(offset);
278
- findings.errors.push({ code, severity: "error", line, column, message: `Line ${line}: ${message}` });
279
- };
280
- const warn = (code, offset, message) => {
281
- if (offset === undefined) {
282
- findings.warnings.push({ code, severity: "warning", message });
283
- return;
284
- }
285
- const { line, column } = at(offset);
286
- findings.warnings.push({ code, severity: "warning", line, column, message: `Line ${line}: ${message}` });
287
- };
288
- const roots = [];
289
- let sawDoctype = false;
290
- let sawElement = false;
291
- const externalLinks = [];
292
- const unpinned = new Set();
293
- const missingNames = new Map();
294
- let networkWarned = 0;
295
- const scriptOriginHelp = allowlist.scripts.length
296
- ? ` (${allowlist.scripts.join(", ")}). Load it from one of those, pinned, e.g. ${PINNED_EXAMPLE}.`
297
- : ". This deployment allows no external scripts. Inline the script, or ask the operator to trust its origin.";
298
- const styleOriginHelp = allowlist.styles.length
299
- ? ` (${allowlist.styles.join(", ")}). Inline the CSS in a <style> element, or load it from one of those.`
300
- : ". This deployment allows no external stylesheets. Inline the CSS, or ask the operator to trust its origin.";
301
- const styleImportHelp = allowlist.styles.length
302
- ? ` (${allowlist.styles.join(", ")}). Inline the CSS, or import from one of those.`
303
- : ". This deployment allows no external stylesheets. Inline the CSS, or ask the operator to trust its origin.";
304
- const checkResourceUrl = (tag, attr) => {
305
- const value = attr.value;
306
- const shown = `<${tag} ${attr.name}="${quote(value)}">`;
307
- const trimmed = normalizedUrl(value);
308
- if (!trimmed) {
309
- error("E_URL", attr.offset, `${shown} is empty. Remove the attribute or embed the content as a data: URL.`);
310
- return;
311
- }
312
- const scheme = schemeOf(trimmed);
313
- if (trimmed.startsWith("#") && (attr.name === "href" || attr.name === "xlink:href"))
314
- return;
315
- if (scheme === "data" || scheme === "blob")
316
- return;
317
- if (scheme === undefined) {
318
- error("E_URL", attr.offset, `${shown} is relative; pages have no files beside them. Embed it as a data: URL.`);
319
- }
320
- else if (scheme === "https" || scheme === "http") {
321
- error("E_URL", attr.offset, `${shown} loads from the network, and pages have no network. Embed it as a data: URL.`);
322
- }
323
- else {
324
- error("E_URL", attr.offset, `${shown} uses ${scheme}:, which pages cannot load. Embed it as a data: URL.`);
325
- }
326
- };
327
- const checkLinkUrl = (tag, attr) => {
328
- const value = attr.value;
329
- const trimmed = normalizedUrl(value);
330
- if (!trimmed || trimmed.startsWith("#"))
331
- return;
332
- const shown = `<${tag} ${attr.name}="${quote(value)}">`;
333
- const scheme = schemeOf(trimmed);
334
- if (scheme === "https" || scheme === "mailto") {
335
- externalLinks.push(attr.offset);
336
- return;
337
- }
338
- if (scheme === undefined) {
339
- error("E_URL", attr.offset, `${shown} is relative; pages have no files beside them. Link an https: URL or a #fragment.`);
340
- }
341
- else if (scheme === "http") {
342
- error("E_URL", attr.offset, `${shown} uses http:. Link the https: URL instead.`);
343
- }
344
- else if (scheme === "javascript") {
345
- error("E_URL", attr.offset, `${shown} uses javascript:. Attach a click handler from a <script> instead.`);
346
- }
347
- else {
348
- error("E_URL", attr.offset, `${shown} uses ${scheme}:. Links may be https:, mailto:, or a #fragment.`);
349
- }
350
- };
351
- const checkCss = (css, offset, where) => {
352
- const urls = /url\(\s*(?:"([^"]*)"|'([^']*)'|([^)\s]*))\s*\)/gi;
353
- // An @import is judged once, as an import; blank it (keeping offsets) so
354
- // its url() is not judged again as a resource.
355
- const resources = css.replace(/@import[^;]*;?/gi, (statement) => " ".repeat(statement.length));
356
- let match;
357
- while ((match = urls.exec(resources)) !== null) {
358
- const value = match[1] ?? match[2] ?? match[3] ?? "";
359
- const trimmed = normalizedUrl(value);
360
- if (trimmed.startsWith("#"))
361
- continue;
362
- const scheme = schemeOf(trimmed);
363
- if (scheme === "data" || scheme === "blob")
364
- continue;
365
- const https = httpsOrigin(trimmed);
366
- if (https && allowlist.fonts.includes(https.origin))
367
- continue;
368
- const position = offset + match.index;
369
- error("E_URL", position, scheme === undefined
370
- ? `${where} url(${quote(value)}) is relative; pages have no files beside them. Use a data: URL.`
371
- : `${where} url(${quote(value)}) loads from the network, and pages have no network. Use a data: URL.`);
372
- }
373
- const imports = /@import\s+(?:url\(\s*)?["']?([^"')\s;]+)/gi;
374
- while ((match = imports.exec(css)) !== null) {
375
- const value = match[1] ?? "";
376
- const https = httpsOrigin(value);
377
- if (https && !https.credentials && allowlist.styles.includes(https.origin))
378
- continue;
379
- error("E_STYLE_ORIGIN", offset + match.index, `${where} @import ${quote(value)} loads from outside the style allowlist${styleImportHelp}`);
380
- }
381
- };
382
- const checkScriptSource = (text, offset) => {
383
- if (networkWarned < 3) {
384
- const network = NETWORK.exec(text);
385
- if (network) {
386
- networkWarned++;
387
- warn("W_NETWORK", offset + network.index, `the script calls ${network[1]?.replace(/\s*\($/, "")}, but pages have no network. Read window.artifact.data instead.`);
388
- }
389
- }
390
- for (const pattern of DATA_READS) {
391
- pattern.lastIndex = 0;
392
- let match;
393
- while ((match = pattern.exec(text)) !== null) {
394
- const name = match[1] ?? "";
395
- if (!input.documentNames.includes(name) && !missingNames.has(name)) {
396
- missingNames.set(name, offset + match.index);
397
- }
398
- }
399
- }
400
- };
401
- for (const token of tokens) {
402
- if (token.type === "doctype") {
403
- if (!sawElement)
404
- sawDoctype = true;
405
- continue;
406
- }
407
- if (token.type === "text") {
408
- if (token.rawOf === "style") {
409
- checkCss(source.slice(token.start, token.end), token.start, "<style>");
410
- }
411
- else if (token.rawOf === "script") {
412
- checkScriptSource(source.slice(token.start, token.end), token.start);
413
- }
414
- continue;
415
- }
416
- if (token.type !== "start")
417
- continue;
418
- sawElement = true;
419
- const tag = token.name;
420
- const attr = (name) => token.attrs.find((candidate) => candidate.name === name);
421
- const embedding = EMBEDDING[tag];
422
- if (embedding) {
423
- error("E_ELEMENT", token.start, `<${tag}> is not allowed; ${embedding}. Remove it.`);
424
- }
425
- if (tag === "meta" && attr("http-equiv")) {
426
- error("E_ELEMENT", token.start, "<meta http-equiv> is not allowed; the viewer sets the page's headers. Remove it.");
427
- }
428
- for (const attribute of token.attrs) {
429
- const name = attribute.name;
430
- if (name === "id" && attribute.value === "artifact-root")
431
- roots.push(token.start);
432
- // An element that is refused whole needs no second finding per URL.
433
- if (embedding)
434
- continue;
435
- const forbidden = FORBIDDEN_ATTRIBUTES[name];
436
- if (forbidden) {
437
- error("E_ATTRIBUTE", attribute.offset, `the ${name} attribute on <${tag}> is not allowed; ${forbidden}. Remove it.`);
438
- continue;
439
- }
440
- if (name === "style")
441
- checkCss(attribute.value, attribute.offset, `<${tag} style>`);
442
- if (name === "srcset" || name === "imagesrcset") {
443
- const bad = srcsetUrls(attribute.value).find((candidate) => {
444
- const scheme = schemeOf(candidate);
445
- return scheme !== "data" && scheme !== "blob";
446
- });
447
- if (bad !== undefined) {
448
- error("E_ATTRIBUTE", attribute.offset, `<${tag} ${name}> names ${quote(bad)}, which cannot load; pages have no network. ` +
449
- "Use a single src with a data: URL.");
450
- }
451
- continue;
452
- }
453
- if (tag === "script" || tag === "link")
454
- continue;
455
- if (name === "href" || name === "xlink:href") {
456
- if (tag === "a" || tag === "area")
457
- checkLinkUrl(tag, attribute);
458
- else
459
- checkResourceUrl(tag, attribute);
460
- continue;
461
- }
462
- if (RESOURCE_ATTRIBUTES.has(name))
463
- checkResourceUrl(tag, attribute);
464
- else if (NAVIGATION_ATTRIBUTES.has(name))
465
- checkLinkUrl(tag, attribute);
466
- }
467
- if (tag === "script") {
468
- const src = attr("src") ?? attr("href") ?? attr("xlink:href");
469
- if (src) {
470
- const https = httpsOrigin(src.value);
471
- const shown = `<script src="${quote(src.value)}">`;
472
- if (!https || https.credentials || !allowlist.scripts.includes(https.origin)) {
473
- error("E_SCRIPT_ORIGIN", src.offset, `${shown} ${!https
474
- ? schemeOf(src.value) === undefined
475
- ? "is relative, and pages have no files beside them"
476
- : "is not an https: URL"
477
- : https.credentials
478
- ? "carries credentials"
479
- : "loads from outside the allowlist"}${scriptOriginHelp}`);
480
- }
481
- else if (!pinned(https.url) && !unpinned.has(https.url.href)) {
482
- unpinned.add(https.url.href);
483
- warn("W_UNPINNED", src.offset, `${shown} names no exact version, so the page can change or break when the library does. Pin one, e.g. ${PINNED_EXAMPLE}.`);
484
- }
485
- }
486
- }
487
- if (tag === "link") {
488
- const href = attr("href");
489
- const rels = (attr("rel")?.value ?? "").toLowerCase().split(/\s+/).filter(Boolean);
490
- if (!href)
491
- continue;
492
- const https = httpsOrigin(href.value);
493
- const shown = `<link rel="${quote(rels.join(" "))}" href="${quote(href.value)}">`;
494
- const stylesheet = rels.includes("stylesheet");
495
- const hint = rels.length > 0 && rels.every((rel) => rel === "preconnect" || rel === "dns-prefetch");
496
- if (!stylesheet && !hint) {
497
- error("E_STYLE_ORIGIN", href.offset, `${shown} is not allowed; only rel="stylesheet" and rel="preconnect" links load. Remove it.`);
498
- continue;
499
- }
500
- const allowed = stylesheet ? allowlist.styles : [...allowlist.styles, ...allowlist.fonts];
501
- if (!https || https.credentials || !allowed.includes(https.origin)) {
502
- error("E_STYLE_ORIGIN", href.offset, `${shown} loads from outside the style allowlist${styleOriginHelp}`);
503
- }
504
- else if (stylesheet && https.url.hostname !== "fonts.googleapis.com" && !pinned(https.url) && !unpinned.has(https.url.href)) {
505
- unpinned.add(https.url.href);
506
- warn("W_UNPINNED", href.offset, `${shown} names no exact version, so the page can change when the library does. Pin one.`);
507
- }
508
- }
509
- }
510
- if (roots.length === 0) {
511
- error("E_ROOT", undefined, 'No element has id="artifact-root". Wrap the page in <main id="artifact-root">…</main>.');
512
- }
513
- else if (roots.length > 1) {
514
- const lines = roots.slice(0, 5).map((offset) => at(offset).line);
515
- error("E_ROOT", roots[1], `id="artifact-root" appears ${roots.length} times (lines ${lines.join(", ")}${roots.length > 5 ? ", …" : ""}). ` +
516
- "Keep exactly one.");
517
- }
518
- if (!sawDoctype) {
519
- warn("W_NO_DOCTYPE", undefined, "The page has no <!doctype html>, so it renders in quirks mode. Start it with <!doctype html>.");
520
- }
521
- for (const [name, offset] of missingNames) {
522
- const have = input.documentNames.length ? input.documentNames.join(", ") : "none";
523
- warn("W_DATA_NAME", offset, `the script reads artifact.data.${quote(name)}, but the page gets no document named ${quote(name)} ` +
524
- `(it has: ${have}). Save it with artifacts.set_documents, or read a name that exists.`);
525
- }
526
- const firstLink = externalLinks[0];
527
- if (firstLink !== undefined) {
528
- warn("W_EXTERNAL_LINK", firstLink, `${externalLinks.length === 1 ? "a link leaves" : `${externalLinks.length} links leave`} the page when clicked: ` +
529
- "they navigate the artifact's own frame, and pages cannot open new windows. Show the URL as text if readers need it elsewhere.");
530
- }
531
- }
532
- /** Check one document's name and value, and serialize it the way it is stored. */
533
- export function checkDocument(name, value, limits) {
534
- if (!validDocumentName(name)) {
535
- return {
536
- bytes: 0,
537
- error: {
538
- code: "E_DOCUMENT",
539
- severity: "error",
540
- message: `Document name ${quote(String(name))} is not allowed. Use letters, digits, and _, starting with a letter ` +
541
- "or _, at most 64 characters, and avoid reserved object property names, so a page can read it as artifact.data.<name>.",
542
- },
543
- };
544
- }
545
- const problem = jsonProblem(value, limits.jsonDepth);
546
- if (problem !== undefined) {
547
- return {
548
- bytes: 0,
549
- error: {
550
- code: "E_DOCUMENT",
551
- severity: "error",
552
- message: `Document '${name}' is not storable JSON: ${problem}.`,
553
- },
554
- };
555
- }
556
- const text = scriptSafeJson(value);
557
- const bytes = utf8Bytes(text);
558
- if (bytes > limits.documentBytes) {
559
- return {
560
- bytes,
561
- error: {
562
- code: "E_TOO_LARGE",
563
- severity: "error",
564
- message: `Document '${name}' is ${count(bytes)} bytes serialized; one document may be at most ` +
565
- `${count(limits.documentBytes)} (${kib(limits.documentBytes)}). Split it across documents or drop fields the page does not show.`,
566
- },
567
- };
568
- }
569
- return { text, bytes };
570
- }
571
- /** The collective document bounds: how many, and how large together. */
572
- export function checkDocumentTotals(live, totalBytes, limits) {
573
- if (live > limits.documents) {
574
- return {
575
- code: "E_TOO_LARGE",
576
- severity: "error",
577
- message: `The artifact would have ${live} documents; the limit is ${limits.documents}. ` +
578
- "Combine related data into fewer documents, or remove one by setting it to null.",
579
- };
580
- }
581
- if (totalBytes > limits.totalDocumentBytes) {
582
- return {
583
- code: "E_TOO_LARGE",
584
- severity: "error",
585
- message: `Its documents would total ${count(totalBytes)} bytes; the limit is ${count(limits.totalDocumentBytes)} ` +
586
- `(${kib(limits.totalDocumentBytes)}). Drop data the page does not show.`,
587
- };
588
- }
589
- return undefined;
590
- }
591
- /** Sort findings by position, cap errors at 20, and report what was cut. */
592
- export function finish(findings) {
593
- const order = (a, b) => (a.line ?? 0) - (b.line ?? 0) || (a.column ?? 0) - (b.column ?? 0);
594
- const errors = [...findings.errors].sort(order);
595
- const warnings = [...findings.warnings].sort(order).slice(0, MAX_REPORTED);
596
- const validation = {
597
- ok: errors.length === 0,
598
- errors: errors.slice(0, MAX_REPORTED),
599
- warnings,
600
- };
601
- if (errors.length > MAX_REPORTED)
602
- validation.errorsOmitted = errors.length - MAX_REPORTED;
603
- return validation;
604
- }
605
- /**
606
- * Validate a page and its documents without saving anything: the same static
607
- * checks every artifact write runs. `ok` is exactly "no errors"; warnings are
608
- * advice.
609
- */
610
- export function validateArtifact(input, options = {}) {
611
- const context = {
612
- limits: resolveLimits(options.limits),
613
- allowlist: resolveAllowlist(options.allowlist),
614
- };
615
- return validateWithContext(input, context);
616
- }
617
- /** `validateArtifact` against an already-resolved context. */
618
- export function validateWithContext(input, context) {
619
- const findings = { errors: [], warnings: [] };
620
- if (input.kind !== "html" && input.kind !== "markdown") {
621
- findings.errors.push({
622
- code: "E_KIND",
623
- severity: "error",
624
- message: 'kind must be "html" or "markdown".',
625
- });
626
- return finish(findings);
627
- }
628
- const documents = input.documents ?? {};
629
- let dataBytes = 0;
630
- let live = 0;
631
- for (const [name, value] of Object.entries(documents)) {
632
- const checked = checkDocument(name, value, context.limits);
633
- if (checked.error)
634
- findings.errors.push(checked.error);
635
- dataBytes += checked.bytes;
636
- live++;
637
- }
638
- const totals = checkDocumentTotals(live, dataBytes, context.limits);
639
- if (totals)
640
- findings.errors.push(totals);
641
- const view = checkView({
642
- kind: input.kind,
643
- source: input.source,
644
- ...(input.title === undefined ? {} : { title: input.title }),
645
- documentNames: Object.keys(documents),
646
- dataBytes,
647
- }, context);
648
- findings.errors.push(...view.errors);
649
- findings.warnings.push(...view.warnings);
650
- return finish(findings);
651
- }
@@ -1,6 +0,0 @@
1
- export { artifacts, type ArtifactsOptions, type RefreshableArtifacts } from "./artifacts/module.js";
2
- export type { RefreshOutcome } from "./artifacts/refresh.js";
3
- export type { ArtifactRenderCheck, ArtifactRenderCheckInput, ArtifactRenderCheckResult, } from "./artifacts/connector.js";
4
- export { kvArtifactStore, type KvArtifactStoreOptions } from "./artifacts/kv-store.js";
5
- export { validateArtifact, type ValidateArtifactInput, type ValidateArtifactOptions, } from "./artifacts/validate.js";
6
- export { ARTIFACT_RUNS_RETAINED, DEFAULT_ARTIFACT_ALLOWLIST, DEFAULT_ARTIFACT_LIMITS, type ArtifactActor, type ArtifactAllowlist, type ArtifactBlobStore, type ArtifactHeadRecord, type ArtifactRefreshState, type ArtifactRefreshSchedule, type ArtifactIssue, type ArtifactKind, type ArtifactLimits, type ArtifactRunRecord, type ArtifactStore, type ArtifactStream, type ArtifactValidation, type ArtifactVersionOp, type ArtifactVersionRecord, } from "./artifacts/types.js";
package/dist/artifacts.js DELETED
@@ -1,9 +0,0 @@
1
- // @zackbart/connecta/artifacts — the optional artifacts module.
2
- //
3
- // Team pages over stored JSON, reached by agents through a built-in
4
- // connector. Nothing here is reachable from the root entry: a deployment that
5
- // never imports this subpath carries none of it and does none of its work.
6
- export { artifacts } from "./artifacts/module.js";
7
- export { kvArtifactStore } from "./artifacts/kv-store.js";
8
- export { validateArtifact, } from "./artifacts/validate.js";
9
- export { ARTIFACT_RUNS_RETAINED, DEFAULT_ARTIFACT_ALLOWLIST, DEFAULT_ARTIFACT_LIMITS, } from "./artifacts/types.js";
@@ -1,11 +0,0 @@
1
- import type { InboundAuth } from "../types.js";
2
- export interface BearerTokenOptions {
3
- /** Stable identity for this credential, used on activity events. */
4
- subjectId?: string;
5
- }
6
- /**
7
- * Static bearer-token inbound auth. Constant-time compares the Bearer token
8
- * against `secret`. Checked before interactive providers in the server; a
9
- * mismatch falls through so another configured provider can admit the request.
10
- */
11
- export declare function bearerToken(secret: string, options?: BearerTokenOptions): InboundAuth;