Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions examples/eep-reference-implementation/node/src/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,50 @@ describe("EEP node reference", () => {
body: JSON.stringify({
source_did: "did:web:test",
delivery_method: "webhook",
callback_url: "https://example.com/hook",
event_types: ["com.example.entity.updated"],
delivery_url: "https://example.com/hook",
}),
});
expect(res.status).toBe(200);
expect(res.status).toBe(201);
const body = await res.json();
expect(body.status).toBe("pending_verification");
});

// `delivery_url` is the field schemas/v0.1/subscription.request.json
// defines. Reading `callback_url` instead meant a conformant subscriber's
// delivery target was silently dropped: the subscription was created but
// could never receive a webhook.
it("records the delivery_url from the request body", async () => {
const res = await fetch(`${baseUrl}/eep/subscribe`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
source_did: "did:web:test",
delivery_method: "webhook",
event_types: ["com.example.entity.updated"],
delivery_url: "https://agent.example.com/hooks/eep",
}),
});
expect(res.status).toBe(201);
const body = await res.json();
expect(body.delivery_url).toBe("https://agent.example.com/hooks/eep");
});

it("still accepts the deprecated callback_url alias", async () => {
const res = await fetch(`${baseUrl}/eep/subscribe`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
source_did: "did:web:test",
delivery_method: "webhook",
callback_url: "https://legacy.example.com/hooks/eep",
}),
});
expect(res.status).toBe(201);
const body = await res.json();
expect(body.delivery_url).toBe("https://legacy.example.com/hooks/eep");
});

it("resolves entity and link headers", async () => {
const res = await fetch(`${baseUrl}/u/u/acme-corp`);
expect(res.status).toBe(200);
Expand All @@ -63,7 +99,7 @@ describe("EEP node reference", () => {
headers: { "Content-Type": "application/json" },
body: "",
});
expect(sub.status).toBe(200);
expect(sub.status).toBe(201);
const payload = await sub.json();
expect(payload.status).toBe("active");
expect(payload.source_did).toContain("did:web:api.eep.dev");
Expand Down
19 changes: 17 additions & 2 deletions examples/eep-reference-implementation/node/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,18 +287,33 @@ export function createEEPNodeServer(baseUrl = "http://localhost:3100") {
const body = await readJson(req);
const method = body.delivery_method === "webhook" ? "webhook" : "sse";
const subscription_id = `sub_ref_${Date.now()}`;
// The wire field is `delivery_url` — that is what
// schemas/v0.1/subscription.request.json defines and what every
// conformant subscriber sends. `callback_url` is this stack's own
// internal column name and was never part of the request body;
// reading it here silently discarded the delivery target.
const deliveryUrl =
typeof body.delivery_url === "string"
? body.delivery_url
: typeof body.callback_url === "string"
? body.callback_url // deprecated alias, accepted for older demos
: undefined;
const entry: SubscriptionEntry = {
subscription_id,
source_did: String(body.source_did ?? "did:web:api.eep.dev:u:acme-corp"),
delivery_method: method,
callback_url: typeof body.callback_url === "string" ? body.callback_url : undefined,
callback_url: deliveryUrl,
created_at: new Date().toISOString(),
};
await subscriptions.save(entry);
return sendJson(res, 200, {
return sendJson(res, 201, {
subscription_id,
status: method === "webhook" ? "pending_verification" : "active",
source_did: entry.source_did,
// Echo the stored target so a subscriber (and the conformance
// suite) can confirm it was actually recorded.
delivery_url: entry.callback_url,
created_at: entry.created_at,
});
}

Expand Down
19 changes: 17 additions & 2 deletions examples/eep-reference-implementation/python/eep_api_python/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,22 +313,37 @@ def gates() -> Dict[str, Any]:
return serialize_gate_config(GATE_CONFIG)


@app.post("/eep/subscribe")
@app.post("/eep/subscribe", status_code=201)
def subscribe(payload: Dict[str, Any]) -> Dict[str, Any]:
method = "webhook" if payload.get("delivery_method") == "webhook" else "sse"
subscription_id = f"sub_ref_{int(time.time() * 1000)}"
# The wire field is `delivery_url` — that is what
# schemas/v0.1/subscription.request.json defines and what every
# conformant subscriber sends. `callback_url` is this stack's own
# internal column name and was never part of the request body; reading
# it here silently discarded the delivery target.
delivery_url = payload.get("delivery_url")
if not isinstance(delivery_url, str):
# Deprecated alias, accepted for older demos.
delivery_url = payload.get("callback_url")
if not isinstance(delivery_url, str):
delivery_url = None
entry = {
"subscription_id": subscription_id,
"source_did": payload.get("source_did", "did:web:api.eep.dev:u:acme-corp"),
"delivery_method": method,
"callback_url": payload.get("callback_url"),
"callback_url": delivery_url,
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
}
SUBSCRIPTIONS.save(entry)
return {
"subscription_id": subscription_id,
"status": "pending_verification" if method == "webhook" else "active",
"source_did": entry["source_did"],
# Echo the stored target so a subscriber (and the conformance
# suite) can confirm it was actually recorded.
"delivery_url": entry["callback_url"],
"created_at": entry["created_at"],
}


Expand Down
35 changes: 34 additions & 1 deletion examples/eep-reference-implementation/python/tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,43 @@ def test_registry_manifest_has_economics():

def test_subscribe():
res = client.post("/eep/subscribe", json={"source_did": "did:web:test", "delivery_method": "webhook"})
assert res.status_code == 200
assert res.status_code == 201
assert res.json()["status"] == "pending_verification"


def test_subscribe_records_the_delivery_url_from_the_request_body():
"""`delivery_url` is the field subscription.request.json defines.

Reading `callback_url` instead meant a conformant subscriber's delivery
target was silently dropped: the subscription was created but could
never receive a webhook.
"""
res = client.post(
"/eep/subscribe",
json={
"source_did": "did:web:test",
"delivery_method": "webhook",
"event_types": ["com.example.entity.updated"],
"delivery_url": "https://agent.example.com/hooks/eep",
},
)
assert res.status_code == 201
assert res.json()["delivery_url"] == "https://agent.example.com/hooks/eep"


def test_subscribe_still_accepts_the_deprecated_callback_url_alias():
res = client.post(
"/eep/subscribe",
json={
"source_did": "did:web:test",
"delivery_method": "webhook",
"callback_url": "https://legacy.example.com/hooks/eep",
},
)
assert res.status_code == 201
assert res.json()["delivery_url"] == "https://legacy.example.com/hooks/eep"


def test_entity_resolution_headers():
res = client.get("/u/u/acme-corp")
assert res.status_code == 200
Expand Down