@yiaany/ghostapi 0.1.8 → 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 (293) 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 -80
  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 +67 -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/assets/ghostapi-avatar.png +0 -0
  206. package/docs/ci.md +49 -49
  207. package/docs/github-actions.md +84 -84
  208. package/docs/mcp.md +58 -52
  209. package/docs/policy.md +63 -61
  210. package/docs/providers/authoring-packs.md +180 -175
  211. package/docs/providers/stripe-core-pack.md +84 -82
  212. package/docs/releases/README.md +13 -0
  213. package/docs/security/action-gateway-threat-model.md +34 -34
  214. package/docs/security/action-ledger-incident-replay-threat-model.md +42 -42
  215. package/docs/security/approval-inbox-threat-model.md +35 -35
  216. package/docs/security/credential-broker-threat-model.md +52 -52
  217. package/docs/security/egress-threat-model.md +126 -126
  218. package/docs/security/inventory-threat-model.md +104 -104
  219. package/docs/security/kill-switch-budgets-threat-model.md +37 -37
  220. package/docs/security/reliability-threat-model.md +111 -111
  221. package/docs/security/trust-ladder-threat-model.md +33 -33
  222. package/docs/telemetry.md +14 -0
  223. package/docs/usage.md +680 -571
  224. package/examples/README.md +10 -10
  225. package/examples/agent-instructions/README.md +39 -39
  226. package/examples/ci-smoke/README.md +21 -21
  227. package/examples/ci-smoke/ghostapi.policy.yaml +22 -22
  228. package/examples/ci-smoke/package.json +9 -9
  229. package/examples/ci-smoke/production-egress.mjs +4 -2
  230. package/examples/ci-smoke/safe.mjs +21 -17
  231. package/examples/evals/README.md +24 -24
  232. package/examples/evals/retry-after.eval.json +71 -52
  233. package/examples/generic-rest/README.md +27 -27
  234. package/examples/github-fetch/README.md +38 -35
  235. package/examples/openai-streaming/README.md +16 -16
  236. package/examples/openai-streaming/streaming-tool-call.mjs +44 -31
  237. package/examples/policy/ghostapi.policy.yaml +27 -27
  238. package/examples/record-replay/README.md +19 -19
  239. package/examples/record-replay/replay-requests.json +22 -22
  240. package/examples/record-replay/stripe-checkout.har.json +30 -30
  241. package/examples/resend-node/README.md +22 -22
  242. package/examples/stripe-node/README.md +35 -35
  243. package/examples/stripe-node/checkout-flow.mjs +87 -61
  244. package/examples/twilio-node/README.md +21 -21
  245. package/examples/worlds/README.md +19 -19
  246. package/examples/worlds/subscription-recovery.mjs +21 -12
  247. package/package.json +28 -6
  248. package/dist/landing/assets/index-BXR41fAD.css +0 -1
  249. package/dist/landing/assets/index-CxWsopzP.css +0 -1
  250. package/dist/landing/assets/index-D8_ggMRE.js +0 -55
  251. package/dist/landing/assets/index-DZlpyhqd.js +0 -55
  252. package/dist/landing/assets/index-Dk-Xezs3.js +0 -55
  253. package/dist/landing/index.html +0 -15
  254. package/dist/landing/landing.d.ts +0 -3
  255. package/dist/landing/landing.js +0 -12
  256. package/dist/landing/landing.js.map +0 -1
  257. package/docs/commercial/README.md +0 -29
  258. package/docs/commercial/data-inventory.md +0 -36
  259. package/docs/commercial/manual-invoicing.md +0 -44
  260. package/docs/commercial/metrics.md +0 -51
  261. package/docs/commercial/pricing.md +0 -103
  262. package/docs/commercial/privacy-policy-draft.md +0 -41
  263. package/docs/commercial/terms-topics-for-counsel.md +0 -51
  264. package/docs/design-partners/README.md +0 -52
  265. package/docs/design-partners/demo-narratives.md +0 -33
  266. package/docs/design-partners/design-partner-offer.md +0 -39
  267. package/docs/design-partners/discovery-questions.md +0 -28
  268. package/docs/design-partners/feedback-capture-template.md +0 -48
  269. package/docs/design-partners/icp-one-pager.md +0 -43
  270. package/docs/design-partners/onboarding-checklist.md +0 -33
  271. package/docs/design-partners/pilot-success-criteria.md +0 -27
  272. package/docs/design-partners/pricing-interview-script.md +0 -18
  273. package/docs/design-partners/telemetry-plan.md +0 -48
  274. package/docs/development/baseline.md +0 -114
  275. package/docs/development/onboarding-smoke.md +0 -37
  276. package/docs/development/verification-0.1.8.md +0 -25
  277. package/docs/enterprise-product-roadmap-ru.md +0 -1879
  278. package/docs/fundraising/README.md +0 -87
  279. package/docs/fundraising/data-room-checklist.md +0 -72
  280. package/docs/fundraising/demo-script.md +0 -52
  281. package/docs/fundraising/design-partners-50.md +0 -74
  282. package/docs/fundraising/launch-posts.md +0 -37
  283. package/docs/fundraising/metrics-and-evidence.md +0 -30
  284. package/docs/fundraising/roadmap-12-month.md +0 -25
  285. package/docs/fundraising/technical-due-diligence-index.md +0 -37
  286. package/docs/fundraising/yc-application.md +0 -25
  287. package/docs/hosted-pilot.md +0 -111
  288. package/docs/operations/disaster-recovery-runbook.md +0 -81
  289. package/docs/operations/kill-switch-runbook.md +0 -32
  290. package/docs/release-checklist.md +0 -83
  291. package/docs/release-migration-and-rollback.md +0 -63
  292. package/docs/release-readiness.md +0 -39
  293. package/docs/team-control-plane.md +0 -72
