From 983f93aa66021efffd40ca1751e0b428f2b8b8f8 Mon Sep 17 00:00:00 2001 From: Liviu Date: Sat, 26 Sep 2026 15:35:24 +0300 Subject: [PATCH] 1.5.2: finality() in all four clients (JS, Python, Go, Java): GET /v1/data/finality The post-quantum finality point of the chain (finalized/safe = the parent of the most recent anchor whose certificate reaches the threshold in force). Same surface in every client; tests updated (JS 12, Python 12, Go ok, Java 7). Synced byte for byte from the source tree (aerenew/sdk) on 2026-09-26. Co-Authored-By: Claude Fable 5.1 --- go/aerecloud.go | 9 +++++++-- go/aerecloud_test.go | 2 +- index.mjs | 2 ++ java/src/main/java/network/aere/cloud/AereCloud.java | 2 ++ package.json | 2 +- python/aere_cloud/__init__.py | 6 +++++- python/pyproject.toml | 2 +- python/test_aere_cloud.py | 5 +++-- test/sdk.test.mjs | 2 ++ 9 files changed, 24 insertions(+), 8 deletions(-) diff --git a/go/aerecloud.go b/go/aerecloud.go index 3818f79..47c2917 100644 --- a/go/aerecloud.go +++ b/go/aerecloud.go @@ -1,6 +1,6 @@ // Package aerecloud is the official Go client for the Aere Cloud API (Aere Network, chain 2800). // -// Same routes and semantics as @aere/cloud (JS), aere-cloud (Python) and aere-cloud (Java) 1.5.0. Zero dependencies +// Same routes and semantics as @aere/cloud (JS), aere-cloud (Python) and aere-cloud (Java) 1.5.2. Zero dependencies // beyond the Go standard library. JSON routes return the server's JSON as json.RawMessage, so the integrator decodes it // into whatever types they already use; the two routes that return FILES (the audit export and the check of a kept // export) return typed results with the digest computed locally from the bytes received. @@ -30,7 +30,7 @@ import ( ) // Version of this client, sent in the User-Agent (the edge refuses generic library agents on every route). -const Version = "1.5.0" +const Version = "1.5.2" // DefaultBaseURL is the production gateway. const DefaultBaseURL = "https://cloud.aere.network/v1" @@ -174,6 +174,11 @@ func (c *Client) Anchors(ctx context.Context, limit int) (json.RawMessage, error func (c *Client) Anchor(ctx context.Context, height uint64) (json.RawMessage, error) { return c.jsonReq(ctx, "GET", "/data/anchors/"+strconv.FormatUint(height, 10), nil, true) } + +// Finality returns the post-quantum finality point (finalized/safe = the parent of the last certified anchor), 2026-09-26. +func (c *Client) Finality(ctx context.Context) (json.RawMessage, error) { + return c.jsonReq(ctx, "GET", "/data/finality", nil, true) +} func (c *Client) Transfers(ctx context.Context, address string, limit int) (json.RawMessage, error) { return c.jsonReq(ctx, "GET", "/data/transfers?address="+url.QueryEscape(address)+"&limit="+strconv.Itoa(limit), nil, true) } diff --git a/go/aerecloud_test.go b/go/aerecloud_test.go index 3dfb4f7..c1fd3bf 100644 --- a/go/aerecloud_test.go +++ b/go/aerecloud_test.go @@ -87,7 +87,7 @@ func TestReadinessCheiaNumaiLaAttest(t *testing.T) { if v.Method != "POST" || v.Path != "/v1/pq/readiness" || v.Key != "" || v.Body != `{"domain":"example.com"}` { t.Fatalf("fara attest: %+v", v) } - if v.UA != "aere-cloud-go/1.5.0" { + if v.UA != "aere-cloud-go/"+Version { // versiunea din cod, nu scrisa fix (2026-09-26: 1.5.2 a rupt literalul) t.Fatalf("user-agent: %q", v.UA) } c.Readiness(ctx, "example.com", true, true) diff --git a/index.mjs b/index.mjs index 16709b5..1068eb2 100644 --- a/index.mjs +++ b/index.mjs @@ -70,6 +70,8 @@ export class AereCloud { validators() { return this._req('GET', '/data/validators'); } anchors(limit = 10) { return this._req('GET', `/data/anchors?limit=${encodeURIComponent(limit)}`); } anchor(height) { return this._req('GET', `/data/anchors/${encodeURIComponent(height)}`); } + // 2026-09-26: the post-quantum finality point (finalized/safe = the parent of the last certified anchor), the tag nodes do not serve yet + finality() { return this._req('GET', '/data/finality'); } transfers(address, limit = 50) { return this._req('GET', `/data/transfers?address=${encodeURIComponent(address)}&limit=${encodeURIComponent(limit)}`); } diff --git a/java/src/main/java/network/aere/cloud/AereCloud.java b/java/src/main/java/network/aere/cloud/AereCloud.java index 1a8abff..6bce224 100644 --- a/java/src/main/java/network/aere/cloud/AereCloud.java +++ b/java/src/main/java/network/aere/cloud/AereCloud.java @@ -132,6 +132,8 @@ public final class AereCloud { public String validators() { return req("GET", "/data/validators", null, true); } public String anchors(int limit) { return req("GET", "/data/anchors?limit=" + limit, null, true); } public String anchor(long height) { return req("GET", "/data/anchors/" + height, null, true); } + /** 2026-09-26: the post-quantum finality point (finalized/safe = the parent of the last certified anchor). */ + public String finality() { return req("GET", "/data/finality", null, true); } public String transfers(String address, int limit) { return req("GET", "/data/transfers?address=" + address + "&limit=" + limit, null, true); } diff --git a/package.json b/package.json index d6517c2..5e01678 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aere/cloud", - "version": "1.5.1", + "version": "1.5.2", "description": "Official client for the Aere Cloud API: keyed RPC, post-quantum verification, chain data, notarization, webhooks and gas sponsorship on Aere Network (chain 2800).", "type": "module", "main": "index.mjs", diff --git a/python/aere_cloud/__init__.py b/python/aere_cloud/__init__.py index 393789d..8878ebb 100644 --- a/python/aere_cloud/__init__.py +++ b/python/aere_cloud/__init__.py @@ -14,7 +14,7 @@ import urllib.request import urllib.error from typing import Any, Optional -__version__ = "1.5.1" +__version__ = "1.5.2" __all__ = ["AereCloud", "AereCloudError", "verify_webhook"] _BAZA = "https://cloud.aere.network/v1" @@ -119,6 +119,10 @@ class AereCloud: def anchor(self, height: int) -> dict: return self._req("GET", f"/data/anchors/{int(height)}") + def finality(self) -> dict: + """2026-09-26: the post-quantum finality point (finalized/safe = the parent of the last certified anchor).""" + return self._req("GET", "/data/finality") + def transfers(self, address: str, limit: int = 50) -> dict: return self._req("GET", f"/data/transfers?address={address}&limit={int(limit)}") diff --git a/python/pyproject.toml b/python/pyproject.toml index 4758a2a..fe968ef 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "aere-cloud" -version = "1.5.1" +version = "1.5.2" description = "Official Python client for the Aere Cloud API (Aere Network, chain 2800): RPC, post-quantum verification, chain data, notarization, webhooks, gas sponsorship." readme = "README.md" requires-python = ">=3.9" diff --git a/python/test_aere_cloud.py b/python/test_aere_cloud.py index 1ee80ef..cee1ce9 100644 --- a/python/test_aere_cloud.py +++ b/python/test_aere_cloud.py @@ -73,12 +73,13 @@ def t_eroare_http(): assert e.status == 403 and e.body["error"] == "invalid_or_expired_key" and e.path == "/account" def t_query(): - tr = Transport([(200, {}), (200, {}), (200, {})]) + tr = Transport([(200, {}), (200, {}), (200, {}), (200, {})]) c = AereCloud("k", opener=tr) - c.anchors(3); c.transfers("0xAB", 7); c.anchor(15000000) + c.anchors(3); c.transfers("0xAB", 7); c.anchor(15000000); c.finality() assert tr.cereri[0].full_url.endswith("/data/anchors?limit=3") assert tr.cereri[1].full_url.endswith("/data/transfers?address=0xAB&limit=7") assert tr.cereri[2].full_url.endswith("/data/anchors/15000000") + assert tr.cereri[3].full_url.endswith("/data/finality") def t_pq_sponsor(): tr = Transport([(200, {"txHash": "0xab", "account": "0xcd", "alreadyDeployed": False})]) diff --git a/test/sdk.test.mjs b/test/sdk.test.mjs index 4daa2c4..3b4e118 100644 --- a/test/sdk.test.mjs +++ b/test/sdk.test.mjs @@ -64,10 +64,12 @@ await test('un status HTTP de eroare devine AereCloudError cu corpul serverului' await test('rutele de date construiesc corect query-ul', async () => { const rute = { 'GET /data/anchors?limit=3': { status: 200, corp: { anchors: [] } }, + 'GET /data/finality': { status: 200, corp: { finalized: 1, anchor: 2 } }, 'GET /data/transfers?address=0xBeef&limit=25': { status: 200, corp: { tokenTransfers: [], nativeTransfers: [] } }, }; const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals(rute) }); await c.anchors(3); + await c.finality(); await c.transfers('0xBeef', 25); // daca reperele nu s-ar potrivi, fetchFals ar da 404 si _req ar arunca });