commit 9b801589beba464868597350aa08ab890581a95f
parent 398f7600d774e9c28e043070a157c458a9b60304
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Fri, 27 Dec 2024 02:20:38 +0000
utils: add/edit nostr utils. add ascii, model utils. edit regex
Diffstat:
17 files changed, 468 insertions(+), 488 deletions(-)
diff --git a/utils/.gitignore b/utils/.gitignore
@@ -27,7 +27,8 @@ yarn-error.log*
# turbo
.turbo
-_tmp
+.tmp*
+.dev*
.vscode
notes*.txt
justfile
diff --git a/utils/package.json b/utils/package.json
@@ -24,7 +24,7 @@
"convert": "^5.5.1",
"geohashing": "^2.0.1",
"nostr-geotags": "^0.7.1",
- "nostr-tools": "^2.7.2",
+ "nostr-tools": "^2.10.4",
"uuid": "^10.0.0",
"zod": "^3.23.8"
}
diff --git a/utils/src/ascii.ts b/utils/src/ascii.ts
@@ -0,0 +1,2 @@
+export const root_symbol = "»-`--,";
+export const root_symbol_full = "»--`--,---";
+\ No newline at end of file
diff --git a/utils/src/index.ts b/utils/src/index.ts
@@ -1,3 +1,4 @@
+export * from "./ascii"
export * from "./currency"
export * from "./error"
export * from "./file"
@@ -6,11 +7,13 @@ export * from "./geolocation"
export * from "./hash"
export * from "./list"
export * from "./math"
-export * from "./nostr/geotags"
-export * from "./nostr/lib"
-export * from "./nostr/lib2"
-export * from "./nostr/ndk"
-export * from "./nostr/types"
+export * from "./model"
+export * from "./nostr-event-util/lib"
+export * from "./nostr-event-util/types"
+export * from "./nostr-key-util/lib"
+export * from "./nostr-key-util/types"
+export * from "./nostr-relay-util/lib"
+export * from "./nostr-relay-util/types"
export * from "./object"
export * from "./regex"
export * from "./time"
diff --git a/utils/src/model.ts b/utils/src/model.ts
@@ -0,0 +1,20 @@
+export type IModelsQueryValue = string | number | boolean;
+export type IModelsQueryBindValue = string | number | boolean | null;
+export type IModelsQueryBindValueTuple = [string, IModelsQueryBindValue];
+export type IModelsQueryBindValueOpt = (IModelsQueryBindValue | null);
+export type IModelsSortCreatedAt = 'newest' | 'oldest';
+export type IModelsQueryParam = { query: string; bind_values: IModelsQueryBindValue[] };
+export type IModelsFormErrorTuple = [boolean, string];
+export type IModelsFormValidationTuple = [RegExp, string];
+export type IModelsSchemaErrors = { err_s: string[]; };
+export type IModelsForm = {
+ label?: string;
+ placeholder?: string;
+ validateKeypress?: boolean;
+ preventFocusRest?: boolean;
+ validation: RegExp;
+ charset: RegExp;
+ hidden?: boolean;
+ optional?: boolean;
+ default?: string | number;
+};
diff --git a/utils/src/nostr-event-util/lib.ts b/utils/src/nostr-event-util/lib.ts
@@ -0,0 +1,113 @@
+import { schnorr } from '@noble/curves/secp256k1';
+import { hexToBytes } from "@noble/hashes/utils";
+import { type NDKEvent } from "@nostr-dev-kit/ndk";
+import ngeotags, { type GeoTags as NostrGeotagsGeotags, type InputData as NostrGeotagsInputData } from "nostr-geotags";
+import { finalizeEvent, getEventHash, nip19, type NostrEvent as NostrToolsEvent } from "nostr-tools";
+import { uuidv4 } from "..";
+import type { INostrEventUtil, INostrEventUtilEventSign, INostrEventUtilFormatTagsBasisNip99, INostrEventUtilNeventEncode, NostrEventTagClient, NostrEventTagLocation, NostrEventTagMediaUpload, NostrEventTagPrice, NostrEventTagQuantity } from "./types";
+
+export class NostrEventUtil implements INostrEventUtil {
+ public first_tag_value = (event: NDKEvent, tag_name: string): string => {
+ const tag = event.getMatchingTags(tag_name)[0];
+ return tag ? tag[1] : "";
+ }
+
+ private fmt_tag_price = (opts: NostrEventTagPrice): string[] => {
+ const tag = [`price`, opts.amt, opts.currency, opts.qty_amt, opts.qty_unit];
+ return tag;
+ };
+
+
+ private fmt_tag_quantity = (opts: NostrEventTagQuantity): string[] => {
+ const tag = [`quantity`, opts.amt, opts.unit];
+ if (opts.label) tag.push(opts.label);
+ return tag;
+ };
+
+ private fmt_tag_location = (opts: NostrEventTagLocation): string[] => {
+ const tag = [`location`];
+ if (opts.city) tag.push(opts.city);
+ if (opts.region_code && !isNaN(parseInt(opts.region_code))) tag.push(opts.region_code);
+ else if (opts.region) tag.push(opts.region); //@todo
+ if (opts.country_code) tag.push(opts.country_code);
+ return tag;
+ };
+
+ private fmt_tag_image = (opts: NostrEventTagMediaUpload): string[] => {
+ const tag = [`image`, opts.url];
+ if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`)
+ return tag;
+ };
+
+ private fmt_tag_client = (opts: NostrEventTagClient, d_tag?: string): string[] => {
+ const tag = [`client`, opts.name];
+ if (d_tag) tag.push(`31990:${opts.pubkey}:${d_tag}`);
+ tag.push(opts.relay);
+ return tag;
+ };
+
+ private fmt_tag_geotags = (opts: NostrEventTagLocation): NostrGeotagsGeotags[] => {
+ const data: NostrGeotagsInputData = {
+ lat: opts.lat,
+ lon: opts.lng,
+ city: opts.city,
+ regionName: opts.region,
+ countryName: opts.country,
+ countryCode: opts.country_code
+ };
+ return ngeotags(data, {
+ geohash: true,
+ gps: true,
+ city: true,
+ iso31662: true,
+ });
+ };
+
+ public fmt_tags_basis_nip99 = (opts: INostrEventUtilFormatTagsBasisNip99): string[][] => {
+ const { d_tag, listing, quantity, price, location } = opts;
+ const tags: string[][] = [[`d`, d_tag]];
+ if (opts.client) tags.push(this.fmt_tag_client(opts.client, opts.d_tag));
+ for (const [k, v] of Object.entries(listing)) if (v) tags.push([k, v]);
+ tags.push(this.fmt_tag_quantity(quantity));
+ tags.push(this.fmt_tag_price(price));
+ tags.push(this.fmt_tag_location(location));
+ if (opts.images) for (const image of opts.images) tags.push(this.fmt_tag_image(image));
+ tags.push(...this.fmt_tag_geotags(location));
+ return tags;
+ };
+
+ public nostr_event_sign = (opts: INostrEventUtilEventSign): NostrToolsEvent => {
+ return finalizeEvent(opts.event, hexToBytes(opts.secret_key))
+ };
+
+ public nostr_event_sign_attest = (secret_key: string): NostrToolsEvent => {
+ return this.nostr_event_sign({
+ secret_key,
+ event: {
+ kind: 1,
+ created_at: Math.floor(Date.now() / 1000),
+ tags: [],
+ content: uuidv4(),
+ },
+ });
+ };
+
+ public nostr_event_verify = (event: NostrToolsEvent): boolean => {
+ const hash = getEventHash(event);
+ if (hash !== event.id) return false
+ const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ return valid;
+ };
+
+ public nostr_event_verify_serialized = (event_serialized: string): boolean => {
+ const event = JSON.parse(event_serialized);
+ const hash = getEventHash(event);
+ if (hash !== event.id) return false
+ const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ return valid;
+ };
+
+ public nevent_encode = (opts: INostrEventUtilNeventEncode): string => {
+ return nip19.neventEncode(opts);
+ };
+}
+\ No newline at end of file
diff --git a/utils/src/nostr-event-util/types.ts b/utils/src/nostr-event-util/types.ts
@@ -0,0 +1,84 @@
+import { NDKEvent } from "@nostr-dev-kit/ndk";
+import { type NostrEvent as NostrToolsEvent, type EventTemplate as NostrToolsEventTemplate } from "nostr-tools";
+
+export type INostrEventUtilFormatTagsBasisNip99 = {
+ d_tag: string;
+ listing: NostrEventTagListing;
+ quantity: NostrEventTagQuantity;
+ price: NostrEventTagPrice;
+ location: NostrEventTagLocation;
+ images?: NostrEventTagMediaUpload[];
+ client?: NostrEventTagClient;
+};
+
+export type INostrEventUtilNeventEncode = {
+ id: string;
+ relays: string[];
+ author: string;
+ kind: number;
+};
+
+export type INostrEventUtilEventSign = {
+ secret_key: string;
+ event: NostrToolsEventTemplate;
+}
+
+export type INostrEventUtil = {
+ first_tag_value(event: NDKEvent, tag_name: string): string;
+ fmt_tags_basis_nip99: (opts: INostrEventUtilFormatTagsBasisNip99) => string[][];
+ nostr_event_sign: (opts: INostrEventUtilEventSign) => NostrToolsEvent;
+ nostr_event_sign_attest: (secret_key: string) => NostrToolsEvent;
+ nostr_event_verify_serialized: (event_serialized: string) => boolean;
+ nostr_event_verify: (event: NostrToolsEvent) => boolean;
+ nevent_encode: (opts: INostrEventUtilNeventEncode) => string;
+};
+
+export type NostrEventTagListing = {
+ key: string;
+ title: string;
+ category: string;
+ summary?: string;
+ process?: string;
+ lot?: string;
+ location?: string;
+ profile?: string;
+ year?: string;
+};
+
+export type NostrEventTagPrice = {
+ amt: string;
+ currency: string;
+ qty_amt: string;
+ qty_unit: string;
+};
+
+export type NostrEventTagQuantity = {
+ amt: string;
+ unit: string;
+ label?: string;
+};
+
+export type NostrEventTagLocation = {
+ city?: string;
+ region?: string;
+ region_code?: string;
+ country?: string;
+ country_code?: string;
+ lat: number;
+ lng: number;
+ geohash: string;
+};
+
+export type NostrEventTagMediaUpload = {
+ url: string;
+ size?: {
+ w: number;
+ h: number;
+ };
+};
+
+export type NostrEventTagClient = {
+ name: string;
+ pubkey: string;
+ relay: string;
+};
diff --git a/utils/src/nostr-key-util/lib.ts b/utils/src/nostr-key-util/lib.ts
@@ -0,0 +1,148 @@
+import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
+import { generateSecretKey, getPublicKey, nip19 } from 'nostr-tools';
+import type { INostrKeyUtil } from './types';
+
+export class NostrKeyUtil implements INostrKeyUtil {
+ private generate_key_bytes(): Uint8Array {
+ const secret_key = generateSecretKey();
+ return secret_key;
+ };
+
+ private get_key_hex(bytes: Uint8Array): string {
+ const hex = bytesToHex(bytes);
+ return hex;
+ };
+
+ private get_key_bytes(hex: string): Uint8Array {
+ const bytes = hexToBytes(hex);
+ return bytes;
+ };
+
+ /**
+ *
+ * @returns nostr secret key hex
+ */
+ public generate_key(): string {
+ const bytes = this.generate_key_bytes();
+ const hex = this.get_key_hex(bytes);
+ return hex;
+ };
+
+ /**
+ *
+ * @returns nostr public key hex
+ */
+ public public_key(secret_key_hex: string | undefined): string {
+ try {
+ if (!secret_key_hex) return ``;
+ const bytes = this.get_key_bytes(secret_key_hex);
+ const hex = getPublicKey(bytes)
+ return hex;
+ } catch (e) {
+ return ``
+ }
+ }
+
+ /**
+ *
+ * @returns nostr secret key to public key hex
+ */
+ public publickey_decode(secret_key_hex?: string): string | undefined {
+ try {
+ if (secret_key_hex) {
+ return getPublicKey(this.get_key_bytes(secret_key_hex))
+ }
+ return undefined;
+ } catch (e) {
+ return undefined;
+ }
+ }
+
+ /**
+ *
+ * @returns nostr public key npub
+ */
+ public npub(public_key_hex: string | undefined, fallback_to_hex?: boolean): string {
+ if (!public_key_hex) return ``;
+ const npub = nip19.npubEncode(public_key_hex);
+ return npub ? npub : fallback_to_hex ? public_key_hex : ``;
+ }
+
+ /**
+ *
+ * @returns public key hex from npub
+ */
+ public npub_decode(npub: string): string {
+ const decode = nip19.decode(npub);
+ console.log(`decode `, decode)
+ if (decode && decode.type === `npub` && decode.data) return decode.data
+ return ``;
+ }
+
+ /**
+ *
+ * @returns nostr secret key nsec
+ */
+ public nsec(secret_key_hex: string | undefined): string {
+ if (!secret_key_hex) return ``;
+ const bytes = this.get_key_bytes(secret_key_hex);
+ const nsec = nip19.nsecEncode(bytes);
+ return nsec;
+ }
+
+ /**
+ *
+ * @returns nostr secret key hex from nsec
+ */
+ public nsec_decode(nsec: string): string | undefined {
+ try {
+ if (!nsec) return undefined;
+ const decode = nip19.decode(nsec);
+ if (decode && decode.type === `nsec` && decode.data) return bytesToHex(decode.data);
+ return undefined;
+ } catch (e) {
+ return undefined;
+ }
+ }
+
+ /**
+ *
+ * @returns
+ */
+ public nevent(event_pointer: nip19.EventPointer, relays: string[]): string {
+ return nip19.neventEncode(event_pointer)
+ }
+
+ /**
+ *
+ * @returns nostr public key nprofile
+ */
+ public nprofile(public_key_hex: string, relays: string[]): string {
+ if (!public_key_hex || !relays.length) return ``;
+ return nip19.nprofileEncode({ pubkey: public_key_hex, relays })
+ }
+
+ /**
+ *
+ * @returns nostr public key nprofile
+ */
+ public nprofile_decode(nprofile: string): [string, string[]] | undefined {
+ if (!nprofile) return undefined;
+ const decode = nip19.decode(nprofile);
+ if (decode && decode.type === `nprofile` && decode.data && decode.data.pubkey && decode.data.relays) return [decode.data.pubkey, decode.data.relays]
+ return undefined;
+ }
+
+ /**
+ *
+ * @returns
+ */
+ public secretkey_to_publickey(nsec_or_hex: string): string | undefined {
+ if (nsec_or_hex.startsWith(`nsec1`)) {
+ return this.nsec_decode(nsec_or_hex);
+ } else if (nsec_or_hex.length === 64) {
+ return this.publickey_decode(nsec_or_hex)
+ }
+ return undefined;
+ }
+};
diff --git a/utils/src/nostr-key-util/types.ts b/utils/src/nostr-key-util/types.ts
@@ -0,0 +1,11 @@
+export type INostrKeyUtil = {
+ generate_key(): string;
+ public_key(secret_key_hex: string | undefined): string;
+ npub(public_key_hex: string | undefined): string;
+ npub_decode(npub: string): string;
+ nsec(secret_key_hex: string | undefined): string;
+ nsec_decode(nsec: string): string | undefined;
+ nprofile(public_key_hex: string, relays: string[]): string;
+ nprofile_decode(nprofile: string): [string, string[]] | undefined;
+ secretkey_to_publickey(nsec_or_hex: string): string | undefined;
+};
diff --git a/utils/src/nostr-relay-util/lib.ts b/utils/src/nostr-relay-util/lib.ts
@@ -0,0 +1,45 @@
+import { type NDKEvent } from "@nostr-dev-kit/ndk";
+import type { INostrRealyUtil, NostrRelayInformationDocument, NostrRelayInformationDocumentFormFields } from "./types";
+
+export class NostrRelayUtil implements INostrRealyUtil {
+ public first_tag_value(event: NDKEvent, tag_name: string): string {
+ const tag = event.getMatchingTags(tag_name)[0];
+ return tag ? tag[1] : "";
+ }
+
+ private parse_nostr_relay_information_document = (data: any): NostrRelayInformationDocument | undefined => {
+ const obj = JSON.parse(data);
+ return {
+ id: typeof obj.id === 'string' ? obj.id : undefined,
+ name: typeof obj.name === 'string' ? obj.name : undefined,
+ description: typeof obj.description === 'string' ? obj.description : undefined,
+ pubkey: typeof obj.pubkey === 'string' ? obj.pubkey : undefined,
+ contact: typeof obj.contact === 'string' ? obj.contact : undefined,
+ supported_nips: Array.isArray(obj.supported_nips) && obj.supported_nips.every((nip: any) => typeof nip === 'number')
+ ? obj.supported_nips
+ : undefined,
+ software: typeof obj.software === 'string' ? obj.software : undefined,
+ version: typeof obj.version === 'string' ? obj.version : undefined,
+ limitation_payment_required: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.payment_required === 'string' ? obj.limitation.payment_required : undefined,
+ limitation_restricted_writes: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.restricted_writes === 'boolean' ? obj.limitation.restricted_writes : undefined,
+ };
+ };
+
+ public parse_nostr_relay_information_document_fields = (data: any): NostrRelayInformationDocumentFormFields | undefined => {
+ const info_doc = this.parse_nostr_relay_information_document(data);
+ if (!info_doc) return;
+ const result: Partial<NostrRelayInformationDocumentFormFields> = {};
+ Object.entries(info_doc).forEach(([key, value]) => {
+ if (typeof value === 'boolean') {
+ result[key as keyof NostrRelayInformationDocument] = value ? '1' : '0';
+ } else if (Array.isArray(value)) {
+ result[key as keyof NostrRelayInformationDocument] = value.join(', ');
+ } else if (value === null || value === undefined) {
+ result[key as keyof NostrRelayInformationDocument] = '';
+ } else {
+ result[key as keyof NostrRelayInformationDocument] = String(value);
+ }
+ });
+ return result;
+ };
+}
+\ No newline at end of file
diff --git a/utils/src/nostr-relay-util/types.ts b/utils/src/nostr-relay-util/types.ts
@@ -0,0 +1,21 @@
+import { NDKEvent } from "@nostr-dev-kit/ndk";
+
+export type INostrRealyUtil = {
+ first_tag_value(event: NDKEvent, tag_name: string): string;
+ parse_nostr_relay_information_document_fields: (data: any) => NostrRelayInformationDocumentFormFields | undefined;
+};
+
+export type NostrRelayInformationDocument = {
+ id?: string;
+ name?: string;
+ description?: string;
+ pubkey?: string;
+ contact?: string;
+ supported_nips?: number[];
+ software?: string;
+ version?: string;
+ limitation_payment_required?: string;
+ limitation_restricted_writes?: boolean;
+}
+
+export type NostrRelayInformationDocumentFormFields = { [K in keyof NostrRelayInformationDocument]: string; };
diff --git a/utils/src/nostr/geotags.ts b/utils/src/nostr/geotags.ts
@@ -1,21 +0,0 @@
-import ngeotags, { type GeoTags, type InputData, type Options } from 'nostr-geotags';
-import type { NostrTagLocation } from './types';
-
-const options: Options = {
- geohash: true,
- gps: true,
- city: true,
- iso31662: true,
-};
-
-export const fmt_tag_geotags = (opts: NostrTagLocation): GeoTags[] => {
- const data: InputData = {
- lat: opts.lat,
- lon: opts.lng,
- city: opts.city,
- regionName: opts.region,
- countryName: opts.country,
- countryCode: opts.country_code
- };
- return ngeotags(data, options)
-};
-\ No newline at end of file
diff --git a/utils/src/nostr/lib.ts b/utils/src/nostr/lib.ts
@@ -1,155 +0,0 @@
-import { schnorr } from '@noble/curves/secp256k1';
-import { hexToBytes } from '@noble/hashes/utils';
-import { type EventTemplate, finalizeEvent, getEventHash, nip19, type NostrEvent } from "nostr-tools";
-import { uuidv4 } from '../uuid';
-import { fmt_tag_geotags } from './geotags';
-import type { NostrRelayInformationDocument, NostrRelayInformationDocumentFormFields, NostrTagClient, NostrTagListing, NostrTagLocation, NostrTagMediaUpload, NostrTagPrice, NostrTagQuantity } from "./types";
-
-export const parse_nostr_relay_information_document = (data: any): NostrRelayInformationDocument | undefined => {
- const obj = JSON.parse(data);
- return {
- id: typeof obj.id === 'string' ? obj.id : undefined,
- name: typeof obj.name === 'string' ? obj.name : undefined,
- description: typeof obj.description === 'string' ? obj.description : undefined,
- pubkey: typeof obj.pubkey === 'string' ? obj.pubkey : undefined,
- contact: typeof obj.contact === 'string' ? obj.contact : undefined,
- supported_nips: Array.isArray(obj.supported_nips) && obj.supported_nips.every((nip: any) => typeof nip === 'number')
- ? obj.supported_nips
- : undefined,
- software: typeof obj.software === 'string' ? obj.software : undefined,
- version: typeof obj.version === 'string' ? obj.version : undefined,
- limitation_payment_required: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.payment_required === 'string' ? obj.limitation.payment_required : undefined,
- limitation_restricted_writes: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.restricted_writes === 'boolean' ? obj.limitation.restricted_writes : undefined,
- };
-};
-
-export const parse_nostr_relay_information_document_fields = (data: any): NostrRelayInformationDocumentFormFields | undefined => {
- const info_doc = parse_nostr_relay_information_document(data);
- if (!info_doc) return;
- const result: Partial<NostrRelayInformationDocumentFormFields> = {};
- Object.entries(info_doc).forEach(([key, value]) => {
- if (typeof value === 'boolean') {
- result[key as keyof NostrRelayInformationDocument] = value ? '1' : '0';
- } else if (Array.isArray(value)) {
- result[key as keyof NostrRelayInformationDocument] = value.join(', ');
- } else if (value === null || value === undefined) {
- result[key as keyof NostrRelayInformationDocument] = '';
- } else {
- result[key as keyof NostrRelayInformationDocument] = String(value);
- }
- });
- return result;
-};
-
-
-export const fmt_tag_price = (opts: NostrTagPrice): string[] => {
- const tag = [`price`, opts.amt, opts.currency, opts.qty_amt, opts.qty_unit];
- return tag;
-};
-
-
-export const fmt_tag_quantity = (opts: NostrTagQuantity): string[] => {
- const tag = [`quantity`, opts.amt, opts.unit];
- if (opts.label) tag.push(opts.label);
- return tag;
-};
-
-
-export const fmt_tag_location = (opts: NostrTagLocation): string[] => {
- const tag = [`location`];
- if (opts.city) tag.push(opts.city);
- if (opts.region_code && !isNaN(parseInt(opts.region_code))) tag.push(opts.region_code);
- else if (opts.region) tag.push(opts.region); //@todo
- if (opts.country_code) tag.push(opts.country_code);
- return tag;
-};
-
-export const fmt_tag_image = (opts: NostrTagMediaUpload): string[] => {
- const tag = [`image`, opts.url];
- if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`)
- return tag;
-};
-
-export const fmt_tag_client = (opts: NostrTagClient, d_tag?: string): string[] => {
- const tag = [`client`, opts.name];
- if (d_tag) tag.push(`31990:${opts.pubkey}:${d_tag}`);
- tag.push(opts.relay);
- return tag;
-};
-
-export const fmt_tags_basis_nip99 = (opts: {
- d_tag: string;
- listing: NostrTagListing;
- quantity: NostrTagQuantity;
- price: NostrTagPrice;
- location: NostrTagLocation;
- images?: NostrTagMediaUpload[];
- client?: NostrTagClient;
-}): string[][] => {
- const { d_tag, listing, quantity, price, location } = opts;
- const tags: string[][] = [
- [`d`, d_tag]
- ];
- if (opts.client) tags.push(fmt_tag_client(opts.client, opts.d_tag));
- for (const [k, v] of Object.entries(listing)) if (v) tags.push([k, v]);
- tags.push(fmt_tag_quantity(quantity));
- tags.push(fmt_tag_price(price));
- tags.push(fmt_tag_location(location));
- if (opts.images) for (const image of opts.images) tags.push(fmt_tag_image(image));
- tags.push(...fmt_tag_geotags(location));
- return tags;
-};
-
-export const nostr_event_sign = (opts: {
- secret_key: string;
- event: EventTemplate;
-}): NostrEvent => {
- return finalizeEvent(opts.event, hexToBytes(opts.secret_key))
-};
-
-export const nostr_event_sign_attest = (secret_key: string): NostrEvent => {
- return nostr_event_sign({
- secret_key,
- event: {
- kind: 1,
- created_at: Math.floor(Date.now() / 1000),
- tags: [],
- content: uuidv4(),
- },
- });
-};
-
-
-export const nostr_event_verify = async (event: NostrEvent): Promise<boolean> => {
- try {
- const hash = getEventHash(event);
- console.log(`hash `, hash)
- if (hash !== event.id) return false
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
- return valid;
- } catch {
- return false;
- }
-};
-
-export const nostr_event_verify_serialized = async (event_serialized: string): Promise<boolean> => {
- try {
- const event = JSON.parse(event_serialized);
- const hash = getEventHash(event);
- console.log(`hash `, hash)
- if (hash !== event.id) return false
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
- return valid;
- } catch {
- return false;
- }
-};
-
-export const nevent_encode = (opts: {
- id: string;
- relays: string[];
- author: string;
- kind: number;
-}): string => {
- return nip19.neventEncode(opts)
-};
-\ No newline at end of file
diff --git a/utils/src/nostr/lib2.ts b/utils/src/nostr/lib2.ts
@@ -1,147 +0,0 @@
-import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
-import { generateSecretKey, getPublicKey, nip19 } from 'nostr-tools';
-
-export class ClientNostrLib2 {
- private generate_key_bytes(): Uint8Array {
- const secret_key = generateSecretKey();
- return secret_key;
- };
-
- private get_key_hex(bytes: Uint8Array): string {
- const hex = bytesToHex(bytes);
- return hex;
- };
-
- private get_key_bytes(hex: string): Uint8Array {
- const bytes = hexToBytes(hex);
- return bytes;
- };
-
- /**
- *
- * @returns nostr secret key hex
- */
- public generate_key(): string {
- const bytes = this.generate_key_bytes();
- const hex = this.get_key_hex(bytes);
- return hex;
- };
-
- /**
- *
- * @returns nostr public key hex
- */
- public public_key(secret_key_hex: string | undefined): string {
- try {
- if (!secret_key_hex) return ``;
- const bytes = this.get_key_bytes(secret_key_hex);
- const hex = getPublicKey(bytes)
- return hex;
- } catch (e) {
- return ``
- }
- }
-
- /**
- *
- * @returns nostr secret key to public key hex
- */
- public publickey_decode(secret_key_hex?: string): string | undefined {
- try {
- if (secret_key_hex) {
- return getPublicKey(this.get_key_bytes(secret_key_hex))
- }
- return undefined;
- } catch (e) {
- return undefined;
- }
- }
-
- /**
- *
- * @returns nostr public key npub
- */
- public npub(public_key_hex: string | undefined, fallback_to_hex?: boolean): string {
- if (!public_key_hex) return ``;
- const npub = nip19.npubEncode(public_key_hex);
- return npub ? npub : fallback_to_hex ? public_key_hex : ``;
- }
-
- /**
- *
- * @returns public key hex from npub
- */
- public npub_decode(npub: string): string {
- const decode = nip19.decode(npub);
- console.log(`decode `, decode)
- if (decode && decode.type === `npub` && decode.data) return decode.data
- return ``;
- }
-
- /**
- *
- * @returns nostr secret key nsec
- */
- public nsec(secret_key_hex: string | undefined): string {
- if (!secret_key_hex) return ``;
- const bytes = this.get_key_bytes(secret_key_hex);
- const nsec = nip19.nsecEncode(bytes);
- return nsec;
- }
-
- /**
- *
- * @returns nostr secret key hex from nsec
- */
- public nsec_decode(nsec: string): string | undefined {
- try {
- if (!nsec) return undefined;
- const decode = nip19.decode(nsec);
- if (decode && decode.type === `nsec` && decode.data) return bytesToHex(decode.data);
- return undefined;
- } catch (e) {
- return undefined;
- }
- }
-
- /**
- *
- * @returns
- */
- public nevent(event_pointer: nip19.EventPointer, relays: string[]): string {
- return nip19.neventEncode(event_pointer)
- }
-
- /**
- *
- * @returns nostr public key nprofile
- */
- public nprofile(public_key_hex: string, relays: string[]): string {
- if (!public_key_hex || !relays.length) return ``;
- return nip19.nprofileEncode({ pubkey: public_key_hex, relays })
- }
-
- /**
- *
- * @returns nostr public key nprofile
- */
- public nprofile_decode(nprofile: string): [string, string[]] | undefined {
- if (!nprofile) return undefined;
- const decode = nip19.decode(nprofile);
- if (decode && decode.type === `nprofile` && decode.data && decode.data.pubkey && decode.data.relays) return [decode.data.pubkey, decode.data.relays]
- return undefined;
- }
-
- /**
- *
- * @returns
- */
- public secretkey_to_publickey(nsec_or_hex: string): string | undefined {
- if (nsec_or_hex.startsWith(`nsec1`)) {
- return this.nsec_decode(nsec_or_hex);
- } else if (nsec_or_hex.length === 64) {
- return this.publickey_decode(nsec_or_hex)
- }
- return undefined;
- }
-};
diff --git a/utils/src/nostr/ndk.ts b/utils/src/nostr/ndk.ts
@@ -1,75 +0,0 @@
-import NDK, { NDKEvent, NDKKind, NDKPrivateKeySigner, NDKUser } from '@nostr-dev-kit/ndk';
-import { time_now_ms } from '../time';
-import type { NostrKind0Metadata } from './types';
-
-export const ndk_init = async (opts: {
- $ndk: NDK;
- secret_key: string;
-}): Promise<NDKUser | undefined> => {
- try {
- const { $ndk: ndk, secret_key } = opts;
- const signer = new NDKPrivateKeySigner(secret_key);
- ndk.signer = signer;
-
- const user = await signer.user();
- if (user) {
- user.ndk = ndk;
- return user;
- }
- } catch (e) {
- console.log(`(error) ndk_init `, e);
- };
-};
-
-export const ndk_event_metadata = async (opts: {
- $ndk: NDK;
- $ndk_user: NDKUser;
- metadata: NostrKind0Metadata
-}): Promise<NDKEvent | undefined> => {
- try {
- const { $ndk, $ndk_user } = opts;
- const ev = await ndk_event({
- $ndk,
- $ndk_user,
- basis: {
- kind: NDKKind.Metadata,
- content: JSON.stringify(opts.metadata),
- },
- });
- return ev;
- } catch (e) {
- console.log(`(error) ndk_event_metadata `, e);
- }
-};
-
-export const ndk_event = async (opts: {
- $ndk: NDK;
- $ndk_user: NDKUser;
- basis: {
- kind: number;
- content: string;
- tags?: string[][];
- }
-}): Promise<NDKEvent | undefined> => {
- try {
- const { $ndk: ndk, $ndk_user: ndk_user, basis } = opts;
- const time_now = time_now_ms();
-
- const tags: string[][] = [
- ['published_at', time_now.toString()],
- ];
-
- if (basis.tags && basis.tags?.length > 0) for (const tag of basis.tags) tags.push(tag);
-
- const event: NDKEvent = new NDKEvent(ndk, {
- kind: basis.kind,
- pubkey: ndk_user.pubkey,
- content: basis.content,
- created_at: time_now,
- tags
- });
- return event;
- } catch (e) {
- console.log(`(error) ndk_event `, e);
- };
-};
diff --git a/utils/src/nostr/types.ts b/utils/src/nostr/types.ts
@@ -1,77 +0,0 @@
-export type NostrRelayInformationDocument = {
- id?: string;
- name?: string;
- description?: string;
- pubkey?: string;
- contact?: string;
- supported_nips?: number[];
- software?: string;
- version?: string;
- limitation_payment_required?: string;
- limitation_restricted_writes?: boolean;
-}
-
-export type NostrRelayInformationDocumentFormFields = { [K in keyof NostrRelayInformationDocument]: string; };
-
-export type NostrTagListing = {
- key: string;
- title: string;
- category: string;
- summary?: string;
- process?: string;
- lot?: string;
- location?: string;
- profile?: string;
- year?: string;
-};
-
-export type NostrTagPrice = {
- amt: string;
- currency: string;
- qty_amt: string;
- qty_unit: string;
-};
-
-export type NostrTagQuantity = {
- amt: string;
- unit: string;
- label?: string;
-};
-
-export type NostrTagLocation = {
- city?: string;
- region?: string;
- region_code?: string;
- country?: string;
- country_code?: string;
- lat: number;
- lng: number;
- geohash: string;
-};
-
-export type NostrTagMediaUpload = {
- url: string;
- size?: {
- w: number;
- h: number;
- };
-};
-
-export type NostrTagClient = {
- name: string;
- pubkey: string;
- relay: string;
-};
-
-export type NostrKind0Metadata = {
- name?: string;
- display_name?: string;
- about?: string;
- website?: string;
- picture?: string;
- banner?: string;
- nip05?: string;
- lud06?: string;
- lud16?: string;
- bot?: boolean;
-};
-\ No newline at end of file
diff --git a/utils/src/regex.ts b/utils/src/regex.ts
@@ -1,4 +1,8 @@
export const regex = {
+ float: /^[+-]?(\d+(\.\d*)?|\.\d+)$/,
+ float_ch: /^[0-9\.\+\-]$/,
+ float_pos: /^\d+(\.\d+)?$/,
+ float_pos_ch: /^[0-9\.]$/,
description: /^(?:\S+(?:\s+\S+)*)$/,
description_ch: /[^a-zA-Z0-9.,!?;:'"(){}[]\s\u0600-\u06FF\u0900-\u097F\u0400-\u04FF\u0500-\u052F\u1F00-\u1FFF\u4E00-\u9FFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF ]+/,
nbsp: /[\u00A0]/g,
@@ -11,9 +15,12 @@ export const regex = {
alpha: /[a-zA-Z ]$/,
alpha_ch: /[a-zA-Z ]$/,
num: /^[0-9]+$/,
+ lat: /^[-+]?([1-8]?[0-9](\.\d{1,6})?|90(\.0{1,6})?)$/,
+ lat_ch: /^[\d\.\+\-]$/,
+ lng: /^[-+]?((1[0-7]?[0-9]|180)(\.\d{1,6})?|(\d{1,2})(\.\d{1,6})?)$/,
+ lng_ch: /^[\d\.\+\-]$/,
alphanum: /[a-zA-Z0-9., ]$/,
alphanum_ch: /[a-zA-Z0-9.,\s\u0600-\u06FF\u0900-\u097F\u0400-\u04FF\u0500-\u052F\u1F00-\u1FFF\u4E00-\u9FFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF ]+/,
- ///[a-zA-Z0-9., ]/,
price: /^\d+(\.\d+)?$/,
price_ch: /[0-9.]$/,
profile_name: /^[a-zA-Z0-9._]{3,30}$/,
@@ -21,6 +28,6 @@ export const regex = {
trade_product_key: /^(?:[a-zA-Z0-9]+(?:\s+[a-zA-Z0-9]+){0,2})$/,
trade_product_category: /^(?:[a-zA-Z0-9]+(?:\s+[a-zA-Z0-9]+){0,2})$/,
currency_symbol: /(?:[A-Za-z]{3,5}\$|\p{Sc})/u,
- currency_marker: /(?:[A-Za-z]{2,4}[^\d\s]+|[^\d\s]{1,3}[A-Za-z]{2,4})/
- ///(?:[A-Za-z]{2,4}\$|\$(?=[A-Za-z]{2,4}$))/
+ currency_marker: /(?:[A-Za-z]{2,4}[^\d\s]+|[^\d\s]{1,3}[A-Za-z]{2,4})/,
+ ws_proto: /^(wss:\/\/|ws:\/\/)/,
};