@@ -1,31 +1,44 @@
1
- const baseUrl = process.env.GHOSTAPI_OPENAI_BASE_URL ?? "http://127.0.0.1:8080/v1";
2
-
3
- const response = await fetch(`${baseUrl}/chat/completions`, {
4
- method: "POST",
5
- headers: {
6
- "content-type": "application/json",
7
- authorization: `Bearer ${process.env.OPENAI_API_KEY ?? "sk-ghostapi"}`
8
- },
9
- body: JSON.stringify({
10
- model: "gpt-4o-mini",
11
- stream: true,
12
- messages: [{ role: "user", content: "Return a local weather tool call for Berlin." }],
13
- tools: [
14
- {
15
- type: "function",
16
- function: {
17
- name: "get_weather",
18
- description: "Return local test weather.",
19
- parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] }
20
- }
21
- }
22
- ]
23
- })
24
- });
25
-
26
- if (!response.ok) throw new Error(`GhostAPI OpenAI request failed: ${response.status} ${await response.text()}`);
27
-
28
- const text = await response.text();
29
- if (!text.includes("[DONE]")) throw new Error("Expected a local streaming completion terminator.");
30
-
31
- console.log("OpenAI streaming/tool-call starter completed against local GhostAPI.");
1
+ const baseUrl =
2
+ process.env.GHOSTAPI_OPENAI_BASE_URL ?? "http://127.0.0.1:8080/v1";
3
+
4
+ const response = await fetch(`${baseUrl}/chat/completions`, {
5
+ method: "POST",
6
+ headers: {
7
+ "content-type": "application/json",
8
+ authorization: `Bearer ${process.env.OPENAI_API_KEY ?? "sk-ghostapi"}`,
9
+ },
10
+ body: JSON.stringify({
11
+ model: "gpt-4o-mini",
12
+ stream: true,
13
+ messages: [
14
+ { role: "user", content: "Return a local weather tool call for Berlin." },
15
+ ],
16
+ tools: [
17
+ {
18
+ type: "function",
19
+ function: {
20
+ name: "get_weather",
21
+ description: "Return local test weather.",
22
+ parameters: {
23
+ type: "object",
24
+ properties: { city: { type: "string" } },
25
+ required: ["city"],
26
+ },
27
+ },
28
+ },
29
+ ],
30
+ }),
31
+ });
32
+
33
+ if (!response.ok)
34
+ throw new Error(
35
+ `GhostAPI OpenAI request failed: ${response.status} ${await response.text()}`,
36
+ );
37
+
38
+ const text = await response.text();
39
+ if (!text.includes("[DONE]"))
40
+ throw new Error("Expected a local streaming completion terminator.");
41
+
42
+ console.log(
43
+ "OpenAI streaming/tool-call starter completed against local GhostAPI.",
44
+ );
@@ -1,27 +1,27 @@
1
- version: 1
2
- network:
3
- default: deny
4
- allow:
5
- - host: localhost
6
- - host: 127.0.0.1
7
- deny:
8
- - host: api.stripe.com
9
- - host: api.openai.com
10
- productionHosts:
11
- - '*.stripe.com'
12
- - '*.openai.com'
13
- credentials:
14
- forbid:
15
- - sk_live_*
16
- - rk_live_*
17
- - ghp_*
18
- requiredScenarios:
19
- - stripe-payment-intent-card-declined
20
- - stripe-subscription-payment-failed
21
- enforcement:
22
- allowedModes:
23
- - linux-network-namespace
24
- reports:
25
- maxProductionEgressAttempts: 0
26
- maxForbiddenCredentialMatches: 0
27
- maxBreakingContractChanges: 0
1
+ version: 1
2
+ network:
3
+ default: deny
4
+ allow:
5
+ - host: localhost
6
+ - host: 127.0.0.1
7
+ deny:
8
+ - host: api.stripe.com
9
+ - host: api.openai.com
10
+ productionHosts:
11
+ - "*.stripe.com"
12
+ - "*.openai.com"
13
+ credentials:
14
+ forbid:
15
+ - sk_live_*
16
+ - rk_live_*
17
+ - ghp_*
18
+ requiredScenarios:
19
+ - stripe-payment-intent-card-declined
20
+ - stripe-subscription-payment-failed
21
+ enforcement:
22
+ allowedModes:
23
+ - linux-network-namespace
24
+ reports:
25
+ maxProductionEgressAttempts: 0
26
+ maxForbiddenCredentialMatches: 0
27
+ maxBreakingContractChanges: 0
@@ -1,19 +1,19 @@
1
- # Record/Replay Starter
2
-
3
- This starter uses a tiny sanitized HAR fixture and a matching request file. It demonstrates the workflow without a live provider key.
4
-
5
- ```bash
6
- npx @yiaany/ghostapi record \
7
- --input examples/record-replay/stripe-checkout.har.json \
8
- --allow-sandbox-host api.stripe.com \
9
- --out .ghostapi/scenarios/stripe-checkout.bundle.json \
10
- --title "Starter checkout" \
11
- --approve
12
-
13
- npx @yiaany/ghostapi replay \
14
- .ghostapi/scenarios/stripe-checkout.bundle.json \
15
- --requests examples/record-replay/replay-requests.json \
16
- --json
17
- ```
18
-
19
- The fixture uses a fake `sk_test_...` key marker; do not record production traffic.
1
+ # Record/Replay Starter
2
+
3
+ This starter uses a tiny sanitized HAR fixture and a matching request file. It demonstrates the workflow without a live provider key.
4
+
5
+ ```bash
6
+ npx @yiaany/ghostapi record \
7
+ --input examples/record-replay/stripe-checkout.har.json \
8
+ --allow-sandbox-host api.stripe.com \
9
+ --out .ghostapi/scenarios/stripe-checkout.bundle.json \
10
+ --title "Starter checkout" \
11
+ --approve
12
+
13
+ npx @yiaany/ghostapi replay \
14
+ .ghostapi/scenarios/stripe-checkout.bundle.json \
15
+ --requests examples/record-replay/replay-requests.json \
16
+ --json
17
+ ```
18
+
19
+ The fixture uses a fake `sk_test_...` key marker; do not record production traffic.
@@ -1,22 +1,22 @@
1
- [
2
- {
3
- "method": "POST",
4
- "path": "/v1/checkout/sessions",
5
- "headers": { "content-type": "application/json" },
6
- "body": {
7
- "mode": "payment",
8
- "success_url": "https://sandbox.example/success",
9
- "cancel_url": "https://sandbox.example/cancel",
10
- "line_items": [
11
- {
12
- "quantity": 1,
13
- "price_data": {
14
- "currency": "usd",
15
- "unit_amount": 2400,
16
- "product_data": { "name": "Starter" }
17
- }
18
- }
19
- ]
20
- }
21
- }
22
- ]
1
+ [
2
+ {
3
+ "method": "POST",
4
+ "path": "/v1/checkout/sessions",
5
+ "headers": { "content-type": "application/json" },
6
+ "body": {
7
+ "mode": "payment",
8
+ "success_url": "https://sandbox.example/success",
9
+ "cancel_url": "https://sandbox.example/cancel",
10
+ "line_items": [
11
+ {
12
+ "quantity": 1,
13
+ "price_data": {
14
+ "currency": "usd",
15
+ "unit_amount": 2400,
16
+ "product_data": { "name": "Starter" }
17
+ }
18
+ }
19
+ ]
20
+ }
21
+ }
22
+ ]
@@ -1,30 +1,30 @@
1
- {
2
- "log": {
3
- "version": "1.2",
4
- "creator": { "name": "ghostapi-starter", "version": "1.0" },
5
- "entries": [
6
- {
7
- "request": {
8
- "method": "POST",
9
- "url": "https://api.stripe.com/v1/checkout/sessions",
10
- "headers": [
11
- { "name": "authorization", "value": "Bearer sk_test_ghostapi" },
12
- { "name": "content-type", "value": "application/json" }
13
- ],
14
- "postData": {
15
- "mimeType": "application/json",
16
- "text": "{\"mode\":\"payment\",\"success_url\":\"https://sandbox.example/success\",\"cancel_url\":\"https://sandbox.example/cancel\",\"line_items\":[{\"quantity\":1,\"price_data\":{\"currency\":\"usd\",\"unit_amount\":2400,\"product_data\":{\"name\":\"Starter\"}}}]}"
17
- }
18
- },
19
- "response": {
20
- "status": 200,
21
- "headers": [{ "name": "content-type", "value": "application/json" }],
22
- "content": {
23
- "mimeType": "application/json",
24
- "text": "{\"id\":\"cs_test_starter\",\"object\":\"checkout.session\",\"mode\":\"payment\",\"livemode\":false,\"url\":\"http://127.0.0.1:8080/checkout/cs_test_starter\"}"
25
- }
26
- }
27
- }
28
- ]
29
- }
30
- }
1
+ {
2
+ "log": {
3
+ "version": "1.2",
4
+ "creator": { "name": "ghostapi-starter", "version": "1.0" },
5
+ "entries": [
6
+ {
7
+ "request": {
8
+ "method": "POST",
9
+ "url": "https://api.stripe.com/v1/checkout/sessions",
10
+ "headers": [
11
+ { "name": "authorization", "value": "Bearer sk_test_ghostapi" },
12
+ { "name": "content-type", "value": "application/json" }
13
+ ],
14
+ "postData": {
15
+ "mimeType": "application/json",
16
+ "text": "{\"mode\":\"payment\",\"success_url\":\"https://sandbox.example/success\",\"cancel_url\":\"https://sandbox.example/cancel\",\"line_items\":[{\"quantity\":1,\"price_data\":{\"currency\":\"usd\",\"unit_amount\":2400,\"product_data\":{\"name\":\"Starter\"}}}]}"
17
+ }
18
+ },
19
+ "response": {
20
+ "status": 200,
21
+ "headers": [{ "name": "content-type", "value": "application/json" }],
22
+ "content": {
23
+ "mimeType": "application/json",
24
+ "text": "{\"id\":\"cs_test_starter\",\"object\":\"checkout.session\",\"mode\":\"payment\",\"livemode\":false,\"url\":\"http://127.0.0.1:8080/checkout/cs_test_starter\"}"
25
+ }
26
+ }
27
+ }
28
+ ]
29
+ }
30
+ }
@@ -1,22 +1,22 @@
1
- # Resend Node Example
2
-
3
- Send a Resend-like email through GhostAPI. This does not send a real email.
4
-
5
- ## Run
6
-
7
- Start GhostAPI:
8
-
9
- ```bash
10
- ghostapi start
11
- ```
12
-
13
- Send an email:
14
-
15
- ```bash
16
- curl -X POST http://localhost:8080/emails \
17
- -H "content-type: application/json" \
18
- -H "authorization: Bearer re_local_only" \
19
- -d '{"from":"onboarding@example.com","to":"ada@example.com","subject":"Welcome","html":"<p>Hello from GhostAPI</p>"}'
20
- ```
21
-
22
- GhostAPI detects Resend from `/emails` and returns a local mock email response.
1
+ # Resend Node Example
2
+
3
+ Send a Resend-like email through GhostAPI. This does not send a real email.
4
+
5
+ ## Run
6
+
7
+ Start GhostAPI:
8
+
9
+ ```bash
10
+ ghostapi start
11
+ ```
12
+
13
+ Send an email:
14
+
15
+ ```bash
16
+ curl -X POST http://localhost:8080/emails \
17
+ -H "content-type: application/json" \
18
+ -H "authorization: Bearer re_local_only" \
19
+ -d '{"from":"onboarding@example.com","to":"ada@example.com","subject":"Welcome","html":"<p>Hello from GhostAPI</p>"}'
20
+ ```
21
+
22
+ GhostAPI detects Resend from `/emails` and returns a local mock email response.
@@ -1,35 +1,35 @@
1
- # Stripe Node Subscription Flow
2
-
3
- Run the official Stripe Node SDK against GhostAPI without patching SDK source. This example only talks to `127.0.0.1`; it does not call Stripe.
4
-
5
- ## Run
6
-
7
- Start GhostAPI:
8
-
9
- ```bash
10
- ghostapi start
11
- ```
12
-
13
- Install the SDK once in this example directory:
14
-
15
- ```bash
16
- npm install stripe
17
- ```
18
-
19
- Run the subscription flow:
20
-
21
- ```bash
22
- node checkout-flow.mjs
23
- ```
24
-
25
- The script creates a customer, product, recurring price, and trial subscription; activates the local renewal control; then verifies the signed `invoice.payment_succeeded` payload with the official Stripe SDK. `delivery_mode=duplicate` deliberately returns the same event again so application-level de-duplication can be tested.
26
-
27
- The pack accepts SDK-style `application/x-www-form-urlencoded` requests and JSON requests used by direct HTTP clients. It uses Stripe API version `2026-02-25.clover`. Webhook deliveries are pull-based local test endpoints, so this example never asks GhostAPI to send an outbound request.
28
-
29
- To inspect the generated state:
30
-
31
- ```bash
32
- curl http://127.0.0.1:8080/v1/payment_intents?limit=10
33
- ```
34
-
35
- See [`docs/providers/stripe-core-pack.md`](../../docs/providers/stripe-core-pack.md) for supported operations and deliberate limits.
1
+ # Stripe Node Subscription Flow
2
+
3
+ Run the official Stripe Node SDK against GhostAPI without patching SDK source. This example only talks to `127.0.0.1`; it does not call Stripe.
4
+
5
+ ## Run
6
+
7
+ Start GhostAPI:
8
+
9
+ ```bash
10
+ ghostapi start
11
+ ```
12
+
13
+ Install the SDK once in this example directory:
14
+
15
+ ```bash
16
+ npm install stripe
17
+ ```
18
+
19
+ Run the subscription flow:
20
+
21
+ ```bash
22
+ node checkout-flow.mjs
23
+ ```
24
+
25
+ The script creates a customer, product, recurring price, and trial subscription; activates the local renewal control; then verifies the signed `invoice.payment_succeeded` payload with the official Stripe SDK. `delivery_mode=duplicate` deliberately returns the same event again so application-level de-duplication can be tested.
26
+
27
+ The pack accepts SDK-style `application/x-www-form-urlencoded` requests and JSON requests used by direct HTTP clients. It uses Stripe API version `2026-02-25.clover`. Webhook deliveries are pull-based local test endpoints, so this example never asks GhostAPI to send an outbound request.
28
+
29
+ To inspect the generated state:
30
+
31
+ ```bash
32
+ curl http://127.0.0.1:8080/v1/payment_intents?limit=10
33
+ ```
34
+
35
+ See [`docs/providers/stripe-core-pack.md`](../../docs/providers/stripe-core-pack.md) for supported operations and deliberate limits.
@@ -1,61 +1,87 @@
1
- import Stripe from "stripe";
2
-
3
- const host = process.env.GHOSTAPI_HOST ?? "127.0.0.1";
4
- const port = Number(process.env.GHOSTAPI_PORT ?? "8080");
5
- const protocol = process.env.GHOSTAPI_PROTOCOL ?? "http";
6
- const baseUrl = `${protocol}://${host}:${port}`;
7
- const webhookSecret = process.env.GHOSTAPI_STRIPE_WEBHOOK_SECRET ?? "whsec_ghostapi_local_test_secret";
8
-
9
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? "sk_test_ghostapi_local_only", {
10
- host,
11
- port,
12
- protocol,
13
- apiVersion: "2026-02-25.clover"
14
- });
15
-
16
- const customer = await stripe.customers.create({
17
- email: "ada@example.com",
18
- name: "Ada Lovelace",
19
- metadata: { example: "ghostapi-subscription-flow" }
20
- });
21
-
22
- const product = await stripe.products.create({ name: "GhostAPI Pro" });
23
- const price = await stripe.prices.create({
24
- product: product.id,
25
- currency: "usd",
26
- unit_amount: 2500,
27
- recurring: { interval: "month" }
28
- });
29
-
30
- const subscription = await stripe.subscriptions.create({
31
- customer: customer.id,
32
- items: [{ price: price.id }],
33
- trial_period_days: 7
34
- });
35
-
36
- // The renewal action is a GhostAPI local test control, not a live Stripe endpoint.
37
- const renewalResponse = await fetch(`${baseUrl}/v1/subscriptions/${subscription.id}/renew`, {
38
- method: "POST",
39
- headers: { "content-type": "application/json" },
40
- body: JSON.stringify({})
41
- });
42
- const renewed = await renewalResponse.json();
43
-
44
- const events = await stripe.events.list({ limit: 20 });
45
- const event = events.data.find((candidate) => candidate.type === "invoice.payment_succeeded");
46
- if (event === undefined) throw new Error("Expected a local invoice.payment_succeeded webhook event.");
47
-
48
- const delivery = await fetch(`${baseUrl}/v1/events/${event.id}/deliver?delivery_mode=duplicate`);
49
- const payload = await delivery.text();
50
- const signature = delivery.headers.get("stripe-signature");
51
- if (signature === null) throw new Error("GhostAPI webhook delivery did not include stripe-signature.");
52
- const verifiedEvent = stripe.webhooks.constructEvent(payload, signature, webhookSecret);
53
-
54
- console.log(JSON.stringify({
55
- customer: customer.id,
56
- product: product.id,
57
- price: price.id,
58
- trialSubscription: subscription.id,
59
- renewedSubscription: renewed.id,
60
- verifiedWebhook: { id: verifiedEvent.id, type: verifiedEvent.type }
61
- }, null, 2));
1
+ import Stripe from "stripe";
2
+
3
+ const host = process.env.GHOSTAPI_HOST ?? "127.0.0.1";
4
+ const port = Number(process.env.GHOSTAPI_PORT ?? "8080");
5
+ const protocol = process.env.GHOSTAPI_PROTOCOL ?? "http";
6
+ const baseUrl = `${protocol}://${host}:${port}`;
7
+ const webhookSecret =
8
+ process.env.GHOSTAPI_STRIPE_WEBHOOK_SECRET ??
9
+ "whsec_ghostapi_local_test_secret";
10
+
11
+ const stripe = new Stripe(
12
+ process.env.STRIPE_SECRET_KEY ?? "sk_test_ghostapi_local_only",
13
+ {
14
+ host,
15
+ port,
16
+ protocol,
17
+ apiVersion: "2026-02-25.clover",
18
+ },
19
+ );
20
+
21
+ const customer = await stripe.customers.create({
22
+ email: "ada@example.com",
23
+ name: "Ada Lovelace",
24
+ metadata: { example: "ghostapi-subscription-flow" },
25
+ });
26
+
27
+ const product = await stripe.products.create({ name: "GhostAPI Pro" });
28
+ const price = await stripe.prices.create({
29
+ product: product.id,
30
+ currency: "usd",
31
+ unit_amount: 2500,
32
+ recurring: { interval: "month" },
33
+ });
34
+
35
+ const subscription = await stripe.subscriptions.create({
36
+ customer: customer.id,
37
+ items: [{ price: price.id }],
38
+ trial_period_days: 7,
39
+ });
40
+
41
+ // The renewal action is a GhostAPI local test control, not a live Stripe endpoint.
42
+ const renewalResponse = await fetch(
43
+ `${baseUrl}/v1/subscriptions/${subscription.id}/renew`,
44
+ {
45
+ method: "POST",
46
+ headers: { "content-type": "application/json" },
47
+ body: JSON.stringify({}),
48
+ },
49
+ );
50
+ const renewed = await renewalResponse.json();
51
+
52
+ const events = await stripe.events.list({ limit: 20 });
53
+ const event = events.data.find(
54
+ (candidate) => candidate.type === "invoice.payment_succeeded",
55
+ );
56
+ if (event === undefined)
57
+ throw new Error("Expected a local invoice.payment_succeeded webhook event.");
58
+
59
+ const delivery = await fetch(
60
+ `${baseUrl}/v1/events/${event.id}/deliver?delivery_mode=duplicate`,
61
+ );
62
+ const payload = await delivery.text();
63
+ const signature = delivery.headers.get("stripe-signature");
64
+ if (signature === null)
65
+ throw new Error(
66
+ "GhostAPI webhook delivery did not include stripe-signature.",
67
+ );
68
+ const verifiedEvent = stripe.webhooks.constructEvent(
69
+ payload,
70
+ signature,
71
+ webhookSecret,
72
+ );
73
+
74
+ console.log(
75
+ JSON.stringify(
76
+ {
77
+ customer: customer.id,
78
+ product: product.id,
79
+ price: price.id,
80
+ trialSubscription: subscription.id,
81
+ renewedSubscription: renewed.id,
82
+ verifiedWebhook: { id: verifiedEvent.id, type: verifiedEvent.type },
83
+ },
84
+ null,
85
+ 2,
86
+ ),
87
+ );
@@ -1,21 +1,21 @@
1
- # Twilio Node Example
2
-
3
- Send a Twilio-like SMS through GhostAPI. This does not send a real SMS.
4
-
5
- ## Run
6
-
7
- Start GhostAPI:
8
-
9
- ```bash
10
- ghostapi start
11
- ```
12
-
13
- Send a message:
14
-
15
- ```bash
16
- curl -X POST http://localhost:8080/2010-04-01/Accounts/AC_mock/Messages.json \
17
- -H "content-type: application/x-www-form-urlencoded" \
18
- -d "To=+15551234567&From=+15557654321&Body=Hello%20from%20GhostAPI"
19
- ```
20
-
21
- GhostAPI detects Twilio from the `/2010-04-01/Accounts/...` path and returns a local message SID.
1
+ # Twilio Node Example
2
+
3
+ Send a Twilio-like SMS through GhostAPI. This does not send a real SMS.
4
+
5
+ ## Run
6
+
7
+ Start GhostAPI:
8
+
9
+ ```bash
10
+ ghostapi start
11
+ ```
12
+
13
+ Send a message:
14
+
15
+ ```bash
16
+ curl -X POST http://localhost:8080/2010-04-01/Accounts/AC_mock/Messages.json \
17
+ -H "content-type: application/x-www-form-urlencoded" \
18
+ -d "To=%2B15551234567&From=%2B15557654321&Body=Hello%20from%20GhostAPI"
19
+ ```
20
+
21
+ GhostAPI detects Twilio from the `/2010-04-01/Accounts/...` path and returns a local message SID.
@@ -1,19 +1,19 @@
1
- # Stateful Synthetic World Example
2
-
3
- This local-only workflow keeps one synthetic persona and organization consistent across Stripe, GitHub, email, and generic REST state.
4
-
5
- ```bash
6
- ghostapi world create --id subscription-recovery --seed demo-seed
7
- npm run build
8
- node examples/worlds/subscription-recovery.mjs
9
- ghostapi world inspect subscription-recovery --json
10
- ```
11
-
12
- The workflow atomically creates a Stripe customer and past-due subscription, records a generic REST payment failure, sends a synthetic email to a `ghostapi.invalid` inbox, and opens a synthetic GitHub recovery issue. Re-running the same action is idempotent. Reset and fork remain local:
13
-
14
- ```bash
15
- ghostapi world reset subscription-recovery
16
- ghostapi world fork subscription-recovery --id subscription-recovery-investigation
17
- ```
18
-
19
- Worlds are local JSON under `.ghostapi/worlds/`. They are bounded to 512 KiB and 100 workflow receipts, use one file lock plus atomic replacement for each transition, and intentionally do not call provider APIs or contain real credentials, inboxes, or PII.
1
+ # Stateful Synthetic World Example
2
+
3
+ This local-only workflow keeps one synthetic persona and organization consistent across Stripe, GitHub, email, and generic REST state.
4
+
5
+ ```bash
6
+ ghostapi world create --id subscription-recovery --seed demo-seed
7
+ npm run build
8
+ node examples/worlds/subscription-recovery.mjs
9
+ ghostapi world inspect subscription-recovery --json
10
+ ```
11
+
12
+ The workflow atomically creates a Stripe customer and past-due subscription, records a generic REST payment failure, sends a synthetic email to a `ghostapi.invalid` inbox, and opens a synthetic GitHub recovery issue. Re-running the same action is idempotent. Reset and fork remain local:
13
+
14
+ ```bash
15
+ ghostapi world reset subscription-recovery
16
+ ghostapi world fork subscription-recovery --id subscription-recovery-investigation
17
+ ```
18
+
19
+ Worlds are local JSON under `.ghostapi/worlds/`. They are bounded to 512 KiB and 100 workflow receipts, use one file lock plus atomic replacement for each transition, and intentionally do not call provider APIs or contain real credentials, inboxes, or PII.