Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aabd66933d | ||
|
|
528081bb88 | ||
|
|
6b0e8b8f77 | ||
|
|
a63c360539 | ||
|
|
89bdd6e3b8 | ||
|
|
909691328e |
No files matched your search
@@ -0,0 +1,15 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Opening a pull request on git.zacharyzhang.com
|
||||||
|
|
||||||
|
Forking is disabled on this server. Open pull requests with AGit instead:
|
||||||
|
|
||||||
|
1. Register an account at https://git.zacharyzhang.com
|
||||||
|
2. Clone, commit your changes, then push to a `refs/for/<target-branch>` ref:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.zacharyzhang.com/Elydora-Infrastructure/Elydora-Node-SDK.git
|
||||||
|
git push origin HEAD:refs/for/main -o topic=<short-name> -o title="<PR title>" -o description="<PR body>"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. To update the pull request, push again with the same `topic`.
|
||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@elydora/sdk",
|
"name": "@elydora/sdk",
|
||||||
"version": "2.0.1",
|
"version": "2.1.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@elydora/sdk",
|
"name": "@elydora/sdk",
|
||||||
"version": "2.0.1",
|
"version": "2.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@decimalturn/toml-patch": "^2.0.0",
|
"@decimalturn/toml-patch": "^2.0.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@elydora/sdk",
|
"name": "@elydora/sdk",
|
||||||
"version": "2.1.0",
|
"version": "2.1.1",
|
||||||
"description": "Node.js/TypeScript SDK for the Elydora tamper-evident audit platform",
|
"description": "Node.js/TypeScript SDK for the Elydora tamper-evident audit platform",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
+14
-2
@@ -285,9 +285,13 @@ export class ElydoraClient {
|
|||||||
return handleResponse<HealthResponse>(res);
|
return handleResponse<HealthResponse>(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 503 carries the degraded report, not an error. */
|
||||||
async deepHealth(): Promise<DeepHealthResponse> {
|
async deepHealth(): Promise<DeepHealthResponse> {
|
||||||
const url = `${this.baseUrl}/v1/health/deep`;
|
const url = `${this.baseUrl}/v1/health/deep`;
|
||||||
const res = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json' } });
|
const res = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json' } });
|
||||||
|
if (res.status === 503) {
|
||||||
|
return (await res.json()) as DeepHealthResponse;
|
||||||
|
}
|
||||||
return handleResponse<DeepHealthResponse>(res);
|
return handleResponse<DeepHealthResponse>(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +344,7 @@ export class ElydoraClient {
|
|||||||
body: body !== undefined ? JSON.stringify(body) : undefined,
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (attempt < this.maxRetries && (res.status === 429 || res.status >= 500)) {
|
if (attempt < this.maxRetries && isIdempotent(method) && (res.status === 429 || res.status >= 500)) {
|
||||||
const retryAfter = res.headers.get('Retry-After');
|
const retryAfter = res.headers.get('Retry-After');
|
||||||
const delayMs = retryAfter
|
const delayMs = retryAfter
|
||||||
? parseInt(retryAfter, 10) * 1000
|
? parseInt(retryAfter, 10) * 1000
|
||||||
@@ -357,10 +361,11 @@ export class ElydoraClient {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attempt < this.maxRetries) {
|
if (attempt < this.maxRetries && isIdempotent(method)) {
|
||||||
await sleep(Math.min(1000 * 2 ** attempt, 10_000));
|
await sleep(Math.min(1000 * 2 ** attempt, 10_000));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +373,13 @@ export class ElydoraClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IDEMPOTENT_METHODS = new Set(['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE']);
|
||||||
|
|
||||||
|
/** A lost response to a non-idempotent request must not be replayed. */
|
||||||
|
function isIdempotent(method: string): boolean {
|
||||||
|
return IDEMPOTENT_METHODS.has(method.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
async function handleResponse<T>(res: Response): Promise<T> {
|
async function handleResponse<T>(res: Response): Promise<T> {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
if (res.status === 204) {
|
if (res.status === 204) {
|
||||||
|
|||||||
@@ -384,6 +384,7 @@ export interface RotateApiTokenResponse {
|
|||||||
readonly token: string;
|
readonly token: string;
|
||||||
readonly expires_at: number | null;
|
readonly expires_at: number | null;
|
||||||
readonly token_id: string;
|
readonly token_id: string;
|
||||||
|
readonly previous_token_grace_until: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HealthResponse {
|
export interface HealthResponse {
|
||||||
|
|||||||
Reference in new issue
Block a user