@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.
- package/CHANGELOG.md +21 -0
- package/CONTRIBUTING.md +132 -119
- package/LICENSE +21 -21
- package/PROVENANCE.md +13 -0
- package/README.md +78 -80
- package/SECURITY.md +56 -53
- package/dist/actions/gateway.js +320 -72
- package/dist/actions/gateway.js.map +1 -1
- package/dist/actions/index.d.ts +2 -2
- package/dist/actions/index.js +1 -1
- package/dist/actions/index.js.map +1 -1
- package/dist/agents/agentPrompt.js +7 -5
- package/dist/agents/agentPrompt.js.map +1 -1
- package/dist/ai/aiClient.js +5 -5
- package/dist/ai/aiClient.js.map +1 -1
- package/dist/ai/aiGenerator.js +66 -26
- package/dist/ai/aiGenerator.js.map +1 -1
- package/dist/ai/genericInference.js +151 -36
- package/dist/ai/genericInference.js.map +1 -1
- package/dist/ai/prompts.js +55 -49
- package/dist/ai/prompts.js.map +1 -1
- package/dist/approvals/approvalInbox.js +649 -133
- package/dist/approvals/approvalInbox.js.map +1 -1
- package/dist/approvals/index.d.ts +2 -2
- package/dist/approvals/index.js +1 -1
- package/dist/approvals/index.js.map +1 -1
- package/dist/behavior/behaviorStore.js +34 -14
- package/dist/behavior/behaviorStore.js.map +1 -1
- package/dist/cache/index.js +14 -5
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/index.js +226 -93
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/openUrl.js +17 -3
- package/dist/cli/openUrl.js.map +1 -1
- package/dist/cli/parser.js +79 -18
- package/dist/cli/parser.js.map +1 -1
- package/dist/config/dataPaths.js +4 -2
- package/dist/config/dataPaths.js.map +1 -1
- package/dist/config/localConfig.js +5 -2
- package/dist/config/localConfig.js.map +1 -1
- package/dist/config/serverConfig.js +11 -5
- package/dist/config/serverConfig.js.map +1 -1
- package/dist/contracts/contract.js +311 -83
- package/dist/contracts/contract.js.map +1 -1
- package/dist/contracts/index.d.ts +2 -2
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/credentials/credentialBroker.js +391 -79
- package/dist/credentials/credentialBroker.js.map +1 -1
- package/dist/credentials/index.d.ts +2 -2
- package/dist/credentials/index.js +1 -1
- package/dist/credentials/index.js.map +1 -1
- package/dist/dashboard/app.js +823 -685
- package/dist/dashboard/dashboard.js.map +1 -1
- package/dist/dashboard/index.html +704 -267
- package/dist/dashboard/styles.css +1040 -349
- package/dist/egress/capabilities.js +55 -25
- package/dist/egress/capabilities.js.map +1 -1
- package/dist/egress/linuxBootstrap.js +47 -11
- package/dist/egress/linuxBootstrap.js.map +1 -1
- package/dist/egress/run.js +170 -31
- package/dist/egress/run.js.map +1 -1
- package/dist/errors/errorEngine.js +15 -3
- package/dist/errors/errorEngine.js.map +1 -1
- package/dist/errors/providerErrors.js.map +1 -1
- package/dist/evals/evals.js +304 -78
- package/dist/evals/evals.js.map +1 -1
- package/dist/evals/index.d.ts +2 -2
- package/dist/evals/index.js +1 -1
- package/dist/evals/index.js.map +1 -1
- package/dist/evidence/index.d.ts +2 -2
- package/dist/evidence/index.js +1 -1
- package/dist/evidence/index.js.map +1 -1
- package/dist/evidence/report.d.ts +1 -1
- package/dist/evidence/report.js +263 -79
- package/dist/evidence/report.js.map +1 -1
- package/dist/fault/faultLab.js +24 -9
- package/dist/fault/faultLab.js.map +1 -1
- package/dist/index.d.ts +42 -42
- package/dist/index.js +21 -21
- package/dist/index.js.map +1 -1
- package/dist/inventory/analysis.d.ts +1 -1
- package/dist/inventory/analysis.js +174 -50
- package/dist/inventory/analysis.js.map +1 -1
- package/dist/inventory/index.d.ts +4 -4
- package/dist/inventory/index.js +3 -3
- package/dist/inventory/index.js.map +1 -1
- package/dist/inventory/inventoryController.js +362 -115
- package/dist/inventory/inventoryController.js.map +1 -1
- package/dist/inventory/types.js +680 -140
- package/dist/inventory/types.js.map +1 -1
- package/dist/ledger/actionLedger.js +355 -78
- package/dist/ledger/actionLedger.js.map +1 -1
- package/dist/ledger/index.d.ts +2 -2
- package/dist/ledger/index.js +1 -1
- package/dist/ledger/index.js.map +1 -1
- package/dist/mcp/server.js +26 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +1 -1
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/policy.js +112 -32
- package/dist/policy/policy.js.map +1 -1
- package/dist/productTelemetry/index.js +71 -20
- package/dist/productTelemetry/index.js.map +1 -1
- package/dist/providers/conformance.js +10 -5
- package/dist/providers/conformance.js.map +1 -1
- package/dist/providers/discord.js +2 -2
- package/dist/providers/generic.js +3 -3
- package/dist/providers/github.js +2 -2
- package/dist/providers/index.d.ts +3 -3
- package/dist/providers/index.js +2 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.js +3 -3
- package/dist/providers/packs/resendPack.js +51 -25
- package/dist/providers/packs/resendPack.js.map +1 -1
- package/dist/providers/packs/stripePack.js +590 -121
- package/dist/providers/packs/stripePack.js.map +1 -1
- package/dist/providers/registry.js +4 -4
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/runtime.js +7 -6
- package/dist/providers/runtime.js.map +1 -1
- package/dist/providers/stripeWebhook.js +39 -10
- package/dist/providers/stripeWebhook.js.map +1 -1
- package/dist/providers/twilio.js +2 -2
- package/dist/proxy/cacheKey.js +9 -2
- package/dist/proxy/cacheKey.js.map +1 -1
- package/dist/proxy/providerDetector.js +22 -9
- package/dist/proxy/providerDetector.js.map +1 -1
- package/dist/proxy/proxyHandler.js +57 -22
- package/dist/proxy/proxyHandler.js.map +1 -1
- package/dist/proxy/requestNormalizer.js +4 -2
- package/dist/proxy/requestNormalizer.js.map +1 -1
- package/dist/reliability/costGovernance.js +211 -49
- package/dist/reliability/costGovernance.js.map +1 -1
- package/dist/reliability/index.d.ts +8 -8
- package/dist/reliability/index.js +4 -4
- package/dist/reliability/index.js.map +1 -1
- package/dist/reliability/reconciliation.js +274 -65
- package/dist/reliability/reconciliation.js.map +1 -1
- package/dist/reliability/runtimeHealth.js +127 -35
- package/dist/reliability/runtimeHealth.js.map +1 -1
- package/dist/reliability/slo.js +257 -50
- package/dist/reliability/slo.js.map +1 -1
- package/dist/report/safetyReport.d.ts +6 -0
- package/dist/report/safetyReport.js +56 -12
- package/dist/report/safetyReport.js.map +1 -1
- package/dist/rules/aiRules.js +5 -5
- package/dist/rules/aiRules.js.map +1 -1
- package/dist/safety/index.d.ts +2 -2
- package/dist/safety/index.js +1 -1
- package/dist/safety/index.js.map +1 -1
- package/dist/safety/safetyController.js +675 -165
- package/dist/safety/safetyController.js.map +1 -1
- package/dist/scenarios/scenarioBundle.js +204 -71
- package/dist/scenarios/scenarioBundle.js.map +1 -1
- package/dist/scenarios/scenarioStore.js +88 -29
- package/dist/scenarios/scenarioStore.js.map +1 -1
- package/dist/security/headerSanitizer.js +52 -10
- package/dist/security/headerSanitizer.js.map +1 -1
- package/dist/security/secrets.js +10 -5
- package/dist/security/secrets.js.map +1 -1
- package/dist/server/accessControl.js +37 -10
- package/dist/server/accessControl.js.map +1 -1
- package/dist/server/createServer.js +1 -1
- package/dist/server/createServer.js.map +1 -1
- package/dist/server/eventsStore.js +15 -5
- package/dist/server/eventsStore.js.map +1 -1
- package/dist/server/routes.js +67 -19
- package/dist/server/routes.js.map +1 -1
- package/dist/server/sse.js +1 -1
- package/dist/server/sse.js.map +1 -1
- package/dist/setup/sdkDetector.js +7 -2
- package/dist/setup/sdkDetector.js.map +1 -1
- package/dist/setup/setupGenerator.js +136 -48
- package/dist/setup/setupGenerator.js.map +1 -1
- package/dist/state/stateExtractor.js +3 -1
- package/dist/state/stateExtractor.js.map +1 -1
- package/dist/state/stateResolver.js +10 -7
- package/dist/state/stateResolver.js.map +1 -1
- package/dist/state/stateStore.js +13 -4
- package/dist/state/stateStore.js.map +1 -1
- package/dist/storage/fileStore.js +12 -4
- package/dist/storage/fileStore.js.map +1 -1
- package/dist/teamControl/controlPlane.js +846 -174
- package/dist/teamControl/controlPlane.js.map +1 -1
- package/dist/teamControl/deployment.js +19 -5
- package/dist/teamControl/deployment.js.map +1 -1
- package/dist/teamControl/index.d.ts +4 -4
- package/dist/teamControl/index.js +2 -2
- package/dist/teamControl/index.js.map +1 -1
- package/dist/tests/testGenerator.js +15 -7
- package/dist/tests/testGenerator.js.map +1 -1
- package/dist/trust/index.d.ts +2 -2
- package/dist/trust/index.js +1 -1
- package/dist/trust/index.js.map +1 -1
- package/dist/trust/trustLadder.js +309 -63
- package/dist/trust/trustLadder.js.map +1 -1
- package/dist/worlds/index.d.ts +2 -2
- package/dist/worlds/index.js +1 -1
- package/dist/worlds/index.js.map +1 -1
- package/dist/worlds/worlds.js +364 -65
- package/dist/worlds/worlds.js.map +1 -1
- package/docs/assets/dashboard.png +0 -0
- package/docs/assets/ghostapi-avatar.png +0 -0
- package/docs/ci.md +49 -49
- package/docs/github-actions.md +84 -84
- package/docs/mcp.md +58 -52
- package/docs/policy.md +63 -61
- package/docs/providers/authoring-packs.md +180 -175
- package/docs/providers/stripe-core-pack.md +84 -82
- package/docs/releases/README.md +13 -0
- package/docs/security/action-gateway-threat-model.md +34 -34
- package/docs/security/action-ledger-incident-replay-threat-model.md +42 -42
- package/docs/security/approval-inbox-threat-model.md +35 -35
- package/docs/security/credential-broker-threat-model.md +52 -52
- package/docs/security/egress-threat-model.md +126 -126
- package/docs/security/inventory-threat-model.md +104 -104
- package/docs/security/kill-switch-budgets-threat-model.md +37 -37
- package/docs/security/reliability-threat-model.md +111 -111
- package/docs/security/trust-ladder-threat-model.md +33 -33
- package/docs/telemetry.md +14 -0
- package/docs/usage.md +680 -571
- package/examples/README.md +10 -10
- package/examples/agent-instructions/README.md +39 -39
- package/examples/ci-smoke/README.md +21 -21
- package/examples/ci-smoke/ghostapi.policy.yaml +22 -22
- package/examples/ci-smoke/package.json +9 -9
- package/examples/ci-smoke/production-egress.mjs +4 -2
- package/examples/ci-smoke/safe.mjs +21 -17
- package/examples/evals/README.md +24 -24
- package/examples/evals/retry-after.eval.json +71 -52
- package/examples/generic-rest/README.md +27 -27
- package/examples/github-fetch/README.md +38 -35
- package/examples/openai-streaming/README.md +16 -16
- package/examples/openai-streaming/streaming-tool-call.mjs +44 -31
- package/examples/policy/ghostapi.policy.yaml +27 -27
- package/examples/record-replay/README.md +19 -19
- package/examples/record-replay/replay-requests.json +22 -22
- package/examples/record-replay/stripe-checkout.har.json +30 -30
- package/examples/resend-node/README.md +22 -22
- package/examples/stripe-node/README.md +35 -35
- package/examples/stripe-node/checkout-flow.mjs +87 -61
- package/examples/twilio-node/README.md +21 -21
- package/examples/worlds/README.md +19 -19
- package/examples/worlds/subscription-recovery.mjs +21 -12
- package/package.json +28 -6
- package/dist/landing/assets/index-BXR41fAD.css +0 -1
- package/dist/landing/assets/index-CxWsopzP.css +0 -1
- package/dist/landing/assets/index-D8_ggMRE.js +0 -55
- package/dist/landing/assets/index-DZlpyhqd.js +0 -55
- package/dist/landing/assets/index-Dk-Xezs3.js +0 -55
- package/dist/landing/index.html +0 -15
- package/dist/landing/landing.d.ts +0 -3
- package/dist/landing/landing.js +0 -12
- package/dist/landing/landing.js.map +0 -1
- package/docs/commercial/README.md +0 -29
- package/docs/commercial/data-inventory.md +0 -36
- package/docs/commercial/manual-invoicing.md +0 -44
- package/docs/commercial/metrics.md +0 -51
- package/docs/commercial/pricing.md +0 -103
- package/docs/commercial/privacy-policy-draft.md +0 -41
- package/docs/commercial/terms-topics-for-counsel.md +0 -51
- package/docs/design-partners/README.md +0 -52
- package/docs/design-partners/demo-narratives.md +0 -33
- package/docs/design-partners/design-partner-offer.md +0 -39
- package/docs/design-partners/discovery-questions.md +0 -28
- package/docs/design-partners/feedback-capture-template.md +0 -48
- package/docs/design-partners/icp-one-pager.md +0 -43
- package/docs/design-partners/onboarding-checklist.md +0 -33
- package/docs/design-partners/pilot-success-criteria.md +0 -27
- package/docs/design-partners/pricing-interview-script.md +0 -18
- package/docs/design-partners/telemetry-plan.md +0 -48
- package/docs/development/baseline.md +0 -114
- package/docs/development/onboarding-smoke.md +0 -37
- package/docs/development/verification-0.1.8.md +0 -25
- package/docs/enterprise-product-roadmap-ru.md +0 -1879
- package/docs/fundraising/README.md +0 -87
- package/docs/fundraising/data-room-checklist.md +0 -72
- package/docs/fundraising/demo-script.md +0 -52
- package/docs/fundraising/design-partners-50.md +0 -74
- package/docs/fundraising/launch-posts.md +0 -37
- package/docs/fundraising/metrics-and-evidence.md +0 -30
- package/docs/fundraising/roadmap-12-month.md +0 -25
- package/docs/fundraising/technical-due-diligence-index.md +0 -37
- package/docs/fundraising/yc-application.md +0 -25
- package/docs/hosted-pilot.md +0 -111
- package/docs/operations/disaster-recovery-runbook.md +0 -81
- package/docs/operations/kill-switch-runbook.md +0 -32
- package/docs/release-checklist.md +0 -83
- package/docs/release-migration-and-rollback.md +0 -63
- package/docs/release-readiness.md +0 -39
- package/docs/team-control-plane.md +0 -72
|
@@ -1,31 +1,44 @@
|
|
|
1
|
-
const baseUrl =
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
-
|
|
12
|
-
-
|
|
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 =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
|
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.
|