web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

meshnet.ts (3700B)


      1 import { nfc_message_json, nfc_record_data_text, nfc_record_json } from "./records.js";
      2 import type { NfcMessageInput, NfcReadPayload, NfcRecord, NfcRecordInput } from "./types.js";
      3 
      4 export type NfcMeshnetProfile = {
      5     display_name: string;
      6     device_label: string;
      7 };
      8 
      9 export type NfcMeshnetPacketProfile = {
     10     type: "meshnet.profile.v1";
     11     profile: NfcMeshnetProfile;
     12     timestamp_ms: number;
     13 };
     14 
     15 export type NfcMeshnetPacketChat = {
     16     type: "meshnet.chat.v1";
     17     message_id: string;
     18     profile: NfcMeshnetProfile;
     19     text: string;
     20     timestamp_ms: number;
     21 };
     22 
     23 export type NfcMeshnetPacket = NfcMeshnetPacketProfile | NfcMeshnetPacketChat;
     24 
     25 export const NFC_MESHNET_MEDIA_TYPE = "application/vnd.radroots.meshnet+json";
     26 
     27 const is_record = (value: unknown): value is Record<string, unknown> =>
     28     typeof value === "object" && value !== null && !Array.isArray(value);
     29 
     30 const is_string = (value: unknown): value is string => typeof value === "string";
     31 
     32 const is_number = (value: unknown): value is number =>
     33     typeof value === "number" && Number.isFinite(value);
     34 
     35 const is_profile = (value: unknown): value is NfcMeshnetProfile => {
     36     if (!is_record(value)) return false;
     37     return is_string(value.display_name) && is_string(value.device_label);
     38 };
     39 
     40 const is_packet_profile = (value: unknown): value is NfcMeshnetPacketProfile => {
     41     if (!is_record(value)) return false;
     42     if (value.type !== "meshnet.profile.v1") return false;
     43     if (!is_profile(value.profile)) return false;
     44     if (!is_number(value.timestamp_ms)) return false;
     45     return true;
     46 };
     47 
     48 const is_packet_chat = (value: unknown): value is NfcMeshnetPacketChat => {
     49     if (!is_record(value)) return false;
     50     if (value.type !== "meshnet.chat.v1") return false;
     51     if (!is_string(value.message_id)) return false;
     52     if (!is_profile(value.profile)) return false;
     53     if (!is_string(value.text)) return false;
     54     if (!is_number(value.timestamp_ms)) return false;
     55     return true;
     56 };
     57 
     58 export const nfc_meshnet_packet_profile = (
     59     profile: NfcMeshnetProfile,
     60     timestamp_ms: number,
     61 ): NfcMeshnetPacketProfile => {
     62     return {
     63         type: "meshnet.profile.v1",
     64         profile,
     65         timestamp_ms,
     66     };
     67 };
     68 
     69 export const nfc_meshnet_packet_chat = (
     70     profile: NfcMeshnetProfile,
     71     text: string,
     72     message_id: string,
     73     timestamp_ms: number,
     74 ): NfcMeshnetPacketChat => {
     75     return {
     76         type: "meshnet.chat.v1",
     77         message_id,
     78         profile,
     79         text,
     80         timestamp_ms,
     81     };
     82 };
     83 
     84 export const nfc_meshnet_record_from_packet = (
     85     packet: NfcMeshnetPacket,
     86 ): NfcRecordInput => {
     87     return nfc_record_json(packet, { media_type: NFC_MESHNET_MEDIA_TYPE });
     88 };
     89 
     90 export const nfc_meshnet_message_from_packet = (
     91     packet: NfcMeshnetPacket,
     92 ): NfcMessageInput => {
     93     return nfc_message_json(packet, { media_type: NFC_MESHNET_MEDIA_TYPE });
     94 };
     95 
     96 export const nfc_meshnet_packet_from_record = (
     97     record: NfcRecord,
     98 ): NfcMeshnetPacket | undefined => {
     99     if (record.record_type !== "mime") return;
    100     if (record.media_type !== NFC_MESHNET_MEDIA_TYPE) return;
    101     const text = nfc_record_data_text(record);
    102     if (!text) return;
    103     let parsed: unknown;
    104     try {
    105         parsed = JSON.parse(text);
    106     } catch {
    107         return;
    108     }
    109     if (is_packet_profile(parsed)) return parsed;
    110     if (is_packet_chat(parsed)) return parsed;
    111 };
    112 
    113 export const nfc_meshnet_packets_from_payload = (
    114     payload: NfcReadPayload,
    115 ): NfcMeshnetPacket[] => {
    116     const packets: NfcMeshnetPacket[] = [];
    117     for (const record of payload.message.records) {
    118         const packet = nfc_meshnet_packet_from_record(record);
    119         if (packet) packets.push(packet);
    120     }
    121     return packets;
    122 };