@yiaany/ghostapi 0.1.9 → 0.2.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 (292) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/CONTRIBUTING.md +132 -119
  3. package/LICENSE +21 -21
  4. package/PROVENANCE.md +13 -0
  5. package/README.md +78 -84
  6. package/SECURITY.md +56 -53
  7. package/dist/actions/gateway.js +320 -72
  8. package/dist/actions/gateway.js.map +1 -1
  9. package/dist/actions/index.d.ts +2 -2
  10. package/dist/actions/index.js +1 -1
  11. package/dist/actions/index.js.map +1 -1
  12. package/dist/agents/agentPrompt.js +7 -5
  13. package/dist/agents/agentPrompt.js.map +1 -1
  14. package/dist/ai/aiClient.js +5 -5
  15. package/dist/ai/aiClient.js.map +1 -1
  16. package/dist/ai/aiGenerator.js +66 -26
  17. package/dist/ai/aiGenerator.js.map +1 -1
  18. package/dist/ai/genericInference.js +151 -36
  19. package/dist/ai/genericInference.js.map +1 -1
  20. package/dist/ai/prompts.js +55 -49
  21. package/dist/ai/prompts.js.map +1 -1
  22. package/dist/approvals/approvalInbox.js +649 -133
  23. package/dist/approvals/approvalInbox.js.map +1 -1
  24. package/dist/approvals/index.d.ts +2 -2
  25. package/dist/approvals/index.js +1 -1
  26. package/dist/approvals/index.js.map +1 -1
  27. package/dist/behavior/behaviorStore.js +34 -14
  28. package/dist/behavior/behaviorStore.js.map +1 -1
  29. package/dist/cache/index.js +14 -5
  30. package/dist/cache/index.js.map +1 -1
  31. package/dist/cli/index.js +226 -93
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/cli/openUrl.js +17 -3
  34. package/dist/cli/openUrl.js.map +1 -1
  35. package/dist/cli/parser.js +79 -18
  36. package/dist/cli/parser.js.map +1 -1
  37. package/dist/config/dataPaths.js +4 -2
  38. package/dist/config/dataPaths.js.map +1 -1
  39. package/dist/config/localConfig.js +5 -2
  40. package/dist/config/localConfig.js.map +1 -1
  41. package/dist/config/serverConfig.js +11 -5
  42. package/dist/config/serverConfig.js.map +1 -1
  43. package/dist/contracts/contract.js +311 -83
  44. package/dist/contracts/contract.js.map +1 -1
  45. package/dist/contracts/index.d.ts +2 -2
  46. package/dist/contracts/index.js +1 -1
  47. package/dist/contracts/index.js.map +1 -1
  48. package/dist/credentials/credentialBroker.js +391 -79
  49. package/dist/credentials/credentialBroker.js.map +1 -1
  50. package/dist/credentials/index.d.ts +2 -2
  51. package/dist/credentials/index.js +1 -1
  52. package/dist/credentials/index.js.map +1 -1
  53. package/dist/dashboard/app.js +823 -685
  54. package/dist/dashboard/dashboard.js.map +1 -1
  55. package/dist/dashboard/index.html +704 -267
  56. package/dist/dashboard/styles.css +1040 -349
  57. package/dist/egress/capabilities.js +55 -25
  58. package/dist/egress/capabilities.js.map +1 -1
  59. package/dist/egress/linuxBootstrap.js +47 -11
  60. package/dist/egress/linuxBootstrap.js.map +1 -1
  61. package/dist/egress/run.js +170 -31
  62. package/dist/egress/run.js.map +1 -1
  63. package/dist/errors/errorEngine.js +15 -3
  64. package/dist/errors/errorEngine.js.map +1 -1
  65. package/dist/errors/providerErrors.js.map +1 -1
  66. package/dist/evals/evals.js +304 -78
  67. package/dist/evals/evals.js.map +1 -1
  68. package/dist/evals/index.d.ts +2 -2
  69. package/dist/evals/index.js +1 -1
  70. package/dist/evals/index.js.map +1 -1
  71. package/dist/evidence/index.d.ts +2 -2
  72. package/dist/evidence/index.js +1 -1
  73. package/dist/evidence/index.js.map +1 -1
  74. package/dist/evidence/report.d.ts +1 -1
  75. package/dist/evidence/report.js +263 -79
  76. package/dist/evidence/report.js.map +1 -1
  77. package/dist/fault/faultLab.js +24 -9
  78. package/dist/fault/faultLab.js.map +1 -1
  79. package/dist/index.d.ts +42 -42
  80. package/dist/index.js +21 -21
  81. package/dist/index.js.map +1 -1
  82. package/dist/inventory/analysis.d.ts +1 -1
  83. package/dist/inventory/analysis.js +174 -50
  84. package/dist/inventory/analysis.js.map +1 -1
  85. package/dist/inventory/index.d.ts +4 -4
  86. package/dist/inventory/index.js +3 -3
  87. package/dist/inventory/index.js.map +1 -1
  88. package/dist/inventory/inventoryController.js +362 -115
  89. package/dist/inventory/inventoryController.js.map +1 -1
  90. package/dist/inventory/types.js +680 -140
  91. package/dist/inventory/types.js.map +1 -1
  92. package/dist/ledger/actionLedger.js +355 -78
  93. package/dist/ledger/actionLedger.js.map +1 -1
  94. package/dist/ledger/index.d.ts +2 -2
  95. package/dist/ledger/index.js +1 -1
  96. package/dist/ledger/index.js.map +1 -1
  97. package/dist/mcp/server.js +26 -11
  98. package/dist/mcp/server.js.map +1 -1
  99. package/dist/policy/index.d.ts +2 -2
  100. package/dist/policy/index.js +1 -1
  101. package/dist/policy/index.js.map +1 -1
  102. package/dist/policy/policy.js +112 -32
  103. package/dist/policy/policy.js.map +1 -1
  104. package/dist/productTelemetry/index.js +71 -20
  105. package/dist/productTelemetry/index.js.map +1 -1
  106. package/dist/providers/conformance.js +10 -5
  107. package/dist/providers/conformance.js.map +1 -1
  108. package/dist/providers/discord.js +2 -2
  109. package/dist/providers/generic.js +3 -3
  110. package/dist/providers/github.js +2 -2
  111. package/dist/providers/index.d.ts +3 -3
  112. package/dist/providers/index.js +2 -2
  113. package/dist/providers/index.js.map +1 -1
  114. package/dist/providers/openai.js +3 -3
  115. package/dist/providers/packs/resendPack.js +51 -25
  116. package/dist/providers/packs/resendPack.js.map +1 -1
  117. package/dist/providers/packs/stripePack.js +590 -121
  118. package/dist/providers/packs/stripePack.js.map +1 -1
  119. package/dist/providers/registry.js +4 -4
  120. package/dist/providers/registry.js.map +1 -1
  121. package/dist/providers/runtime.js +7 -6
  122. package/dist/providers/runtime.js.map +1 -1
  123. package/dist/providers/stripeWebhook.js +39 -10
  124. package/dist/providers/stripeWebhook.js.map +1 -1
  125. package/dist/providers/twilio.js +2 -2
  126. package/dist/proxy/cacheKey.js +9 -2
  127. package/dist/proxy/cacheKey.js.map +1 -1
  128. package/dist/proxy/providerDetector.js +22 -9
  129. package/dist/proxy/providerDetector.js.map +1 -1
  130. package/dist/proxy/proxyHandler.js +57 -22
  131. package/dist/proxy/proxyHandler.js.map +1 -1
  132. package/dist/proxy/requestNormalizer.js +4 -2
  133. package/dist/proxy/requestNormalizer.js.map +1 -1
  134. package/dist/reliability/costGovernance.js +211 -49
  135. package/dist/reliability/costGovernance.js.map +1 -1
  136. package/dist/reliability/index.d.ts +8 -8
  137. package/dist/reliability/index.js +4 -4
  138. package/dist/reliability/index.js.map +1 -1
  139. package/dist/reliability/reconciliation.js +274 -65
  140. package/dist/reliability/reconciliation.js.map +1 -1
  141. package/dist/reliability/runtimeHealth.js +127 -35
  142. package/dist/reliability/runtimeHealth.js.map +1 -1
  143. package/dist/reliability/slo.js +257 -50
  144. package/dist/reliability/slo.js.map +1 -1
  145. package/dist/report/safetyReport.d.ts +6 -0
  146. package/dist/report/safetyReport.js +56 -12
  147. package/dist/report/safetyReport.js.map +1 -1
  148. package/dist/rules/aiRules.js +5 -5
  149. package/dist/rules/aiRules.js.map +1 -1
  150. package/dist/safety/index.d.ts +2 -2
  151. package/dist/safety/index.js +1 -1
  152. package/dist/safety/index.js.map +1 -1
  153. package/dist/safety/safetyController.js +675 -165
  154. package/dist/safety/safetyController.js.map +1 -1
  155. package/dist/scenarios/scenarioBundle.js +204 -71
  156. package/dist/scenarios/scenarioBundle.js.map +1 -1
  157. package/dist/scenarios/scenarioStore.js +88 -29
  158. package/dist/scenarios/scenarioStore.js.map +1 -1
  159. package/dist/security/headerSanitizer.js +52 -10
  160. package/dist/security/headerSanitizer.js.map +1 -1
  161. package/dist/security/secrets.js +10 -5
  162. package/dist/security/secrets.js.map +1 -1
  163. package/dist/server/accessControl.js +37 -10
  164. package/dist/server/accessControl.js.map +1 -1
  165. package/dist/server/createServer.js +1 -1
  166. package/dist/server/createServer.js.map +1 -1
  167. package/dist/server/eventsStore.js +15 -5
  168. package/dist/server/eventsStore.js.map +1 -1
  169. package/dist/server/routes.js +61 -19
  170. package/dist/server/routes.js.map +1 -1
  171. package/dist/server/sse.js +1 -1
  172. package/dist/server/sse.js.map +1 -1
  173. package/dist/setup/sdkDetector.js +7 -2
  174. package/dist/setup/sdkDetector.js.map +1 -1
  175. package/dist/setup/setupGenerator.js +136 -48
  176. package/dist/setup/setupGenerator.js.map +1 -1
  177. package/dist/state/stateExtractor.js +3 -1
  178. package/dist/state/stateExtractor.js.map +1 -1
  179. package/dist/state/stateResolver.js +10 -7
  180. package/dist/state/stateResolver.js.map +1 -1
  181. package/dist/state/stateStore.js +13 -4
  182. package/dist/state/stateStore.js.map +1 -1
  183. package/dist/storage/fileStore.js +12 -4
  184. package/dist/storage/fileStore.js.map +1 -1
  185. package/dist/teamControl/controlPlane.js +846 -174
  186. package/dist/teamControl/controlPlane.js.map +1 -1
  187. package/dist/teamControl/deployment.js +19 -5
  188. package/dist/teamControl/deployment.js.map +1 -1
  189. package/dist/teamControl/index.d.ts +4 -4
  190. package/dist/teamControl/index.js +2 -2
  191. package/dist/teamControl/index.js.map +1 -1
  192. package/dist/tests/testGenerator.js +15 -7
  193. package/dist/tests/testGenerator.js.map +1 -1
  194. package/dist/trust/index.d.ts +2 -2
  195. package/dist/trust/index.js +1 -1
  196. package/dist/trust/index.js.map +1 -1
  197. package/dist/trust/trustLadder.js +309 -63
  198. package/dist/trust/trustLadder.js.map +1 -1
  199. package/dist/worlds/index.d.ts +2 -2
  200. package/dist/worlds/index.js +1 -1
  201. package/dist/worlds/index.js.map +1 -1
  202. package/dist/worlds/worlds.js +364 -65
  203. package/dist/worlds/worlds.js.map +1 -1
  204. package/docs/assets/dashboard.png +0 -0
  205. package/docs/ci.md +49 -49
  206. package/docs/github-actions.md +84 -84
  207. package/docs/mcp.md +58 -52
  208. package/docs/policy.md +63 -61
  209. package/docs/providers/authoring-packs.md +180 -175
  210. package/docs/providers/stripe-core-pack.md +84 -82
  211. package/docs/releases/README.md +13 -0
  212. package/docs/security/action-gateway-threat-model.md +34 -34
  213. package/docs/security/action-ledger-incident-replay-threat-model.md +42 -42
  214. package/docs/security/approval-inbox-threat-model.md +35 -35
  215. package/docs/security/credential-broker-threat-model.md +52 -52
  216. package/docs/security/egress-threat-model.md +126 -126
  217. package/docs/security/inventory-threat-model.md +104 -104
  218. package/docs/security/kill-switch-budgets-threat-model.md +37 -37
  219. package/docs/security/reliability-threat-model.md +111 -111
  220. package/docs/security/trust-ladder-threat-model.md +33 -33
  221. package/docs/telemetry.md +14 -0
  222. package/docs/usage.md +680 -571
  223. package/examples/README.md +10 -10
  224. package/examples/agent-instructions/README.md +39 -39
  225. package/examples/ci-smoke/README.md +21 -21
  226. package/examples/ci-smoke/ghostapi.policy.yaml +22 -22
  227. package/examples/ci-smoke/package.json +9 -9
  228. package/examples/ci-smoke/production-egress.mjs +4 -2
  229. package/examples/ci-smoke/safe.mjs +21 -17
  230. package/examples/evals/README.md +24 -24
  231. package/examples/evals/retry-after.eval.json +71 -52
  232. package/examples/generic-rest/README.md +27 -27
  233. package/examples/github-fetch/README.md +38 -35
  234. package/examples/openai-streaming/README.md +16 -16
  235. package/examples/openai-streaming/streaming-tool-call.mjs +44 -31
  236. package/examples/policy/ghostapi.policy.yaml +27 -27
  237. package/examples/record-replay/README.md +19 -19
  238. package/examples/record-replay/replay-requests.json +22 -22
  239. package/examples/record-replay/stripe-checkout.har.json +30 -30
  240. package/examples/resend-node/README.md +22 -22
  241. package/examples/stripe-node/README.md +35 -35
  242. package/examples/stripe-node/checkout-flow.mjs +87 -61
  243. package/examples/twilio-node/README.md +21 -21
  244. package/examples/worlds/README.md +19 -19
  245. package/examples/worlds/subscription-recovery.mjs +21 -12
  246. package/package.json +28 -6
  247. package/dist/landing/assets/index-BXR41fAD.css +0 -1
  248. package/dist/landing/assets/index-CxWsopzP.css +0 -1
  249. package/dist/landing/assets/index-D8_ggMRE.js +0 -55
  250. package/dist/landing/assets/index-DZlpyhqd.js +0 -55
  251. package/dist/landing/assets/index-Dk-Xezs3.js +0 -55
  252. package/dist/landing/index.html +0 -15
  253. package/dist/landing/landing.d.ts +0 -3
  254. package/dist/landing/landing.js +0 -12
  255. package/dist/landing/landing.js.map +0 -1
  256. package/docs/commercial/README.md +0 -29
  257. package/docs/commercial/data-inventory.md +0 -36
  258. package/docs/commercial/manual-invoicing.md +0 -44
  259. package/docs/commercial/metrics.md +0 -51
  260. package/docs/commercial/pricing.md +0 -103
  261. package/docs/commercial/privacy-policy-draft.md +0 -41
  262. package/docs/commercial/terms-topics-for-counsel.md +0 -51
  263. package/docs/design-partners/README.md +0 -52
  264. package/docs/design-partners/demo-narratives.md +0 -33
  265. package/docs/design-partners/design-partner-offer.md +0 -39
  266. package/docs/design-partners/discovery-questions.md +0 -28
  267. package/docs/design-partners/feedback-capture-template.md +0 -48
  268. package/docs/design-partners/icp-one-pager.md +0 -43
  269. package/docs/design-partners/onboarding-checklist.md +0 -33
  270. package/docs/design-partners/pilot-success-criteria.md +0 -27
  271. package/docs/design-partners/pricing-interview-script.md +0 -18
  272. package/docs/design-partners/telemetry-plan.md +0 -48
  273. package/docs/development/baseline.md +0 -114
  274. package/docs/development/onboarding-smoke.md +0 -37
  275. package/docs/development/verification-0.1.8.md +0 -25
  276. package/docs/enterprise-product-roadmap-ru.md +0 -1879
  277. package/docs/fundraising/README.md +0 -87
  278. package/docs/fundraising/data-room-checklist.md +0 -72
  279. package/docs/fundraising/demo-script.md +0 -52
  280. package/docs/fundraising/design-partners-50.md +0 -74
  281. package/docs/fundraising/launch-posts.md +0 -37
  282. package/docs/fundraising/metrics-and-evidence.md +0 -30
  283. package/docs/fundraising/roadmap-12-month.md +0 -25
  284. package/docs/fundraising/technical-due-diligence-index.md +0 -37
  285. package/docs/fundraising/yc-application.md +0 -25
  286. package/docs/hosted-pilot.md +0 -111
  287. package/docs/operations/disaster-recovery-runbook.md +0 -81
  288. package/docs/operations/kill-switch-runbook.md +0 -32
  289. package/docs/release-checklist.md +0 -83
  290. package/docs/release-migration-and-rollback.md +0 -63
  291. package/docs/release-readiness.md +0 -39
  292. package/docs/team-control-plane.md +0 -72
