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 <noreply@anthropic.com>
This commit is contained in:
Liviu 2026-09-26 15:35:24 +03:00
parent af565d3aec
commit 983f93aa66
9 changed files with 24 additions and 8 deletions

View File

@ -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)
}

View File

@ -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)

View File

@ -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)}`);
}

View File

@ -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);
}

View File

@ -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",

View File

@ -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)}")

View File

@ -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"

View File

@ -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})])

View File

@ -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
});