@333eco/heartbank-api 0.0.0-stage → 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/LICENSE +7 -0
- package/LICENSE-APACHE +73 -0
- package/LICENSE-CC0 +121 -0
- package/README.md +72 -2
- package/dist/confirm.d.ts +43 -0
- package/dist/confirm.js +45 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/login.d.ts +113 -0
- package/dist/login.js +165 -0
- package/dist/lookup.d.ts +23 -0
- package/dist/lookup.js +22 -0
- package/dist/runtime.d.ts +46 -0
- package/dist/runtime.js +98 -0
- package/dist/sign.d.ts +68 -0
- package/dist/sign.js +43 -0
- package/dist/thank.d.ts +89 -0
- package/dist/thank.js +85 -0
- package/dist/verify.d.ts +58 -0
- package/dist/verify.js +113 -0
- package/package.json +26 -4
package/dist/login.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Generated by scripts/gen-client.mjs from openapi/login.json. ⛔ Do not edit: change the description and run npm run client.
|
|
2
|
+
import { send, urlOf } from "./runtime.js";
|
|
3
|
+
/** Log in with HeartBank®: Prove who someone is, with a passkey. OpenID Connect on the FAPI 2.0 profile. */
|
|
4
|
+
export class LoginClient {
|
|
5
|
+
o;
|
|
6
|
+
constructor(o = {}) {
|
|
7
|
+
this.o = o;
|
|
8
|
+
}
|
|
9
|
+
/** The discovery document: every endpoint, scope and algorithm. @see https://developers.333.eco/log-in#discovery */
|
|
10
|
+
discovery() {
|
|
11
|
+
return send(this.o, {
|
|
12
|
+
method: "GET",
|
|
13
|
+
base: "https://login.333.eco",
|
|
14
|
+
path: "/.well-known/openid-configuration",
|
|
15
|
+
pathParams: undefined,
|
|
16
|
+
query: undefined,
|
|
17
|
+
headers: undefined,
|
|
18
|
+
security: "none",
|
|
19
|
+
accept: "json",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** The keys login signs ID tokens with. @see https://developers.333.eco/log-in#jwks */
|
|
23
|
+
jwks() {
|
|
24
|
+
return send(this.o, {
|
|
25
|
+
method: "GET",
|
|
26
|
+
base: "https://login.333.eco",
|
|
27
|
+
path: "/.well-known/jwks.json",
|
|
28
|
+
pathParams: undefined,
|
|
29
|
+
query: undefined,
|
|
30
|
+
headers: undefined,
|
|
31
|
+
security: "none",
|
|
32
|
+
accept: "json",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** Push the log-in request (PAR, required). @see https://developers.333.eco/log-in#pushauthorizationrequest */
|
|
36
|
+
pushAuthorizationRequest(input) {
|
|
37
|
+
return send(this.o, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
base: "https://login.333.eco",
|
|
40
|
+
path: "/request",
|
|
41
|
+
pathParams: undefined,
|
|
42
|
+
query: undefined,
|
|
43
|
+
headers: undefined,
|
|
44
|
+
body: input.body,
|
|
45
|
+
contentType: "application/x-www-form-urlencoded",
|
|
46
|
+
security: "privateKeyJwt",
|
|
47
|
+
audience: "endpoint",
|
|
48
|
+
accept: "json",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Send the browser here (one tap from where the person is). @see https://developers.333.eco/log-in#authorize */
|
|
52
|
+
authorizeUrl(input) {
|
|
53
|
+
return urlOf(this.o.baseUrl ?? "https://login.333.eco", "/auth", undefined, { client_id: input.client_id, request_uri: input.request_uri });
|
|
54
|
+
}
|
|
55
|
+
/** Exchange the code. @see https://developers.333.eco/log-in#token */
|
|
56
|
+
token(input) {
|
|
57
|
+
return send(this.o, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
base: "https://login.333.eco",
|
|
60
|
+
path: "/token",
|
|
61
|
+
pathParams: undefined,
|
|
62
|
+
query: undefined,
|
|
63
|
+
headers: undefined,
|
|
64
|
+
body: input.body,
|
|
65
|
+
contentType: "application/x-www-form-urlencoded",
|
|
66
|
+
security: "privateKeyJwt+dpop",
|
|
67
|
+
audience: "endpoint",
|
|
68
|
+
accept: "json",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** The person's claims. @see https://developers.333.eco/log-in#userinfo */
|
|
72
|
+
userinfo(input) {
|
|
73
|
+
return send(this.o, {
|
|
74
|
+
method: "GET",
|
|
75
|
+
base: "https://login.333.eco",
|
|
76
|
+
path: "/me",
|
|
77
|
+
pathParams: undefined,
|
|
78
|
+
query: undefined,
|
|
79
|
+
headers: undefined,
|
|
80
|
+
security: "dpop",
|
|
81
|
+
accessToken: input.accessToken,
|
|
82
|
+
accept: "json",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Revoke a token. @see https://developers.333.eco/log-in#revoke */
|
|
86
|
+
revoke(input) {
|
|
87
|
+
return send(this.o, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
base: "https://login.333.eco",
|
|
90
|
+
path: "/token/revocation",
|
|
91
|
+
pathParams: undefined,
|
|
92
|
+
query: undefined,
|
|
93
|
+
headers: undefined,
|
|
94
|
+
body: input.body,
|
|
95
|
+
contentType: "application/x-www-form-urlencoded",
|
|
96
|
+
security: "privateKeyJwt",
|
|
97
|
+
audience: "endpoint",
|
|
98
|
+
accept: "none",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** Log out of HeartBank® too. @see https://developers.333.eco/log-in#logout */
|
|
102
|
+
logOutUrl(input) {
|
|
103
|
+
return urlOf(this.o.baseUrl ?? "https://login.333.eco", "/session/end", undefined, { client_id: input.client_id, post_logout_redirect_uri: input.post_logout_redirect_uri });
|
|
104
|
+
}
|
|
105
|
+
/** Is this browser logged in at HeartBank®? (display only). @see https://developers.333.eco/log-in#sessionstate */
|
|
106
|
+
sessionState() {
|
|
107
|
+
return send(this.o, {
|
|
108
|
+
method: "GET",
|
|
109
|
+
base: "https://login.333.eco",
|
|
110
|
+
path: "/session/state",
|
|
111
|
+
pathParams: undefined,
|
|
112
|
+
query: undefined,
|
|
113
|
+
headers: undefined,
|
|
114
|
+
security: "none",
|
|
115
|
+
accept: "json",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/** Announce a security change before making it. @see https://developers.333.eco/log-in#notice */
|
|
119
|
+
notice(input) {
|
|
120
|
+
return send(this.o, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
base: "https://login.333.eco",
|
|
123
|
+
path: "/notice",
|
|
124
|
+
pathParams: undefined,
|
|
125
|
+
query: undefined,
|
|
126
|
+
headers: undefined,
|
|
127
|
+
body: input.body,
|
|
128
|
+
contentType: "application/x-www-form-urlencoded",
|
|
129
|
+
security: "privateKeyJwt",
|
|
130
|
+
audience: "endpoint",
|
|
131
|
+
accept: "json",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/** Read a person's verified-human layers again. @see https://developers.333.eco/log-in#verifiedhuman */
|
|
135
|
+
verifiedHuman(input) {
|
|
136
|
+
return send(this.o, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
base: "https://login.333.eco",
|
|
139
|
+
path: "/poh",
|
|
140
|
+
pathParams: undefined,
|
|
141
|
+
query: undefined,
|
|
142
|
+
headers: undefined,
|
|
143
|
+
body: input.body,
|
|
144
|
+
contentType: "application/x-www-form-urlencoded",
|
|
145
|
+
security: "privateKeyJwt",
|
|
146
|
+
audience: "endpoint",
|
|
147
|
+
accept: "json",
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Thank with HeartBank®: exchange a press for a pressToken. @see https://developers.333.eco/log-in#wrappress */
|
|
151
|
+
wrapPress(input) {
|
|
152
|
+
return send(this.o, {
|
|
153
|
+
method: "POST",
|
|
154
|
+
base: "https://login.333.eco",
|
|
155
|
+
path: "/press/wrap",
|
|
156
|
+
pathParams: undefined,
|
|
157
|
+
query: undefined,
|
|
158
|
+
headers: undefined,
|
|
159
|
+
body: input.body,
|
|
160
|
+
contentType: "application/x-www-form-urlencoded",
|
|
161
|
+
security: "none",
|
|
162
|
+
accept: "json",
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
package/dist/lookup.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ClientOptions } from "./runtime.js";
|
|
2
|
+
export type Name = {
|
|
3
|
+
/** The name in the form its holder chose, with @ (for example @sokha.keo). */ name: string;
|
|
4
|
+
/** Their page. */ page: string;
|
|
5
|
+
/** What they are called, as they wrote it (any script). */ said: string;
|
|
6
|
+
/** Their one line, or empty. */ line: string;
|
|
7
|
+
/** Up to three https links they chose. */ links: Array<string>;
|
|
8
|
+
/** Their photo's address, or null. */ photo: string | null;
|
|
9
|
+
/** Their own recording of their name, or null. */ voice: string | null;
|
|
10
|
+
/** Whether they let search engines list their page. */ searchable: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type ErrorBody = {
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
15
|
+
/** Lookup: One exact name on B-Registry℠, and what that person's public page shows. Free, with no key. */
|
|
16
|
+
export declare class LookupClient {
|
|
17
|
+
private readonly o;
|
|
18
|
+
constructor(o?: ClientOptions);
|
|
19
|
+
/** Look up one exact name. @see https://developers.333.eco/lookup#byname */
|
|
20
|
+
byName(input: {
|
|
21
|
+
/** The name, with or without @; the registry folds case and punctuation, so sokha.keo, SOKHA-KEO and sokhakeo are one name. */ name: string;
|
|
22
|
+
}): Promise<Name>;
|
|
23
|
+
}
|
package/dist/lookup.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Generated by scripts/gen-client.mjs from openapi/lookup.json. ⛔ Do not edit: change the description and run npm run client.
|
|
2
|
+
import { send } from "./runtime.js";
|
|
3
|
+
/** Lookup: One exact name on B-Registry℠, and what that person's public page shows. Free, with no key. */
|
|
4
|
+
export class LookupClient {
|
|
5
|
+
o;
|
|
6
|
+
constructor(o = {}) {
|
|
7
|
+
this.o = o;
|
|
8
|
+
}
|
|
9
|
+
/** Look up one exact name. @see https://developers.333.eco/lookup#byname */
|
|
10
|
+
byName(input) {
|
|
11
|
+
return send(this.o, {
|
|
12
|
+
method: "GET",
|
|
13
|
+
base: "https://333.eco",
|
|
14
|
+
path: "/api/v1/names/{name}",
|
|
15
|
+
pathParams: { name: input.name },
|
|
16
|
+
query: undefined,
|
|
17
|
+
headers: undefined,
|
|
18
|
+
security: "none",
|
|
19
|
+
accept: "json",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime the generated clients share. It knows HOW to send a request and names no endpoint: every endpoint, field
|
|
3
|
+
* and type comes from openapi/ through scripts/gen-client.mjs (SPEC §7: no hand-written second copy).
|
|
4
|
+
*
|
|
5
|
+
* ⛔ The client never holds a key. Your server signs: `assertion(aud)` returns a fresh ES256 client assertion (one use,
|
|
6
|
+
* at most five minutes old) and `dpop(method, url, accessToken?)` a DPoP proof. A key inside an app is not a secret, so
|
|
7
|
+
* this client is for your SERVER; the browser steps (log in, log out, the signing page) are links it builds for you.
|
|
8
|
+
*/
|
|
9
|
+
export interface ClientOptions {
|
|
10
|
+
/** Replaces the server named in the description (for a test double; the sandbox when it exists). */
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
fetch?: typeof globalThis.fetch;
|
|
13
|
+
/** A fresh client assertion whose `aud` is the given address (private_key_jwt). */
|
|
14
|
+
assertion?: (aud: string) => Promise<string>;
|
|
15
|
+
/** A DPoP proof for this request; `accessToken` is given when the request carries one. */
|
|
16
|
+
dpop?: (method: string, url: string, accessToken?: string) => Promise<string>;
|
|
17
|
+
/** A B-Origin℠ API key (it begins `bo_live_`). ⛔ Keep it on your server. */
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Any answer outside 2xx. `error` and `why` are the service's own words; a refusal from Thank never reaches here (it is `{written: false}`). */
|
|
21
|
+
export declare class ApiError extends Error {
|
|
22
|
+
status: number;
|
|
23
|
+
error: string;
|
|
24
|
+
why?: string | undefined;
|
|
25
|
+
body?: unknown | undefined;
|
|
26
|
+
constructor(status: number, error: string, why?: string | undefined, body?: unknown | undefined);
|
|
27
|
+
}
|
|
28
|
+
export type Security = "none" | "clientAssertion" | "privateKeyJwt" | "dpop" | "privateKeyJwt+dpop" | "apiKey";
|
|
29
|
+
export interface Call {
|
|
30
|
+
method: string;
|
|
31
|
+
base: string;
|
|
32
|
+
path: string;
|
|
33
|
+
pathParams?: Record<string, string | number>;
|
|
34
|
+
query?: Record<string, string | number | undefined>;
|
|
35
|
+
headers?: Record<string, string | undefined>;
|
|
36
|
+
body?: unknown;
|
|
37
|
+
contentType?: string;
|
|
38
|
+
security: Security;
|
|
39
|
+
accessToken?: string;
|
|
40
|
+
/** The client assertion's `aud`: the server's address, or this endpoint's (each security scheme's `x-aud` says which). */
|
|
41
|
+
audience?: "server" | "endpoint";
|
|
42
|
+
/** What the success answer is: parsed JSON, text, or bytes. */
|
|
43
|
+
accept: "json" | "text" | "bytes" | "none";
|
|
44
|
+
}
|
|
45
|
+
export declare function urlOf(base: string, path: string, pathParams?: Record<string, string | number>, query?: Record<string, string | number | undefined>): string;
|
|
46
|
+
export declare function send<T>(o: ClientOptions, c: Call): Promise<T>;
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** Any answer outside 2xx. `error` and `why` are the service's own words; a refusal from Thank never reaches here (it is `{written: false}`). */
|
|
2
|
+
export class ApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
error;
|
|
5
|
+
why;
|
|
6
|
+
body;
|
|
7
|
+
constructor(status, error, why, body) {
|
|
8
|
+
super(`${status} ${error}${why ? `: ${why}` : ""}`);
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.error = error;
|
|
11
|
+
this.why = why;
|
|
12
|
+
this.body = body;
|
|
13
|
+
this.name = "ApiError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
17
|
+
export function urlOf(base, path, pathParams = {}, query = {}) {
|
|
18
|
+
const filled = path.replace(/\{(\w+)\}/g, (_, k) => {
|
|
19
|
+
if (pathParams[k] === undefined)
|
|
20
|
+
throw new TypeError(`missing path parameter ${k}`);
|
|
21
|
+
return encodeURIComponent(String(pathParams[k]));
|
|
22
|
+
});
|
|
23
|
+
const u = new URL(base.replace(/\/$/, "") + filled);
|
|
24
|
+
for (const [k, v] of Object.entries(query))
|
|
25
|
+
if (v !== undefined)
|
|
26
|
+
u.searchParams.set(k, String(v));
|
|
27
|
+
return u.toString();
|
|
28
|
+
}
|
|
29
|
+
export async function send(o, c) {
|
|
30
|
+
const f = o.fetch ?? globalThis.fetch;
|
|
31
|
+
const url = urlOf(o.baseUrl ?? c.base, c.path, c.pathParams, c.query);
|
|
32
|
+
// The address the service checks, never the test double's.
|
|
33
|
+
const aud = c.audience === "server" ? c.base.replace(/\/$/, "") : urlOf(c.base, c.path, c.pathParams);
|
|
34
|
+
const headers = {};
|
|
35
|
+
for (const [k, v] of Object.entries(c.headers ?? {}))
|
|
36
|
+
if (v !== undefined)
|
|
37
|
+
headers[k] = v;
|
|
38
|
+
let body;
|
|
39
|
+
let form;
|
|
40
|
+
if (c.contentType === "application/x-www-form-urlencoded")
|
|
41
|
+
form = { ...c.body };
|
|
42
|
+
if (c.security === "clientAssertion") {
|
|
43
|
+
if (!o.assertion)
|
|
44
|
+
throw new TypeError("this call needs options.assertion");
|
|
45
|
+
headers["x-client-assertion"] = await o.assertion(aud);
|
|
46
|
+
}
|
|
47
|
+
if (c.security === "privateKeyJwt" || c.security === "privateKeyJwt+dpop") {
|
|
48
|
+
if (!o.assertion)
|
|
49
|
+
throw new TypeError("this call needs options.assertion");
|
|
50
|
+
form = { ...form, client_assertion_type: ASSERTION_TYPE, client_assertion: await o.assertion(aud) };
|
|
51
|
+
}
|
|
52
|
+
if (c.security === "dpop" || c.security === "privateKeyJwt+dpop") {
|
|
53
|
+
if (!o.dpop)
|
|
54
|
+
throw new TypeError("this call needs options.dpop");
|
|
55
|
+
headers["DPoP"] = await o.dpop(c.method, aud, c.accessToken);
|
|
56
|
+
if (c.accessToken)
|
|
57
|
+
headers["Authorization"] = `DPoP ${c.accessToken}`;
|
|
58
|
+
}
|
|
59
|
+
if (c.security === "apiKey") {
|
|
60
|
+
if (!o.apiKey)
|
|
61
|
+
throw new TypeError("this call needs options.apiKey");
|
|
62
|
+
headers["Authorization"] = `Bearer ${o.apiKey}`;
|
|
63
|
+
}
|
|
64
|
+
if (form) {
|
|
65
|
+
const p = new URLSearchParams();
|
|
66
|
+
for (const [k, v] of Object.entries(form))
|
|
67
|
+
if (v !== undefined)
|
|
68
|
+
p.set(k, String(v));
|
|
69
|
+
body = p;
|
|
70
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
71
|
+
}
|
|
72
|
+
else if (c.body !== undefined) {
|
|
73
|
+
if (c.contentType === "application/json") {
|
|
74
|
+
body = JSON.stringify(c.body);
|
|
75
|
+
headers["Content-Type"] = "application/json";
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
body = c.body;
|
|
79
|
+
headers["Content-Type"] = c.contentType ?? "application/octet-stream";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const r = await f(url, { method: c.method, headers, body, redirect: "manual" });
|
|
83
|
+
if (r.status < 200 || r.status > 299) {
|
|
84
|
+
let j = null;
|
|
85
|
+
try {
|
|
86
|
+
j = await r.json();
|
|
87
|
+
}
|
|
88
|
+
catch { /* not JSON */ }
|
|
89
|
+
throw new ApiError(r.status, j?.error ?? (r.statusText || "error"), j?.why ?? j?.error_description, j);
|
|
90
|
+
}
|
|
91
|
+
if (c.accept === "none")
|
|
92
|
+
return undefined;
|
|
93
|
+
if (c.accept === "bytes")
|
|
94
|
+
return new Uint8Array(await r.arrayBuffer());
|
|
95
|
+
if (c.accept === "text")
|
|
96
|
+
return (await r.text());
|
|
97
|
+
return (await r.json());
|
|
98
|
+
}
|
package/dist/sign.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type ClientOptions } from "./runtime.js";
|
|
2
|
+
export type ErrorBody = {
|
|
3
|
+
error: string;
|
|
4
|
+
why?: string;
|
|
5
|
+
};
|
|
6
|
+
/** Built by `claimFor()` in the package; send it as built. It names the file by its fingerprints only. */
|
|
7
|
+
export type Claim = {
|
|
8
|
+
v: 2;
|
|
9
|
+
sha256: string;
|
|
10
|
+
pixels?: string;
|
|
11
|
+
phash?: string;
|
|
12
|
+
mime: string;
|
|
13
|
+
bytes: number;
|
|
14
|
+
/** An IPTC digital source type, for example `digitalCreation`. From the package, `sourceFromHistory({imports, mostly: 0.8})` works it out from what went into the work. */ source: string;
|
|
15
|
+
/** Your app's registered name. ⚠️ It goes into every record your app signs, permanently, so keep it short and plain. */ tool: string;
|
|
16
|
+
declared: boolean;
|
|
17
|
+
/** Optional, for example `CC0-1.0`. */ rights?: string;
|
|
18
|
+
imports?: Array<Record<string, unknown>>;
|
|
19
|
+
createdAtDeclared?: string;
|
|
20
|
+
};
|
|
21
|
+
export type RecordEntry = {
|
|
22
|
+
/** The record's number in the public log. */ index: number;
|
|
23
|
+
/** `similar` is a hint that two pictures look alike, nothing more. */ how: "exact" | "same pixels" | "similar";
|
|
24
|
+
distance?: number;
|
|
25
|
+
signedWith: "passkey";
|
|
26
|
+
at: string;
|
|
27
|
+
source: string;
|
|
28
|
+
declared: boolean;
|
|
29
|
+
rights?: string;
|
|
30
|
+
/** Present when the signer withdrew it: it stays in the log, marked as withdrawn by them. */ withdrawnAt?: string;
|
|
31
|
+
};
|
|
32
|
+
export type Trace = {
|
|
33
|
+
/** The file's SHA-256. */ fingerprint: string;
|
|
34
|
+
records: Array<RecordEntry>;
|
|
35
|
+
/** The file's C2PA manifest when present; `check.state` is `trusted` (signer on the C2PA trust list; it still says only what the signer declared), `valid` (signer not on the list, so anyone could have made it) or `invalid` (`failures` says why). */ c2pa?: Record<string, unknown>;
|
|
36
|
+
iptc?: Record<string, unknown>;
|
|
37
|
+
generators: Array<string>;
|
|
38
|
+
watermarks: Array<{
|
|
39
|
+
kind?: string;
|
|
40
|
+
model?: string;
|
|
41
|
+
agreement?: number;
|
|
42
|
+
}>;
|
|
43
|
+
/** B-Signal℠: the AI markers found in the file, recomputable from this same answer. ⛔ Never a measure of how human a work is, and never shown as a grade of someone's work (you agree to this when you make a key). */ signal: number;
|
|
44
|
+
/** What this answer did not look for, on every answer (SynthID has no public check). */ notChecked: Array<string>;
|
|
45
|
+
};
|
|
46
|
+
/** Sign with HeartBank®: Let the people who use your app sign what they made, and let anyone check it. B-Origin℠. */
|
|
47
|
+
export declare class SignClient {
|
|
48
|
+
private readonly o;
|
|
49
|
+
constructor(o?: ClientOptions);
|
|
50
|
+
/** Look up what a file carries (B-Trace℠, metered). @see https://developers.333.eco/sign#trace */
|
|
51
|
+
trace(input: {
|
|
52
|
+
body: Uint8Array | ArrayBuffer | Blob;
|
|
53
|
+
}): Promise<Trace>;
|
|
54
|
+
/** Ask a person to sign a file (from your web page). @see https://developers.333.eco/sign#requestsign */
|
|
55
|
+
requestSign(input: {
|
|
56
|
+
body: {
|
|
57
|
+
claim: Claim;
|
|
58
|
+
state?: string;
|
|
59
|
+
};
|
|
60
|
+
}): Promise<{
|
|
61
|
+
request_uri: string;
|
|
62
|
+
expires_in: number;
|
|
63
|
+
}>;
|
|
64
|
+
/** The page where the person signs. @see https://developers.333.eco/sign#signpage */
|
|
65
|
+
signPageUrl(input: {
|
|
66
|
+
request_uri: string;
|
|
67
|
+
}): string;
|
|
68
|
+
}
|
package/dist/sign.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Generated by scripts/gen-client.mjs from openapi/sign.json. ⛔ Do not edit: change the description and run npm run client.
|
|
2
|
+
import { send, urlOf } from "./runtime.js";
|
|
3
|
+
/** Sign with HeartBank®: Let the people who use your app sign what they made, and let anyone check it. B-Origin℠. */
|
|
4
|
+
export class SignClient {
|
|
5
|
+
o;
|
|
6
|
+
constructor(o = {}) {
|
|
7
|
+
this.o = o;
|
|
8
|
+
}
|
|
9
|
+
/** Look up what a file carries (B-Trace℠, metered). @see https://developers.333.eco/sign#trace */
|
|
10
|
+
trace(input) {
|
|
11
|
+
return send(this.o, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
base: "https://origin.333.eco",
|
|
14
|
+
path: "/api/v1/trace",
|
|
15
|
+
pathParams: undefined,
|
|
16
|
+
query: undefined,
|
|
17
|
+
headers: undefined,
|
|
18
|
+
body: input.body,
|
|
19
|
+
contentType: "application/octet-stream",
|
|
20
|
+
security: "apiKey",
|
|
21
|
+
accept: "json",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** Ask a person to sign a file (from your web page). @see https://developers.333.eco/sign#requestsign */
|
|
25
|
+
requestSign(input) {
|
|
26
|
+
return send(this.o, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
base: "https://sign.333.eco",
|
|
29
|
+
path: "/sign/par",
|
|
30
|
+
pathParams: undefined,
|
|
31
|
+
query: undefined,
|
|
32
|
+
headers: undefined,
|
|
33
|
+
body: input.body,
|
|
34
|
+
contentType: "application/json",
|
|
35
|
+
security: "none",
|
|
36
|
+
accept: "json",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** The page where the person signs. @see https://developers.333.eco/sign#signpage */
|
|
40
|
+
signPageUrl(input) {
|
|
41
|
+
return urlOf(this.o.baseUrl ?? "https://sign.333.eco", "/sign", undefined, { request_uri: input.request_uri });
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dist/thank.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type ClientOptions } from "./runtime.js";
|
|
2
|
+
/** The ledger declined, or there is no season open. ⛔ No reason and no count, by design. */
|
|
3
|
+
export type NotWritten = {
|
|
4
|
+
written: false;
|
|
5
|
+
};
|
|
6
|
+
export type Prepared = {
|
|
7
|
+
/** Send back unchanged at commit. */ pending: string;
|
|
8
|
+
/** Signed by the ledger with the challenge and a description of what is being signed (ledger, units, season, to, and for Kiitti the direction and kind); sign.333.eco shows the person that description before they press. */ ticket: string;
|
|
9
|
+
};
|
|
10
|
+
export type Written = {
|
|
11
|
+
written: true;
|
|
12
|
+
/** ⛔ Only the entry's id reaches your app (threat T16: an index or a signature would count other apps' thanks). The full receipt goes to the two people, in their own records. */ receipt: {
|
|
13
|
+
id: string;
|
|
14
|
+
};
|
|
15
|
+
/** One-use tokens, one per side, to place that side on the public map later with /v1/place. A token knows neither the person nor the entry. */ place?: {
|
|
16
|
+
from?: string;
|
|
17
|
+
to?: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** ⏳ Outside apps will name the receiver by registry handle instead, never another person's token (A591 (3)). */
|
|
21
|
+
export type Person = {
|
|
22
|
+
/** From the person's log-in at login.333.eco (scope `ledger`). */ pidToken: string;
|
|
23
|
+
sub: string;
|
|
24
|
+
};
|
|
25
|
+
export type PrepareKiitos = {
|
|
26
|
+
/** Your id for this thank. The same ref returns the same answer and writes once. */ ref: string;
|
|
27
|
+
pidToken: string;
|
|
28
|
+
sub: string;
|
|
29
|
+
ledger: "kiitos";
|
|
30
|
+
to: Person;
|
|
31
|
+
/** Optional: exactly 32 bytes of your own, committed with a salt (never stored as sent); it reaches the two people in their records. */ cargo?: string;
|
|
32
|
+
};
|
|
33
|
+
/** First-party only (B-Twin, thank.333.eco): care for a thing, plant or animal, decided by the ledger's public rule on witnessed evidence. ⛔ Never an outside app: from season 2 an outside app's Kiitti is only a person's thanks to all of life, a call with no direction, twin or evidence field (directive #94). */
|
|
34
|
+
export type PrepareKiitti = {
|
|
35
|
+
ref: string;
|
|
36
|
+
pidToken: string;
|
|
37
|
+
sub: string;
|
|
38
|
+
ledger: "kiitti";
|
|
39
|
+
dir: "kind" | "thankful";
|
|
40
|
+
evidence: {
|
|
41
|
+
kind: "thing" | "plant" | "animal";
|
|
42
|
+
twinId: string;
|
|
43
|
+
attested: boolean;
|
|
44
|
+
match?: number;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export type ErrorBody = {
|
|
48
|
+
error: string;
|
|
49
|
+
};
|
|
50
|
+
export type Ring = {
|
|
51
|
+
/** The ring's color. */ color: string;
|
|
52
|
+
/** The ring's width, drawn as a ring: ⛔ never shown as a number to chase. */ ring: number;
|
|
53
|
+
};
|
|
54
|
+
/** Thank with HeartBank®: Record a thank on the gratitude ledger. Your app prepares it, the person presses their own passkey, your app commits it. */
|
|
55
|
+
export declare class ThankClient {
|
|
56
|
+
private readonly o;
|
|
57
|
+
constructor(o?: ClientOptions);
|
|
58
|
+
/** Step 1: prepare a thank. @see https://developers.333.eco/thank#prepare */
|
|
59
|
+
prepare(input: {
|
|
60
|
+
body: PrepareKiitos | PrepareKiitti;
|
|
61
|
+
}): Promise<Prepared | NotWritten>;
|
|
62
|
+
/** Step 3: commit the pressed thank. @see https://developers.333.eco/thank#commit */
|
|
63
|
+
commit(input: {
|
|
64
|
+
body: {
|
|
65
|
+
ref: string;
|
|
66
|
+
pending: string;
|
|
67
|
+
/** From POST https://login.333.eco/press/wrap. */ pressToken: string;
|
|
68
|
+
};
|
|
69
|
+
}): Promise<Written | NotWritten>;
|
|
70
|
+
/** Place one side of a written thank on the public map. @see https://developers.333.eco/thank#place */
|
|
71
|
+
place(input: {
|
|
72
|
+
body: {
|
|
73
|
+
token: string;
|
|
74
|
+
/** An area about 100 km across (0.9° bands), from the ledger's open cell function. */ cell: number;
|
|
75
|
+
};
|
|
76
|
+
}): Promise<{
|
|
77
|
+
placed: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
/** Read a person's ring. @see https://developers.333.eco/thank#ring */
|
|
80
|
+
ring(input: {
|
|
81
|
+
sub: string;
|
|
82
|
+
"x-pid-token": string;
|
|
83
|
+
}): Promise<{
|
|
84
|
+
kiitos?: Ring;
|
|
85
|
+
kiitti?: Ring;
|
|
86
|
+
}>;
|
|
87
|
+
/** Retired: a thank without a press (retired). @see https://developers.333.eco/thank#submit */
|
|
88
|
+
submit(): Promise<void>;
|
|
89
|
+
}
|
package/dist/thank.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Generated by scripts/gen-client.mjs from openapi/thank.json. ⛔ Do not edit: change the description and run npm run client.
|
|
2
|
+
import { send } from "./runtime.js";
|
|
3
|
+
/** Thank with HeartBank®: Record a thank on the gratitude ledger. Your app prepares it, the person presses their own passkey, your app commits it. */
|
|
4
|
+
export class ThankClient {
|
|
5
|
+
o;
|
|
6
|
+
constructor(o = {}) {
|
|
7
|
+
this.o = o;
|
|
8
|
+
}
|
|
9
|
+
/** Step 1: prepare a thank. @see https://developers.333.eco/thank#prepare */
|
|
10
|
+
prepare(input) {
|
|
11
|
+
return send(this.o, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
base: "https://ledger.heartbank.net",
|
|
14
|
+
path: "/v1/prepare",
|
|
15
|
+
pathParams: undefined,
|
|
16
|
+
query: undefined,
|
|
17
|
+
headers: undefined,
|
|
18
|
+
body: input.body,
|
|
19
|
+
contentType: "application/json",
|
|
20
|
+
security: "clientAssertion",
|
|
21
|
+
audience: "server",
|
|
22
|
+
accept: "json",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** Step 3: commit the pressed thank. @see https://developers.333.eco/thank#commit */
|
|
26
|
+
commit(input) {
|
|
27
|
+
return send(this.o, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
base: "https://ledger.heartbank.net",
|
|
30
|
+
path: "/v1/commit",
|
|
31
|
+
pathParams: undefined,
|
|
32
|
+
query: undefined,
|
|
33
|
+
headers: undefined,
|
|
34
|
+
body: input.body,
|
|
35
|
+
contentType: "application/json",
|
|
36
|
+
security: "clientAssertion",
|
|
37
|
+
audience: "server",
|
|
38
|
+
accept: "json",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Place one side of a written thank on the public map. @see https://developers.333.eco/thank#place */
|
|
42
|
+
place(input) {
|
|
43
|
+
return send(this.o, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
base: "https://ledger.heartbank.net",
|
|
46
|
+
path: "/v1/place",
|
|
47
|
+
pathParams: undefined,
|
|
48
|
+
query: undefined,
|
|
49
|
+
headers: undefined,
|
|
50
|
+
body: input.body,
|
|
51
|
+
contentType: "application/json",
|
|
52
|
+
security: "clientAssertion",
|
|
53
|
+
audience: "server",
|
|
54
|
+
accept: "json",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Read a person's ring. @see https://developers.333.eco/thank#ring */
|
|
58
|
+
ring(input) {
|
|
59
|
+
return send(this.o, {
|
|
60
|
+
method: "GET",
|
|
61
|
+
base: "https://ledger.heartbank.net",
|
|
62
|
+
path: "/v1/aura",
|
|
63
|
+
pathParams: undefined,
|
|
64
|
+
query: { sub: input.sub },
|
|
65
|
+
headers: { "x-pid-token": input["x-pid-token"] },
|
|
66
|
+
security: "clientAssertion",
|
|
67
|
+
audience: "server",
|
|
68
|
+
accept: "json",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Retired: a thank without a press (retired). @see https://developers.333.eco/thank#submit */
|
|
72
|
+
submit() {
|
|
73
|
+
return send(this.o, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
base: "https://ledger.heartbank.net",
|
|
76
|
+
path: "/v1/submit",
|
|
77
|
+
pathParams: undefined,
|
|
78
|
+
query: undefined,
|
|
79
|
+
headers: undefined,
|
|
80
|
+
security: "clientAssertion",
|
|
81
|
+
audience: "server",
|
|
82
|
+
accept: "none",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|