package/docs/policy.md CHANGED
@@ -1,61 +1,63 @@
1
- # Policy As Code
2
-
3
- GhostAPI reads one local, versioned YAML policy. It has no remote includes, environment-variable interpolation, templates, or executable expressions.
4
-
5
- Copy [`examples/policy/ghostapi.policy.yaml`](../examples/policy/ghostapi.policy.yaml) into a project as `ghostapi.policy.yaml`, then validate it:
6
-
7
- ```bash
8
- ghostapi policy validate
9
- ghostapi policy explain network api.stripe.com --provider stripe
10
- ghostapi policy explain stripe.card_declined
11
- ghostapi policy explain report 0 0 0
12
- ```
13
-
14
- `ghostapi run --policy ghostapi.policy.yaml -- <command>` loads and validates the file once before any namespace preflight or target spawn. The run evidence records only the policy SHA-256 and required scenario IDs, not policy file content or command arguments. Policy changes during a run do not reload or alter that run.
15
-
16
- `ghostapi evidence generate --policy ghostapi.policy.yaml --ci` evaluates required scenarios and report thresholds against the generated evidence artifact. Pass `--contract-baseline` and `--contract-candidate` to include contract drift. CI mode exits non-zero when required scenarios are missing, production-egress, forbidden-credential, or breaking-contract thresholds are exceeded, or other fail findings are present.
17
-
18
- ## Schema V1
19
-
20
- ```yaml
21
- version: 1
22
- network:
23
- default: deny
24
- allow:
25
- - host: localhost
26
- - provider: stripe
27
- deny:
28
- - host: api.stripe.com
29
- productionHosts:
30
- - '*.stripe.com'
31
- credentials:
32
- forbid:
33
- - sk_live_*
34
- requiredScenarios:
35
- - stripe-payment-intent-card-declined
36
- enforcement:
37
- allowedModes:
38
- - linux-network-namespace
39
- reports:
40
- maxProductionEgressAttempts: 0
41
- maxForbiddenCredentialMatches: 0
42
- maxBreakingContractChanges: 0
43
- ```
44
-
45
- - `network.default`: `allow` or `deny` when no rule matches.
46
- - `network.allow` and `network.deny`: rules contain exactly one `host` or `provider` field.
47
- - `network.productionHosts`: classifies hostnames for decision traces and CI/report evaluation.
48
- - `credentials.forbid`: bounded `*` globs matched against an explicit input; GhostAPI never expands environment variables in policy.
49
- - `requiredScenarios`: scenario IDs the evidence report must mark complete.
50
- - `enforcement.allowedModes`: currently `linux-network-namespace` or `proxy-guidance`.
51
- - `reports`: maximum allowed production-egress attempts, forbidden-credential matches, and breaking contract changes for a report decision. `maxBreakingContractChanges` defaults to `0` when omitted by an existing policy.
52
-
53
- ## Precedence And Limits
54
-
55
- For a network decision, a matching `network.deny` rule always wins over a matching `network.allow` rule. Otherwise `network.default` decides. `ghostapi policy explain` prints the selected rule and decision trace.
56
-
57
- Policies are limited to 128 KiB and list fields to 200 entries. Unknown fields, duplicate YAML keys, unsupported versions, anchors/aliases, interpolation syntax, path traversal, symlink policy files and multiple YAML documents are rejected with a path-aware error.
58
-
59
- ## Migration
60
-
61
- Schema versions are exact. GhostAPI does not coerce or silently upgrade an unknown version. A future version must add an explicit migration command that reads one known old version, emits a new file for review, and requires a separate validation step. It must never rewrite a policy while `ghostapi run` is active.
1
+ # Policy As Code
2
+
3
+ GhostAPI reads one local, versioned YAML policy. It has no remote includes, environment-variable interpolation, templates, or executable expressions.
4
+
5
+ Copy [`examples/policy/ghostapi.policy.yaml`](../examples/policy/ghostapi.policy.yaml) into a project as `ghostapi.policy.yaml`, then validate it:
6
+
7
+ ```bash
8
+ ghostapi policy validate
9
+ ghostapi policy explain network api.stripe.com --provider stripe
10
+ ghostapi policy explain stripe.card_declined
11
+ ghostapi policy explain report 0 0 0
12
+ ```
13
+
14
+ `ghostapi run --policy ghostapi.policy.yaml -- <command>` loads and validates the file once before any namespace preflight or target spawn. The run evidence records only the policy SHA-256 and required scenario IDs, not policy file content or command arguments. Policy changes during a run do not reload or alter that run.
15
+
16
+ `ghostapi evidence generate --policy ghostapi.policy.yaml --ci` evaluates required scenarios and report thresholds against the generated evidence artifact. Pass `--contract-baseline` and `--contract-candidate` to include contract drift. CI mode exits non-zero when required scenarios are missing, production-egress, forbidden-credential, or breaking-contract thresholds are exceeded, or other fail findings are present.
17
+
18
+ Schema-v1 network rules provide policy decisions and report classification; they do not configure a host firewall, intercept DNS, or transparently proxy arbitrary traffic. The current Linux launcher is loopback-only and rejects external allow-host requests.
19
+
20
+ ## Schema V1
21
+
22
+ ```yaml
23
+ version: 1
24
+ network:
25
+ default: deny
26
+ allow:
27
+ - host: localhost
28
+ - provider: stripe
29
+ deny:
30
+ - host: api.stripe.com
31
+ productionHosts:
32
+ - "*.stripe.com"
33
+ credentials:
34
+ forbid:
35
+ - sk_live_*
36
+ requiredScenarios:
37
+ - stripe-payment-intent-card-declined
38
+ enforcement:
39
+ allowedModes:
40
+ - linux-network-namespace
41
+ reports:
42
+ maxProductionEgressAttempts: 0
43
+ maxForbiddenCredentialMatches: 0
44
+ maxBreakingContractChanges: 0
45
+ ```
46
+
47
+ - `network.default`: `allow` or `deny` when no rule matches.
48
+ - `network.allow` and `network.deny`: rules contain exactly one `host` or `provider` field.
49
+ - `network.productionHosts`: classifies hostnames for decision traces and CI/report evaluation.
50
+ - `credentials.forbid`: bounded `*` globs matched against an explicit input; GhostAPI never expands environment variables in policy.
51
+ - `requiredScenarios`: scenario IDs the evidence report must mark complete.
52
+ - `enforcement.allowedModes`: currently `linux-network-namespace` or `proxy-guidance`.
53
+ - `reports`: maximum allowed production-egress attempts, forbidden-credential matches, and breaking contract changes for a report decision. `maxBreakingContractChanges` defaults to `0` when omitted by an existing policy.
54
+
55
+ ## Precedence And Limits
56
+
57
+ For a network decision, a matching `network.deny` rule always wins over a matching `network.allow` rule. Otherwise `network.default` decides. `ghostapi policy explain` prints the selected rule and decision trace.
58
+
59
+ Policies are limited to 128 KiB and list fields to 200 entries. Unknown fields, duplicate YAML keys, unsupported versions, anchors/aliases, interpolation syntax, path traversal, symlink policy files and multiple YAML documents are rejected with a path-aware error.
60
+
61
+ ## Migration
62
+
63
+ Schema versions are exact. GhostAPI does not coerce or silently upgrade an unknown version. A future version must add an explicit migration command that reads one known old version, emits a new file for review, and requires a separate validation step. It must never rewrite a policy while `ghostapi run` is active.
@@ -1,175 +1,180 @@
1
- # Authoring Provider Packs
2
-
3
- Provider packs are the versioned contract layer for provider-specific behavior in GhostAPI. Resend and Stripe are migrated built-in packs. Twilio, GitHub, Discord, and OpenAI remain on the legacy adapter path until they can be migrated in small reviewed changes. Generic REST remains the fallback.
4
-
5
- ## Scope And Trust Boundary
6
-
7
- Provider packs are built-in TypeScript modules compiled with GhostAPI. GhostAPI does not load uploaded, downloaded, or third-party executable provider code.
8
-
9
- A pack receives only explicit inputs:
10
-
11
- - detection receives a normalized path only;
12
- - parsing, validation, and handling receive the sanitized `NormalizedRequest`;
13
- - clock, ID generation, and a read-only state snapshot require explicit runtime capabilities;
14
- - no network, filesystem, environment, or secret capability is available to a pack.
15
-
16
- The source regression test rejects pack modules that import Node network/filesystem modules or access `process.env` or `fetch`. This is a maintenance boundary, not a secure JavaScript sandbox. Do not advertise arbitrary plugin isolation.
17
-
18
- ## Public Interfaces
19
-
20
- The stable authoring surface is exported from `src/index.ts`:
21
-
22
- - `ProviderPack`;
23
- - `ProviderPackManifest`;
24
- - `ProviderConformanceFixture`;
25
- - `ProviderRuntime` and `ProviderRuntimeCapabilities`;
26
- - `ProviderScenario` and `ProviderScenarioStep`;
27
- - `ProviderWebhookHook`;
28
- - `createProviderRuntime()`;
29
- - `runProviderPackConformance()`.
30
-
31
- The request pipeline, registry lookup, prepared execution object, response headers, state persistence, cache, Fault Lab, dashboard events, and scenario persistence are internal interfaces. Packs must not import stores or server modules directly.
32
-
33
- ## Required Contract
34
-
35
- Every pack declares:
36
-
37
- ```ts
38
- export const examplePack: ProviderPack = {
39
- name: "example",
40
- displayName: "Example",
41
- manifest: {
42
- schemaVersion: 1,
43
- name: "example",
44
- displayName: "Example",
45
- implementation: "pack",
46
- packVersion: "1.0.0",
47
- apiVersions: { default: "v1", supported: ["v1"] },
48
- capabilities: {
49
- detection: true,
50
- requestParsing: true,
51
- validation: true,
52
- deterministicResponses: true,
53
- stateTransitions: true,
54
- providerErrors: true,
55
- scenarios: false,
56
- webhooks: false,
57
- conformanceFixtures: true
58
- }
59
- },
60
- detection: { priority: 100, matches: ({ path }) => path.startsWith("/example") },
61
- parseRequest: (request) => request.body,
62
- selectApiVersion: () => ({ version: "v1" }),
63
- validate: () => null,
64
- handleDeterministic: ({ runtime }) => ({
65
- status: 200,
66
- headers: { "content-type": "application/json" },
67
- body: { id: runtime.requireCapability("idGenerator").create("example_mock") }
68
- }),
69
- createResponseHeaders: () => ({}),
70
- transitionState: () => null,
71
- stateful: false,
72
- formatError: (details) => ({ error: { message: details.message } }),
73
- promptHints: [],
74
- scenarios: [],
75
- conformanceFixtures: []
76
- };
77
- ```
78
-
79
- The manifest is returned by `GET /api/providers`, shown in dashboard provider filters, and printed by `ghostapi providers list` and `ghostapi providers inspect <name>`.
80
-
81
- ## API Version Selection
82
-
83
- Pack API versions are GhostAPI compatibility versions, not an automatic claim of full parity with a provider's live API. A pack must:
84
-
85
- 1. declare one default version and all supported versions;
86
- 2. select a version before request validation;
87
- 3. return a provider-shaped `ProviderErrorDetails` for unsupported explicit versions;
88
- 4. include version-sensitive request headers in cache identity;
89
- 5. change `packVersion` when pack behavior changes and add a new API version when the simulated contract changes incompatibly.
90
-
91
- The Resend pack accepts `x-ghostapi-api-version: v1`. Successful responses include:
92
-
93
- ```text
94
- x-ghostapi-provider-pack: resend@1.0.0
95
- x-ghostapi-api-version: v1
96
- ```
97
-
98
- ## Determinism
99
-
100
- Do not call `Date.now()`, `new Date()`, random generators, environment variables, or external services inside a pack. Request runtime capabilities explicitly:
101
-
102
- ```ts
103
- const now = runtime.requireCapability("clock").now();
104
- const id = runtime.requireCapability("idGenerator").create("item_mock");
105
- ```
106
-
107
- Tests must inject fixed implementations with `createProviderRuntime()`. `createResponseHeaders()` can add deterministic provider headers such as Stripe request IDs to successful or early-error responses. Asking for an undeclared capability fails with `Unknown provider capability: <name>`.
108
-
109
- ## Validation And Errors
110
-
111
- `parseRequest()` converts the sanitized normalized request into the provider's internal request shape. `validate()` returns `null` or `ProviderErrorDetails`. Core formats the details through the registered provider error formatter.
112
-
113
- Keep validation order stable when migrating a public route. Error status, field names, messages, and provider shape are observable behavior.
114
-
115
- ## State Transitions
116
-
117
- `transitionState()` describes persistence but does not write it. Core owns storage and requires keys to stay in the exact `<provider>:<id>` namespace. A pack that declares `stateful: true` executes under one atomic local-state transaction and can inspect the injected read-only snapshot while deciding its response. It still cannot access a store directly.
118
-
119
- A transition must be derived from the handled response and must not read ambient state. The conformance fixture should assert both the key and value. Core rejects cross-provider or empty keys before persistence.
120
-
121
- ## Scenarios And Webhooks
122
-
123
- Pack scenarios use the shared `ProviderScenario` shape and are merged into the existing scenario registry. Scenario replay still installs deterministic method/path behaviors and runs before faults, validation, state, cache, and generation.
124
-
125
- `ProviderWebhookHook` is part of the authoring vocabulary, but no built-in pack currently advertises webhook capability. Do not set `webhooks: true` until event synthesis, signing, delivery timing, retries, and failure semantics have tests.
126
-
127
- ## Conformance Fixtures
128
-
129
- Every migrated pack must provide at least one fixture that exercises its main mutation or read flow. Run it through the common harness:
130
-
131
- ```ts
132
- const runtime = createProviderRuntime({
133
- clock: { now: () => new Date("2026-08-06T12:00:00.000Z") },
134
- idGenerator: { create: (prefix) => `${prefix}_fixture` }
135
- });
136
-
137
- runProviderPackConformance(examplePack, runtime);
138
- ```
139
-
140
- The harness:
141
-
142
- 1. selects an API version;
143
- 2. parses and validates the fixture request;
144
- 3. generates a deterministic response;
145
- 4. runs the fixture response assertion;
146
- 5. computes and validates the state transition;
147
- 6. runs the fixture transition assertion.
148
-
149
- Malformed responses and wrong state keys must fail the harness.
150
-
151
- ## Adding Or Migrating A Pack
152
-
153
- 1. Add one pack under `src/providers/packs/`.
154
- 2. Register it in the ordered built-in pack list in `src/providers/registry.ts`.
155
- 3. Remove only that provider's legacy detection, validation, generation, prompt, and scenario branches.
156
- 4. Preserve route detection precedence and generic REST fallback.
157
- 5. Add conformance, provider regression, manifest API, state, cache, and provider-shaped error tests.
158
- 6. Run `npm run typecheck`, `npm test`, and `npm run build`.
159
- 7. Inspect built CLI output and package contents before release.
160
-
161
- ## Migration Plan
162
-
163
- The remaining providers should move one at a time:
164
-
165
- | Order | Provider | Migration focus | Deferred risk |
166
- | --- | --- | --- | --- |
167
- | 1 | Twilio | Form parsing, validation, SID generation, error shape | Message status transitions and callbacks |
168
- | 2 | GitHub | Version header, deterministic issue/repository shapes, scenarios | Pagination and conditional requests |
169
- | 3 | OpenAI | API version policy, typed response families, list state | Streaming and token accounting |
170
- | 4 | Discord | Route/body detection and message shapes | Webhook and interaction semantics |
171
- | Done | Stripe | Core pack for customers, payment intents, payment methods, checkout sessions, refunds, pagination, and idempotency | Webhooks, subscriptions, invoices, disputes, and broader state-machine parity |
172
-
173
- Stripe now demonstrates the deeper stateful pack path. See [`stripe-core-pack.md`](stripe-core-pack.md) for the supported contract and limits.
174
-
175
- Generic REST should not become a provider pack. It remains the explicit fallback so unknown APIs continue to work without pretending to have a provider contract.
1
+ # Authoring Provider Packs
2
+
3
+ Provider packs are the versioned contract layer for provider-specific behavior in GhostAPI. Resend and Stripe are migrated built-in packs. Twilio, GitHub, Discord, and OpenAI remain on the legacy adapter path until they can be migrated in small reviewed changes. Generic REST remains the fallback.
4
+
5
+ ## Scope And Trust Boundary
6
+
7
+ Provider packs are built-in TypeScript modules compiled with GhostAPI. GhostAPI does not load uploaded, downloaded, or third-party executable provider code.
8
+
9
+ A pack receives only explicit inputs:
10
+
11
+ - detection receives a normalized path only;
12
+ - parsing, validation, and handling receive the sanitized `NormalizedRequest`;
13
+ - clock, ID generation, and a read-only state snapshot require explicit runtime capabilities;
14
+ - no network, filesystem, environment, or secret capability is available to a pack.
15
+
16
+ The source regression test rejects pack modules that import Node network/filesystem modules or access `process.env` or `fetch`. This is a maintenance boundary, not a secure JavaScript sandbox. Do not advertise arbitrary plugin isolation.
17
+
18
+ ## Public Interfaces
19
+
20
+ The stable authoring surface is exported from `src/index.ts`:
21
+
22
+ - `ProviderPack`;
23
+ - `ProviderPackManifest`;
24
+ - `ProviderConformanceFixture`;
25
+ - `ProviderRuntime` and `ProviderRuntimeCapabilities`;
26
+ - `ProviderScenario` and `ProviderScenarioStep`;
27
+ - `ProviderWebhookHook`;
28
+ - `createProviderRuntime()`;
29
+ - `runProviderPackConformance()`.
30
+
31
+ The request pipeline, registry lookup, prepared execution object, response headers, state persistence, cache, Fault Lab, dashboard events, and scenario persistence are internal interfaces. Packs must not import stores or server modules directly.
32
+
33
+ ## Required Contract
34
+
35
+ Every pack declares:
36
+
37
+ ```ts
38
+ export const examplePack: ProviderPack = {
39
+ name: "example",
40
+ displayName: "Example",
41
+ manifest: {
42
+ schemaVersion: 1,
43
+ name: "example",
44
+ displayName: "Example",
45
+ implementation: "pack",
46
+ packVersion: "1.0.0",
47
+ apiVersions: { default: "v1", supported: ["v1"] },
48
+ capabilities: {
49
+ detection: true,
50
+ requestParsing: true,
51
+ validation: true,
52
+ deterministicResponses: true,
53
+ stateTransitions: true,
54
+ providerErrors: true,
55
+ scenarios: false,
56
+ webhooks: false,
57
+ conformanceFixtures: true,
58
+ },
59
+ },
60
+ detection: {
61
+ priority: 100,
62
+ matches: ({ path }) => path.startsWith("/example"),
63
+ },
64
+ parseRequest: (request) => request.body,
65
+ selectApiVersion: () => ({ version: "v1" }),
66
+ validate: () => null,
67
+ handleDeterministic: ({ runtime }) => ({
68
+ status: 200,
69
+ headers: { "content-type": "application/json" },
70
+ body: {
71
+ id: runtime.requireCapability("idGenerator").create("example_mock"),
72
+ },
73
+ }),
74
+ createResponseHeaders: () => ({}),
75
+ transitionState: () => null,
76
+ stateful: false,
77
+ formatError: (details) => ({ error: { message: details.message } }),
78
+ promptHints: [],
79
+ scenarios: [],
80
+ conformanceFixtures: [],
81
+ };
82
+ ```
83
+
84
+ The manifest is returned by `GET /api/providers`, shown in dashboard provider filters, and printed by `ghostapi providers list` and `ghostapi providers inspect <name>`.
85
+
86
+ ## API Version Selection
87
+
88
+ Pack API versions are GhostAPI compatibility versions, not an automatic claim of full parity with a provider's live API. A pack must:
89
+
90
+ 1. declare one default version and all supported versions;
91
+ 2. select a version before request validation;
92
+ 3. return a provider-shaped `ProviderErrorDetails` for unsupported explicit versions;
93
+ 4. include version-sensitive request headers in cache identity;
94
+ 5. change `packVersion` when pack behavior changes and add a new API version when the simulated contract changes incompatibly.
95
+
96
+ The Resend pack accepts `x-ghostapi-api-version: v1`. Successful responses include:
97
+
98
+ ```text
99
+ x-ghostapi-provider-pack: resend@1.0.0
100
+ x-ghostapi-api-version: v1
101
+ ```
102
+
103
+ ## Determinism
104
+
105
+ Do not call `Date.now()`, `new Date()`, random generators, environment variables, or external services inside a pack. Request runtime capabilities explicitly:
106
+
107
+ ```ts
108
+ const now = runtime.requireCapability("clock").now();
109
+ const id = runtime.requireCapability("idGenerator").create("item_mock");
110
+ ```
111
+
112
+ Tests must inject fixed implementations with `createProviderRuntime()`. `createResponseHeaders()` can add deterministic provider headers such as Stripe request IDs to successful or early-error responses. Asking for an undeclared capability fails with `Unknown provider capability: <name>`.
113
+
114
+ ## Validation And Errors
115
+
116
+ `parseRequest()` converts the sanitized normalized request into the provider's internal request shape. `validate()` returns `null` or `ProviderErrorDetails`. Core formats the details through the registered provider error formatter.
117
+
118
+ Keep validation order stable when migrating a public route. Error status, field names, messages, and provider shape are observable behavior.
119
+
120
+ ## State Transitions
121
+
122
+ `transitionState()` describes persistence but does not write it. Core owns storage and requires keys to stay in the exact `<provider>:<id>` namespace. A pack that declares `stateful: true` executes under one atomic local-state transaction and can inspect the injected read-only snapshot while deciding its response. It still cannot access a store directly.
123
+
124
+ A transition must be derived from the handled response and must not read ambient state. The conformance fixture should assert both the key and value. Core rejects cross-provider or empty keys before persistence.
125
+
126
+ ## Scenarios And Webhooks
127
+
128
+ Pack scenarios use the shared `ProviderScenario` shape and are merged into the existing scenario registry. Scenario replay still installs deterministic method/path behaviors and runs before faults, validation, state, cache, and generation.
129
+
130
+ `ProviderWebhookHook` is part of the authoring vocabulary, but no built-in pack currently advertises webhook capability. Do not set `webhooks: true` until event synthesis, signing, delivery timing, retries, and failure semantics have tests.
131
+
132
+ ## Conformance Fixtures
133
+
134
+ Every migrated pack must provide at least one fixture that exercises its main mutation or read flow. Run it through the common harness:
135
+
136
+ ```ts
137
+ const runtime = createProviderRuntime({
138
+ clock: { now: () => new Date("2026-08-06T12:00:00.000Z") },
139
+ idGenerator: { create: (prefix) => `${prefix}_fixture` },
140
+ });
141
+
142
+ runProviderPackConformance(examplePack, runtime);
143
+ ```
144
+
145
+ The harness:
146
+
147
+ 1. selects an API version;
148
+ 2. parses and validates the fixture request;
149
+ 3. generates a deterministic response;
150
+ 4. runs the fixture response assertion;
151
+ 5. computes and validates the state transition;
152
+ 6. runs the fixture transition assertion.
153
+
154
+ Malformed responses and wrong state keys must fail the harness.
155
+
156
+ ## Adding Or Migrating A Pack
157
+
158
+ 1. Add one pack under `src/providers/packs/`.
159
+ 2. Register it in the ordered built-in pack list in `src/providers/registry.ts`.
160
+ 3. Remove only that provider's legacy detection, validation, generation, prompt, and scenario branches.
161
+ 4. Preserve route detection precedence and generic REST fallback.
162
+ 5. Add conformance, provider regression, manifest API, state, cache, and provider-shaped error tests.
163
+ 6. Run `npm run typecheck`, `npm test`, and `npm run build`.
164
+ 7. Inspect built CLI output and package contents before release.
165
+
166
+ ## Migration Plan
167
+
168
+ The remaining providers should move one at a time:
169
+
170
+ | Order | Provider | Migration focus | Deferred risk |
171
+ | ----- | -------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
172
+ | 1 | Twilio | Form parsing, validation, SID generation, error shape | Message status transitions and callbacks |
173
+ | 2 | GitHub | Version header, deterministic issue/repository shapes, scenarios | Pagination and conditional requests |
174
+ | 3 | OpenAI | API version policy, typed response families, list state | Streaming and token accounting |
175
+ | 4 | Discord | Route/body detection and message shapes | Webhook and interaction semantics |
176
+ | Done | Stripe | Core pack for customers, payment intents, payment methods, checkout sessions, refunds, pagination, and idempotency | Webhooks, subscriptions, invoices, disputes, and broader state-machine parity |
177
+
178
+ Stripe now demonstrates the deeper stateful pack path. See [`stripe-core-pack.md`](stripe-core-pack.md) for the supported contract and limits.
179
+
180
+ Generic REST should not become a provider pack. It remains the explicit fallback so unknown APIs continue to work without pretending to have a provider contract.