From 2f102248fbcaeb84ce6de41779b90b79937362c1 Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Tue, 23 Apr 2024 10:04:11 -0500 Subject: [PATCH 1/4] added js doc and refactored some terms --- nhgc/jsr.json | 2 +- nhgc/kv.ts | 8 +-- nhgc/mod.ts | 11 +++ nhgc/types.ts | 189 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 199 insertions(+), 11 deletions(-) diff --git a/nhgc/jsr.json b/nhgc/jsr.json index f003797..b4029d9 100644 --- a/nhgc/jsr.json +++ b/nhgc/jsr.json @@ -1,5 +1,5 @@ { "name": "@synadiaorbit/nhgc", - "version": "0.0.1", + "version": "0.0.2", "exports": "./mod.ts" } diff --git a/nhgc/kv.ts b/nhgc/kv.ts index b5f2110..20a3e4c 100644 --- a/nhgc/kv.ts +++ b/nhgc/kv.ts @@ -19,7 +19,7 @@ import { KvEntry, KvWatchFn, KvWatchOpts, - Operation, + KvOperation, ReviverFn, toKvChangeEvent, Value, @@ -33,7 +33,7 @@ type KvE = { created: string; revision: number; delta: number; - operation: Operation; + operation: KvOperation; value: Uint8Array; }; @@ -65,7 +65,7 @@ class KvEntryImpl implements KvEntry { created: r.headers.get("X-Nats-Kv-Created") || "", revision: parseInt(r.headers.get("X-Nats-Kv-Revision") || "0"), delta: parseInt(r.headers.get("X-Nats-Kv-Delta") || "0"), - operation: r.headers.get("X-Nats-Kv-Operation") as Operation, + operation: r.headers.get("X-Nats-Kv-Operation") as KvOperation, value, }; return Promise.resolve(new KvEntryImpl(kve)); @@ -76,7 +76,7 @@ class KvEntryImpl implements KvEntry { return this.entry.value; } - get operation(): Operation { + get operation(): KvOperation { return this.entry.operation; } diff --git a/nhgc/mod.ts b/nhgc/mod.ts index 8f39301..46bfc7b 100644 --- a/nhgc/mod.ts +++ b/nhgc/mod.ts @@ -15,10 +15,21 @@ import { Kvm } from "./types.ts"; import { KvmImpl } from "./kvm.ts"; +/** + * Interface to the API of the NHG + */ export interface NHG { + /** + * Return an object that you can use to manage or access + * KeyValue stores. + */ kvm: Kvm; } +/** + * Creates a client for the Nats-Http-Gateway. + * @param opts + */ export function newNHG( opts: { url: string; apiKey: string }, ): NHG { diff --git a/nhgc/types.ts b/nhgc/types.ts index 2ad0962..02dbd97 100644 --- a/nhgc/types.ts +++ b/nhgc/types.ts @@ -12,9 +12,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/** + * Value represents a payload type value. Can be a string, Uint8Array or a ReadableStream. + */ export type Value = string | Uint8Array | ReadableStream; -export type Operation = "PUT" | "DEL" | "PURGE"; + export function toKvChangeEvent(m: MessageEvent): KvChangeEvent { // deno-lint-ignore no-explicit-any @@ -26,31 +29,60 @@ export function toKvChangeEvent(m: MessageEvent): KvChangeEvent { }) as KvChangeEvent; } +/** + * KvOperation types operations recorded by the KV, such as "PUT", "DEL" or "PURGE" + */ +export type KvOperation = "PUT" | "DEL" | "PURGE"; + +/** + * KvChangeEvent is the interface of events for a Kv Watch. + */ export interface KvChangeEvent { key: string; bucket: string; created: Date; revision: number; delta: number; - operation: Operation; + operation: KvOperation; } +/** + * KvEntryInfo describes the metadata properties for a KvEntry + */ export interface KvEntryInfo { bucket: string; created: Date; revision: number; delta: number; - operation: Operation; + operation: KvOperation; value: Uint8Array | string; } +/** + * Represents a KvEntry, note you can access data directly via KvEntryInfo properties. + */ export interface KvEntry extends KvEntryInfo { + /** + * Returns the value of the entry in string form. + */ string(): string; + + /** + * Returns the value of the entry as a JavaScript object. + * @param reviver + */ json(reviver?: ReviverFn): T; } +/** + * A ReviverFn allows you to modify the object returned by KvEntry#json() + * during JSON parsing. + */ export type ReviverFn = (key: string, value: unknown) => unknown; +/** + * Kv is the interface to a NATS Kv + */ export interface Kv { /** * Creates an entry in the KV only if it doesn't already exist. @@ -87,63 +119,208 @@ export interface Kv { */ delete(key: string, purge?: boolean): Promise; - /** */ + /** + * Purge removes all history values for an entry that has been deleted. + */ purge(): Promise; + + /** + * Keys returns a list of subjects known to be in the KV. Note that + * this operation will list entries that have been deleted (have a KvOperation "DEL"). + * @param filter + */ keys(filter?: string): Promise; + + /** + * Returns a watcher that notifies you of changes to the KV. + * @param opts + */ watch(opts: KvWatchOpts): Promise; + + /** + * Returns information about a Kv bucket. + */ info(): Promise; } +/** + * Type of describing the state of a Kv + */ export type KvBucketInfo = { + /** + * Name of the bucket + */ name: string; + /** + * The number of values (entries in the KV), will include + * values that are in history. + */ values: number; + /** + * Maximum number of history entries for a key + */ history: number; + /** + * Maximum amount of milliseconds an entry can live in the KV + */ ttl: number; + /** + * The storage type of the Kv + */ backing_store: string; + /** + * The number of bytes that the KV uses on disk + */ size: number; + /** + * True if the KV compresses values + */ compression: boolean; }; +/** + * Type describing a Kv configuration + */ export type KvBucketConfig = { + /** + * An user specified description + */ description: string; + /** + * The maximum size in bytes for an entry + */ max_value_size: number; + /** + * The maximum number of history entries per key + */ history: number; + /** + * The number of milliseconds that an entry will live (0 is forever) + */ ttl: number; + /** + * The maximum amount of storage that the KV can grow to + */ max_bytes: number; + /** + * The type of storage used by the KV + */ storage: "file" | "memory"; + /** + * The number of replicas for the KV + */ replicas: number; + /** + * Compress the KV data + */ compression: boolean; + /** + * User metadata entries + */ metadata: Record; }; -export type Include = "allHistory" | "updatesOnly" | "lastValue" | ""; +/** + * Types of data to include on when watching the Kv. + * All history will include all values and their changes recorded in history + * Updates only will only notify when there's a change in the Kv after the watch is started + * Last value will notify of the latest values for a key when the watcher starts. + * + */ +export type KvInclude = "allHistory" | "updatesOnly" | "lastValue" | ""; +/** + * Callback for the watcher + */ export type KvWatchFn = (err?: Error, e?: KvChangeEvent) => void; +/** + * Interface for interacting with a Watcher. Allows you to stop it, + * as well as get notified when it stops. + */ export interface Watcher { + /** + * Requests the watcher to stop yielding values. + */ stop(): void; + + /** + * Promise that resolves to true when the watcher stops. + */ stopped: Promise; } +/** + * Options for a Watch + */ export type KvWatchOpts = WatchOpts & { + /** + * Filter watcher to the specified key + */ filter?: string; + /** + * Resume a watch at a the specified revision. + */ resumeRevision?: number; + /** + * A callback that will get called when a value is added, updated, or deleted. + * Note that values pruned by a TTL may not get notified. + */ callback: KvWatchFn; }; export type HeartbeatOpts = { + /** + * Send a heartbeat if no values are notified within the specified time. + * This option should be left to its default (30_000 millis) unless you + * have been directed by support to use a different value. + */ idleHeartbeat?: number; }; export type WatchOpts = HeartbeatOpts & { - include?: Include; + /** + * Values to include in the updates + */ + include?: KvInclude; + /** + * If true, deletes will not be notified + */ ignoreDeletes?: boolean; }; +/** + * An interface for managing Kvs + */ export interface Kvm { + /** + * Start a context for operating on a specific Kv. Note this operation + * doesn't perform any remote calls. + * @param bucket + */ get(bucket: string): Kv; + + /** + * Add a new Kv bucket + * @param bucket + * @param config + */ add(bucket: string, config?: Partial): Promise; + + /** + * Destroy a Kv bucket + * @param bucket + */ destroy(bucket: string): Promise; + + /** + * List available Kv bucket names + */ list(): Promise; + + /** + * Get info on a Kv + * @param bucket + */ info(bucket: string): Promise; } From c57498fc604afb70b4aa42ad0e900e1383981cec Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Tue, 23 Apr 2024 10:05:09 -0500 Subject: [PATCH 2/4] fmt --- nhgc/kv.ts | 2 +- nhgc/types.ts | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/nhgc/kv.ts b/nhgc/kv.ts index 20a3e4c..1c83e40 100644 --- a/nhgc/kv.ts +++ b/nhgc/kv.ts @@ -17,9 +17,9 @@ import { Kv, KvBucketInfo, KvEntry, + KvOperation, KvWatchFn, KvWatchOpts, - KvOperation, ReviverFn, toKvChangeEvent, Value, diff --git a/nhgc/types.ts b/nhgc/types.ts index 02dbd97..cb54d8b 100644 --- a/nhgc/types.ts +++ b/nhgc/types.ts @@ -17,8 +17,6 @@ */ export type Value = string | Uint8Array | ReadableStream; - - export function toKvChangeEvent(m: MessageEvent): KvChangeEvent { // deno-lint-ignore no-explicit-any return JSON.parse(m.data, function (this: any, key: string, value: any): any { @@ -225,7 +223,6 @@ export type KvBucketConfig = { * All history will include all values and their changes recorded in history * Updates only will only notify when there's a change in the Kv after the watch is started * Last value will notify of the latest values for a key when the watcher starts. - * */ export type KvInclude = "allHistory" | "updatesOnly" | "lastValue" | ""; From 4a52f77f541ba3d19d47e209e1b24a434dcdaf13 Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Tue, 23 Apr 2024 11:55:09 -0500 Subject: [PATCH 3/4] changed to use `Authorization` instead of `X-Nats-Api-Key` as preferred token header/qs --- nhgc/kv.ts | 2 +- nhgc/nhgc.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nhgc/kv.ts b/nhgc/kv.ts index 1c83e40..187c6ef 100644 --- a/nhgc/kv.ts +++ b/nhgc/kv.ts @@ -241,7 +241,7 @@ export class KvImpl extends HttpImpl implements Kv { opts: KvWatchOpts, ): Promise { const args: string[] = []; - args.push(`X-Nats-Api-Key=${this.apiKey}`); + args.push(`authorization=${this.apiKey}`); const dopts = Object.assign({ filter: ">", diff --git a/nhgc/nhgc.ts b/nhgc/nhgc.ts index 671a204..1e690d9 100644 --- a/nhgc/nhgc.ts +++ b/nhgc/nhgc.ts @@ -50,7 +50,7 @@ export class HttpImpl implements Http { } const r = Object.assign(opts, { method, body }); const headers = new Headers(opts.headers); - headers.append("X-Nats-Api-Key", this.apiKey); + headers.append("Authorization", this.apiKey); r.headers = headers; return fetch(u, r); } From 13c3a5ea66461f6b0ccc4e9b2d78d0541a3a18f7 Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Tue, 23 Apr 2024 12:03:16 -0500 Subject: [PATCH 4/4] more jsdoc --- nhgc/types.ts | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/nhgc/types.ts b/nhgc/types.ts index cb54d8b..41d4d91 100644 --- a/nhgc/types.ts +++ b/nhgc/types.ts @@ -17,6 +17,10 @@ */ export type Value = string | Uint8Array | ReadableStream; +/** + * This function converts a MessageEvent into a KvChangeEvent + * @param m + */ export function toKvChangeEvent(m: MessageEvent): KvChangeEvent { // deno-lint-ignore no-explicit-any return JSON.parse(m.data, function (this: any, key: string, value: any): any { @@ -36,11 +40,29 @@ export type KvOperation = "PUT" | "DEL" | "PURGE"; * KvChangeEvent is the interface of events for a Kv Watch. */ export interface KvChangeEvent { + /** + * The name of the key + */ key: string; + /** + * The name of the bucket + */ bucket: string; + /** + * The created Date for the entry + */ created: Date; + /** + * The revision of the entry + */ revision: number; + /** + * The delta from the entry's revision the latest revision in the KV + */ delta: number; + /** + * The operation type of the entry + */ operation: KvOperation; } @@ -48,11 +70,29 @@ export interface KvChangeEvent { * KvEntryInfo describes the metadata properties for a KvEntry */ export interface KvEntryInfo { + /** + * The bucket storing the entry + */ bucket: string; + /** + * The created Date for the entry + */ created: Date; + /** + * The revision of the entry + */ revision: number; + /** + * The delta from the entry's revision the latest revision in the KV + */ delta: number; + /** + * The operation type of the entry + */ operation: KvOperation; + /** + * The value of the entry - if string type, it is base64 encoded + */ value: Uint8Array | string; }