this.me
Version:
.me is your identity. It enables decentralized trust through cryptographic signatures.
325 lines (324 loc) • 9.74 kB
JavaScript
class o {
constructor(t, s) {
this.me = t, this.url = s, this.ws = null, this.reconnectInterval = 1e4, this.isConnected = !1, this.connect();
}
connect() {
this.ws = new WebSocket(this.url), this.ws.onopen = () => {
console.log("[this.me][WS] Connected to daemon"), this.isConnected = !0, this.me.state?.status && (this.me.state.status.active = !0, this.me.state.status.error = !1), this.#t();
}, this.ws.onmessage = (t) => {
try {
const s = JSON.parse(t.data);
this.#s(s);
} catch {
console.warn("[this.me][WS] Invalid message:", t.data);
}
}, this.ws.onclose = () => {
console.warn("[this.me][WS] Disconnected, retrying in 10s"), this.isConnected = !1, this.me.state?.status && (this.me.state.status.active = !1, this.me.state.status.error = !0), this.#t(), setTimeout(() => this.connect(), this.reconnectInterval);
}, this.ws.onerror = (t) => {
console.error("[this.me][WS] Error:", t), this.ws.close();
};
}
#s(t) {
switch (t.type) {
case "status":
this.me.state.status = {
active: t.data.active,
error: !1,
data: t.data
};
break;
case "listUs":
this.me.state.listUs = t.data;
break;
case "update":
console.log("[this.me][WS] Update event:", t.data);
break;
default:
console.warn("[this.me][WS] Unknown message type:", t.type);
}
this.#t();
}
send(t, s) {
this.isConnected && this.ws.readyState === WebSocket.OPEN && this.ws.send(JSON.stringify({ type: t, data: s }));
}
#t() {
this.me.subscribers?.size && this.me.subscribers.forEach((t) => t(this.me.state));
}
}
class c {
constructor(t = "http://localhost:7777/graphql") {
this.endpoint = t, this.state = {
status: { active: !1, error: !1, loading: !0, data: null },
listUs: [],
activeMe: null
}, this.subscribers = /* @__PURE__ */ new Set(), this.status(), this.socket = null;
}
/** 🔹 Init
* Manually initializes the daemon state (status + listUs).
* Useful if you need to re-check after user actions.
*/
async init() {
return this.#s({
status: { ...this.state.status, loading: !0 }
}), (await this.status()).active && (await this.startSocket(), await new Promise((s) => {
let a = !1;
const e = this.subscribe((i) => {
!a && i.status.active !== void 0 && (a = !0, e(), s());
});
setTimeout(() => {
a || (a = !0, e(), s());
}, 2e3);
})), this.#s({
status: { ...this.state.status, loading: !1 }
}), this.state.status;
}
async startSocket() {
if (this.state.status.active) {
if (this.socket) {
console.warn("[this.me] WebSocket already running");
return;
}
this.socket = new o(this.endpoint.replace("/graphql", "")), this.socket.on("status", (t) => {
this._updateFromSocket({
status: { active: !0, error: !1, data: t }
});
}), this.socket.on("listUs", (t) => {
this._updateFromSocket({ listUs: t });
}), this.socket.on("update", (t) => {
console.log("[this.me] update event", t);
});
}
}
_updateFromSocket(t) {
this.#s(t);
}
setEndpoint(t) {
typeof t == "string" && t.trim() !== "" && (this.endpoint = t);
}
getState() {
return this.state;
}
#s(t) {
this.state = { ...this.state, ...t }, this.subscribers.forEach((s) => s(this.state));
}
subscribe(t) {
return this.subscribers.add(t), () => this.subscribers.delete(t);
}
async #t(t, s = {}) {
const a = await fetch(this.endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: t, variables: s })
});
if (!a.ok) throw new Error(`GraphQL error: ${a.status}`);
const { data: e, errors: i } = await a.json();
if (i) throw new Error(i.map((r) => r.message).join(", "));
return e;
}
// 🔹 Daemon-level helpers
/** 🔹 Daemon status
* Retrieves the current status of the daemon.
* Use to check if the service is active and get version/uptime info.
*/
async status() {
const t = `
query {
status {
active
version
uptime
}
}
`;
try {
const s = await this.#t(t), a = s.status ? {
active: s.status.active,
version: s.status.version,
uptime: s.status.uptime
} : { active: !1, version: null, uptime: null };
return this.#s({ status: { active: a.active, error: !1, data: a } }), a;
} catch {
const s = { active: !1, version: null, uptime: null };
return this.#s({ status: { active: !1, error: !0, data: null } }), s;
}
}
/** 🔹 List all identities
* Fetches all available identities (users).
* Use to display or manage the list of identities.
*/
async listUs() {
const t = `
query {
listUs {
alias
path
}
}
`;
try {
const s = await this.#t(t), a = Array.isArray(s.listUs) ? s.listUs.map(({ alias: e, path: i }) => ({ alias: e, path: i })) : [];
return this.#s({ listUs: a }), a;
} catch {
return this.#s({ listUs: [] }), [];
}
}
/** 🔹 Load an identity
* Loads a specific identity by alias and hash.
* Use to activate or switch to a particular identity.
*/
async loadMe(t, s) {
const a = `
mutation($alias: String!, $hash: String!) {
loadMe(alias: $alias, hash: $hash)
}
`;
try {
const i = !!(await this.#t(a, { alias: t, hash: s })).loadMe;
return i && this.#s({ activeMe: t }), i;
} catch {
return !1;
}
}
// 🔹 Me-level operations
/** 🔹 Be operation
* Performs a 'be' mutation for given alias, key, and value.
* Use to set or update identity attributes.
*/
async be(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
be(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).be;
} catch {
return !1;
}
}
/** 🔹 Have operation
* Performs a 'have' mutation for given alias, key, and value.
* Use to declare possession or ownership related to identity.
*/
async have(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
have(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).have;
} catch {
return !1;
}
}
/** 🔹 Do operation
* Performs a 'do' mutation for given alias, key, and value.
* Use to record actions or activities for the identity.
*/
async do_(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
do(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).do;
} catch {
return !1;
}
}
/** 🔹 At operation
* Performs an 'at' mutation for given alias, key, and value.
* Use to set location or context related data for the identity.
*/
async at(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
at(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).at;
} catch {
return !1;
}
}
/** 🔹 Relate operation
* Performs a 'relate' mutation for given alias, key, and value.
* Use to define relationships or connections for the identity.
*/
async relate(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
relate(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).relate;
} catch {
return !1;
}
}
/** 🔹 React operation
* Performs a 'react' mutation for given alias, key, and value.
* Use to record reactions or responses by the identity.
*/
async react(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
react(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).react;
} catch {
return !1;
}
}
/** 🔹 Communication operation
* Performs a 'communication' mutation for given alias, key, and value.
* Use to log communications or messages for the identity.
*/
async communication(t, s, a) {
const e = `
mutation($alias: String!, $key: String!, $value: String!) {
communication(alias: $alias, key: $key, value: $value)
}
`;
try {
return !!(await this.#t(e, { alias: t, key: s, value: a })).communication;
} catch {
return !1;
}
}
/** 🔹 Get identity info
* Queries detailed information about a specific identity by alias.
* Use to retrieve public data like alias and publicKey.
*/
async me(t) {
const s = `
query($alias: String!) {
me(alias: $alias) {
alias
publicKey
}
}
`;
try {
const a = await this.#t(s, { alias: t });
if (a.me && typeof a.me == "object") {
const { alias: e, publicKey: i } = a.me;
return e && i ? { alias: e, publicKey: i } : null;
}
return null;
} catch {
return null;
}
}
}
const u = new c();
typeof window < "u" && (window.me = u, console.log("[this.me] Global instance available as window.me"));
export {
u as default
};