@johannc-dev/zyrk 0.2.0 → 0.2.2

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/dist/sdk.d.ts CHANGED
@@ -278,7 +278,12 @@ export declare const MarketEvent: {
278
278
  export declare const MarketFlag: {
279
279
  /** `tokenReserve` and `quoteReserve` are set. */
280
280
  readonly reserves: 1;
281
- /** `virtualTokenReserve` and `virtualQuoteReserve` are set. */
281
+ /**
282
+ * `virtualTokenReserve` and `virtualQuoteReserve` are both set (always
283
+ * with {@link MarketFlag.virtualTokenReserve} and
284
+ * {@link MarketFlag.virtualQuoteReserve}). PumpSwap trades usually carry
285
+ * one side only: test the side you need instead.
286
+ */
282
287
  readonly virtualReserves: 2;
283
288
  /**
284
289
  * The provider row holds several operations on this pool (e.g. a buy and
@@ -315,6 +320,14 @@ export declare const MarketFlag: {
315
320
  * trader receives 0.30 % less than `tokenRaw`. `chainBreak` accounts for it.
316
321
  */
317
322
  readonly invertedPool: 512;
323
+ /** `virtualTokenReserve` is set. */
324
+ readonly virtualTokenReserve: 1024;
325
+ /**
326
+ * `virtualQuoteReserve` is set. On PumpSwap (pools created by pump.fun)
327
+ * it is added to the real reserve: the effective quote reserve is
328
+ * `quoteReserve + virtualQuoteReserve`.
329
+ */
330
+ readonly virtualQuoteReserve: 2048;
318
331
  };
319
332
  /**
320
333
  * Pool state and fees of each trade (`withMarket: true`), entry `i` for
@@ -328,9 +341,12 @@ export interface MarketColumns {
328
341
  readonly tokenReserve: BigUint64Array;
329
342
  readonly quoteReserve: BigUint64Array;
330
343
  /**
331
- * Pumpfun: the virtual reserves of the bonding curve, the ones its
332
- * constant product uses. Pumpswap: the provider's virtual reserves, when
333
- * it gives them.
344
+ * Pumpfun: the total virtual reserves of the bonding curve, the ones its
345
+ * constant product uses. Pumpswap: a virtual amount added to the real
346
+ * reserve (effective quote reserve = `quoteReserve + virtualQuoteReserve`),
347
+ * usually on one side only. Each side is set when its flag is
348
+ * ({@link MarketFlag.virtualTokenReserve},
349
+ * {@link MarketFlag.virtualQuoteReserve}), `0` otherwise.
334
350
  */
335
351
  readonly virtualTokenReserve: BigUint64Array;
336
352
  readonly virtualQuoteReserve: BigUint64Array;
@@ -352,11 +368,11 @@ export interface MarketColumns {
352
368
  readonly event: Uint8Array;
353
369
  }
354
370
  /**
355
- * Latest known token metadata (`/v1/tokens/{mint}/info`, also `metadata` of
371
+ * Latest known token metadata (`ctx.data.tokenInfo`, also `metadata` of
356
372
  * `tokenTotals`): provider values copied verbatim from the newest row of the
357
373
  * mint that is cheap to reach, `null` when the row lacks them. `name`,
358
- * `symbol` and `uri` of stored hours come from the hour's `tokens.t2` (the
359
- * newest hour that has them), cut at 128, 64 and 512 UTF-8 bytes.
374
+ * `symbol` and `uri` of sealed hours come from the token index of the newest
375
+ * sealed hour that has them, cut at 128, 64 and 512 UTF-8 bytes.
360
376
  */
361
377
  export type TokenMetadata = {
362
378
  readonly name: string | null;
@@ -372,6 +388,12 @@ export type TokenMetadata = {
372
388
  readonly quoteName: string | null;
373
389
  readonly quoteSymbol: string | null;
374
390
  readonly quoteUri: string | null;
391
+ /**
392
+ * Decimals of `quoteMint`: the row's, else 9 for SOL and 6 for USDC, else
393
+ * those of the quote table (rows sent before 2026-10-29 18:15 UTC lack
394
+ * them), else `null` (absent from metadata saved by older exports).
395
+ */
396
+ readonly quoteDecimals?: number | null;
375
397
  /** Time, slot and signature of the row the values come from. */
376
398
  readonly asOfMs: number | null;
377
399
  readonly slot: number | null;
@@ -393,8 +415,8 @@ export type TokenInfo = {
393
415
  readonly metadata: TokenMetadata | null;
394
416
  };
395
417
  /**
396
- * Parameters of `/v1/volume/search`, with the same names and units
397
- * (`since`/`until` in **seconds**, multiples of 60). Paging is handled by
418
+ * Parameters of `ctx.data.volumeSearch` (`since`/`until` in **seconds**,
419
+ * multiples of 60, `[since, until)`, at most 31 days). Paging is handled by
398
420
  * `ctx.data.volumeSearch`: there is no `cursor`.
399
421
  */
400
422
  export interface VolumeSearchParams {
@@ -501,9 +523,9 @@ export interface Subscription {
501
523
  readonly maxReplayEvents?: number;
502
524
  }
503
525
  /**
504
- * A trade as published by the live feed, in the JSON shape of the public API
505
- * (`/v1/tokens/{mint}/operations`). Only the fields most programs read are
506
- * typed; the others are kept as they come.
526
+ * A trade as published by the live feed (the `operation` of a `trade` or
527
+ * `volume` event), with `id` the trade id `"hour:line:op"`. Only the fields
528
+ * most programs read are typed; the others are kept as they come.
507
529
  */
508
530
  export interface MarketOperation {
509
531
  readonly id: string;
@@ -795,7 +817,7 @@ export interface ExecutionInfo {
795
817
  /** 1 for the first attempt. */
796
818
  readonly attempt: number;
797
819
  }
798
- /** Lakebed's `StoragePutOptions` (every field optional here). */
820
+ /** Options of `put` (every field optional). */
799
821
  export interface StoragePutOptions {
800
822
  /** `type/subtype`; parameters are dropped. Default: `text/plain` for a string, else `application/octet-stream`. */
801
823
  readonly contentType?: string;
@@ -809,7 +831,7 @@ export interface StoragePutOptions {
809
831
  */
810
832
  readonly ifMatch?: string;
811
833
  }
812
- /** Lakebed's `StorageObjectHead`, plus where the object stands in time. */
834
+ /** The head of a stored object, with where it stands in time. */
813
835
  export interface StorageObjectHead {
814
836
  readonly key: string;
815
837
  readonly size: number;
@@ -824,11 +846,11 @@ export interface StorageObjectHead {
824
846
  /** Changes at every write (HTTP `ETag`). */
825
847
  readonly etag: string;
826
848
  }
827
- /** Lakebed's `StorageReadResult`. With a range, `body` is that range and `size` the whole object's. */
849
+ /** What `get` answers. With a range, `body` is that range and `size` the whole object's. */
828
850
  export interface StorageReadResult extends StorageObjectHead {
829
851
  readonly body: Uint8Array;
830
852
  }
831
- /** Lakebed's `StorageObjectSummary` (what `list` answers), plus expiry. */
853
+ /** One object of a `list` answer, with its expiry. */
832
854
  export interface StorageObjectSummary {
833
855
  readonly key: string;
834
856
  readonly size: number;
@@ -837,14 +859,14 @@ export interface StorageObjectSummary {
837
859
  readonly expiresAt: number | null;
838
860
  }
839
861
  /**
840
- * What `list` answers: Lakebed's array of summaries, plus `cursor` (pass it
862
+ * What `list` answers: an array of summaries, plus `cursor` (pass it
841
863
  * as `after` for the next page, `null` at the end) and `truncated`.
842
864
  */
843
865
  export type StorageListPage = StorageObjectSummary[] & {
844
866
  readonly cursor: string | null;
845
867
  readonly truncated: boolean;
846
868
  };
847
- /** Lakebed's `StorageLedgerUsage` for one area of the account, with its limits. */
869
+ /** Usage of one storage area of the account, with its limits. */
848
870
  export interface StorageUsage {
849
871
  readonly area: "short" | "long" | "durable";
850
872
  readonly initialized: boolean;
@@ -886,9 +908,9 @@ export interface StorageWriter {
886
908
  * execution fails afterwards.
887
909
  */
888
910
  export interface StorageArea {
889
- /** Lakebed's `put`. Answers the new head. */
911
+ /** Writes an object. Answers the new head. */
890
912
  put(key: string, body: StorageBody, options?: StoragePutOptions): Promise<StorageObjectHead>;
891
- /** Lakebed's `get`; `range` reads part of a large object. `null` when absent or expired. */
913
+ /** Reads an object; `range` reads part of a large object. `null` when absent or expired. */
892
914
  get(key: string, range?: {
893
915
  offset?: number;
894
916
  length?: number;
@@ -899,7 +921,7 @@ export interface StorageArea {
899
921
  ifMatch?: string;
900
922
  }): Promise<void>;
901
923
  /**
902
- * Lakebed's `list`: keys starting with `prefix`, in byte order, at most
924
+ * Lists keys starting with `prefix`, in byte order, at most
903
925
  * `maxObjects` (1000). For the next page, pass the last key as `after`.
904
926
  */
905
927
  list(prefix?: string, options?: {
@@ -914,6 +936,189 @@ export interface StorageArea {
914
936
  putJSON(key: string, value: JsonInput, options?: Omit<StoragePutOptions, "contentType">): Promise<StorageObjectHead>;
915
937
  writer(key: string, options?: StoragePutOptions): Promise<StorageWriter>;
916
938
  }
939
+ /** Milliseconds, or text such as `"500ms"`, `"30s"`, `"15m"`, `"6h"`, `"30d"`. */
940
+ export type ComputeDuration = number | `${number}${"ms" | "s" | "m" | "h" | "d"}`;
941
+ /** `[since, until)` in ms; `until` defaults to the call's time. */
942
+ export type ComputeWindow = {
943
+ readonly since: number;
944
+ readonly until?: number;
945
+ } | {
946
+ readonly last: ComputeDuration;
947
+ readonly until?: number;
948
+ };
949
+ /** Fields of a trade a filter or a measure reads. */
950
+ export type ComputeField = "side" | "protocol" | "token" | "trader" | "quoteMint" | "timeMs" | "ageMs" | "quoteRaw" | "tokenRaw" | "quoteAmount" | "tokenAmount" | "execPrice" | "isCreator" | "marketFlags" | "orderFlags";
951
+ /** Fields measured by `sum`, `min`, `max`, `avg`, `first`, `last`, `anchor`, `asOf`. */
952
+ export type ComputeNumericField = "timeMs" | "ageMs" | "quoteRaw" | "tokenRaw" | "quoteAmount" | "tokenAmount" | "execPrice";
953
+ type ComputeValue = string | number | boolean;
954
+ /** A comparison of one field: a value (equality), or operators (all must hold). */
955
+ export type ComputeCondition = ComputeValue | {
956
+ readonly eq?: ComputeValue;
957
+ readonly ne?: ComputeValue;
958
+ readonly gt?: number | string;
959
+ readonly gte?: number | string;
960
+ readonly lt?: number | string;
961
+ readonly lte?: number | string;
962
+ readonly in?: readonly ComputeValue[];
963
+ readonly notIn?: readonly ComputeValue[];
964
+ /** Flag fields (`marketFlags`, `orderFlags`): bits of the mask set. */
965
+ readonly hasAll?: number;
966
+ readonly hasAny?: number;
967
+ readonly hasNone?: number;
968
+ };
969
+ /**
970
+ * A filter: every field listed must pass (`and`), with `and`, `or`, `not`
971
+ * to combine. In `where`, the fields of a trade (and `"<stage>.<measure>"`);
972
+ * in `having`, the measures and keys of a group. A comparison with an
973
+ * unknown value (no trader, a creation not seen, a missing stage value) is
974
+ * false, `ne` and `notIn` included.
975
+ */
976
+ export interface ComputeFilter {
977
+ readonly and?: readonly ComputeFilter[];
978
+ readonly or?: readonly ComputeFilter[];
979
+ readonly not?: ComputeFilter;
980
+ readonly [field: string]: ComputeCondition | ComputeFilter | readonly ComputeFilter[] | undefined;
981
+ }
982
+ export type ComputeKey = "token" | "trader" | "quoteMint" | "side" | "protocol"
983
+ /** `floor(timeMs / width) * width`. */
984
+ | {
985
+ readonly time: ComputeDuration;
986
+ }
987
+ /** `floor(ageMs / width) * width` (tokens whose creation is known). */
988
+ | {
989
+ readonly age: ComputeDuration;
990
+ };
991
+ type MeasureOptions = {
992
+ /** Only the trades that pass it. */
993
+ readonly where?: ComputeFilter;
994
+ /** Plans with `anchors`: the token's trades in `[anchor + from, anchor + to)` ms. */
995
+ readonly window?: readonly [number, number];
996
+ };
997
+ export type ComputeMeasure = ({
998
+ readonly count: true;
999
+ } & MeasureOptions) | ({
1000
+ readonly countDistinct: "token" | "trader" | "quoteMint";
1001
+ } & MeasureOptions) | ({
1002
+ readonly sum: ComputeNumericField;
1003
+ } & MeasureOptions) | ({
1004
+ readonly min: ComputeNumericField;
1005
+ } & MeasureOptions) | ({
1006
+ readonly max: ComputeNumericField;
1007
+ } & MeasureOptions) | ({
1008
+ readonly avg: ComputeNumericField;
1009
+ } & MeasureOptions)
1010
+ /** In the token's trade sequence (see the docs). */
1011
+ | ({
1012
+ readonly first: ComputeNumericField;
1013
+ } & MeasureOptions) | ({
1014
+ readonly last: ComputeNumericField;
1015
+ } & MeasureOptions)
1016
+ /** `Number(a) / Number(b)` of two other measures. */
1017
+ | {
1018
+ readonly ratio: readonly [string, string];
1019
+ }
1020
+ /** Plans with `anchors`: a field of the anchor trade. */
1021
+ | {
1022
+ readonly anchor: ComputeNumericField;
1023
+ }
1024
+ /**
1025
+ * Plans with `anchors`: `field` of the token's trade as of `anchor +
1026
+ * offsetMs` (the last at or before it; with `direction: "after"`, the
1027
+ * first at or after it), within `withinMs` (default and at most 1 h). An
1028
+ * array of offsets gives one column each, `"<name>@<offset>"`.
1029
+ */
1030
+ | ({
1031
+ readonly asOf: ComputeNumericField;
1032
+ readonly offsetMs: number | readonly number[];
1033
+ readonly direction?: "before" | "after";
1034
+ readonly withinMs?: number;
1035
+ } & Omit<MeasureOptions, "window">);
1036
+ export interface ComputePlan {
1037
+ readonly range: ComputeWindow;
1038
+ /** Only these mints (1 to 10 000). */
1039
+ readonly tokens?: readonly Address[];
1040
+ /** Only the tokens created in this window (creations seen in its hours). */
1041
+ readonly created?: ComputeWindow;
1042
+ /** `"SOL"` (default), a quote mint, `"auto"` (per token, as `tokenTotals`) or `"any"`. */
1043
+ readonly quote?: "SOL" | "auto" | "any" | Address;
1044
+ readonly where?: ComputeFilter;
1045
+ readonly groupBy?: readonly ComputeKey[];
1046
+ /** 1 to 16 named measures; results list them in name order. */
1047
+ readonly measures: Readonly<Record<string, ComputeMeasure>>;
1048
+ readonly having?: ComputeFilter;
1049
+ /** The `n` groups with the largest `by`, per partition of the `per` keys. */
1050
+ readonly top?: {
1051
+ readonly by: string;
1052
+ readonly n: number;
1053
+ readonly per?: readonly string[];
1054
+ };
1055
+ readonly orderBy?: readonly (string | {
1056
+ readonly by: string;
1057
+ readonly desc?: boolean;
1058
+ })[];
1059
+ readonly limit?: number;
1060
+ /** Accept a window not fully covered, or rejected operations. */
1061
+ readonly allowPartial?: boolean;
1062
+ /** Stages: measures per token, read in `where` as `"<stage>.<measure>"`. */
1063
+ readonly with?: Readonly<Record<string, {
1064
+ readonly where?: ComputeFilter;
1065
+ readonly measures: Readonly<Record<string, ComputeMeasure>>;
1066
+ readonly having?: ComputeFilter;
1067
+ }>>;
1068
+ /**
1069
+ * One row per anchor: the first trade, in its token's sequence, of each
1070
+ * group of `by` (with `token`) that passes `where`. Measures then read it
1071
+ * (`anchor`) and its token's trades around it (`asOf`, `window`).
1072
+ */
1073
+ readonly anchors?: {
1074
+ readonly by: readonly ComputeKey[];
1075
+ readonly where?: ComputeFilter;
1076
+ readonly pick?: "first";
1077
+ };
1078
+ }
1079
+ /** A column of a result: addresses and names, numbers, or exact integers. */
1080
+ export type ComputeColumn = readonly (string | null)[] | Float64Array | readonly (bigint | null)[];
1081
+ export interface ComputeStats {
1082
+ readonly hours: number;
1083
+ readonly derivedHours: number;
1084
+ readonly sealedHours: number;
1085
+ readonly openHours: number;
1086
+ readonly passes: number;
1087
+ readonly trades: number;
1088
+ readonly groups: number;
1089
+ /** Server time of the call, every thread (the history reading; not your CPU). */
1090
+ readonly cpuMs: number;
1091
+ readonly wallMs: number;
1092
+ }
1093
+ interface ComputeSummary {
1094
+ readonly length: number;
1095
+ /** Key columns, in `groupBy` order. */
1096
+ readonly keys: readonly string[];
1097
+ /** Measure columns, in name order. */
1098
+ readonly measures: readonly string[];
1099
+ readonly coverage: Json;
1100
+ /** Covered, and no rejected operation counted. */
1101
+ readonly complete: boolean;
1102
+ /** Operations of the tokens read that normalization rejects, in the range. */
1103
+ readonly skipped: number;
1104
+ readonly stats: ComputeStats;
1105
+ }
1106
+ export interface ComputeResult extends ComputeSummary {
1107
+ /** One column per key and measure, `length` values each. */
1108
+ readonly columns: Readonly<Record<string, ComputeColumn>>;
1109
+ }
1110
+ /** A result written to storage (`output`): JSON lines, one object per row. */
1111
+ export interface ComputeOutput extends ComputeSummary {
1112
+ readonly output: {
1113
+ readonly area: "short" | "long" | "durable";
1114
+ readonly key: string;
1115
+ readonly rows: number;
1116
+ readonly bytes: number;
1117
+ readonly etag: string;
1118
+ };
1119
+ }
1120
+ /** The rows of a result as objects (keys and measures by name). */
1121
+ export declare function computeRows(r: ComputeResult): Record<string, string | number | bigint | null>[];
917
1122
  export interface Context {
918
1123
  readonly execution: ExecutionInfo;
919
1124
  readonly data: {
@@ -924,16 +1129,26 @@ export interface Context {
924
1129
  walletTrades(wallet: Address, query: TradeQuery): AsyncIterable<HourBatch>;
925
1130
  /** Trades of a token, one hour per batch, oldest first. */
926
1131
  tokenTrades(mint: Address, query: TradeQuery): AsyncIterable<HourBatch>;
927
- /** Same JSON as `/v1/tokens/{mint}/totals` (with `metadata`). */
1132
+ /**
1133
+ * Volume of a token since its creation (`cumulativeRaw`, `buyRaw`,
1134
+ * `sellRaw`, `buys`, `sells`, `sinceCreation.complete`, `coverage`), its
1135
+ * `creation` and `metadata`, as JSON. Amounts are in `quoteMint` at
1136
+ * `quoteDecimals`; without `quote`: SOL; `quote: "auto"`: SOL unless the
1137
+ * token trades in other quotes only (then its most traded one; `quotes`
1138
+ * lists them all).
1139
+ */
928
1140
  tokenTotals(mint: Address, options?: {
929
- quote?: Address;
1141
+ quote?: Address | "auto";
930
1142
  }): Promise<Json>;
931
1143
  /**
932
- * Same JSON as `/v1/tokens/{mint}/info`: latest known metadata and the
933
- * creation, at most two blocks read (no volumes).
1144
+ * Latest known metadata and the creation, at most two blocks read (no
1145
+ * volumes).
934
1146
  */
935
1147
  tokenInfo(mint: Address): Promise<TokenInfo>;
936
- /** Pages of `/v1/volume/search`, in its JSON shape. */
1148
+ /**
1149
+ * Tokens ranked by volume over a window, page by page (`items` of
1150
+ * `{mint, volume, buyVolume, sellVolume, buys, sells, volumeRaw}`).
1151
+ */
937
1152
  volumeSearch(params: VolumeSearchParams): AsyncIterable<Json>;
938
1153
  };
939
1154
  /** Private JSON state of the program, kept between executions. */
@@ -967,6 +1182,22 @@ export interface Context {
967
1182
  * after the last write), `long` (500 MiB, 7 days after the last write) and
968
1183
  * `durable` (50 MiB, never expires).
969
1184
  */
1185
+ /**
1186
+ * Runs a plan (or up to 8 plans over one read) natively over the
1187
+ * history: answers columns, or with `output` writes the rows to storage
1188
+ * as JSON lines and answers a summary. Errors: `invalid_plan`,
1189
+ * `invalid_window`, `partial_coverage`, `compute_result_limit`,
1190
+ * `compute_memory_limit`, `compute_limit`, `compute_overflow`, and those of
1191
+ * history reads.
1192
+ */
1193
+ compute(plan: ComputePlan): Promise<ComputeResult>;
1194
+ compute(plans: readonly ComputePlan[]): Promise<ComputeResult[]>;
1195
+ compute(plan: ComputePlan, options: {
1196
+ readonly output: {
1197
+ readonly area: "short" | "long" | "durable";
1198
+ readonly key: string;
1199
+ };
1200
+ }): Promise<ComputeOutput>;
970
1201
  readonly storage: {
971
1202
  readonly short: StorageArea;
972
1203
  readonly long: StorageArea;
@@ -1047,7 +1278,7 @@ export declare function parseTradeId(id: string): TradeKey;
1047
1278
  export declare function compareTradeIds(a: string, b: string): number;
1048
1279
  /**
1049
1280
  * Id of a live-feed operation, in the {@link tradeId} format (`operation.id`
1050
- * as delivered by funrun, else `order.ord`); `null` without order.
1281
+ * as delivered to subscriptions, else `order.ord`); `null` without order.
1051
1282
  */
1052
1283
  export declare function operationTradeId(operation: MarketOperation): string | null;
1053
1284
  /**
@@ -1115,9 +1346,9 @@ export declare function tradeAt(batch: HourBatch, i: number): Trade;
1115
1346
  * `error.code`; `message` is for humans and may change.
1116
1347
  */
1117
1348
  export type SdkErrorCode = "invalid_window" | "partial_coverage" | "history_preparing" | "storage_busy" | "history_unavailable" | "read_limit" | "read_time_limit" | "invalid_argument" | "unknown_function" | "execution_not_found" | "state_value_too_large" | "state_limit" | "children_limit" | "subscription_limit" | "price_subscription_limit" | "output_limit" | StorageErrorCode | (string & {});
1118
- /** Lakebed's `StorageErrorCode`, plus `already_exists`, `value_changed`, `io_limit`, `upload_limit`, `precondition_failed`. */
1349
+ /** Error codes of user storage (`ctx.storage` and the HTTP storage routes). */
1119
1350
  export type StorageErrorCode = "quota_exceeded" | "too_large" | "not_found" | "invalid_request" | "forbidden" | "unavailable" | "blocked_type" | "already_exists" | "value_changed" | "io_limit" | "upload_limit" | "precondition_failed";
1120
- /** HTTP status of each storage code (Lakebed's for its seven). */
1351
+ /** HTTP status of each storage code. */
1121
1352
  export declare const STORAGE_STATUS_BY_CODE: Readonly<Record<StorageErrorCode, number>>;
1122
1353
  /** Error thrown by a `ctx` call. `retryAfterMs` comes with `storage_busy`/`history_preparing`. */
1123
1354
  export interface SdkError extends Error {
package/dist/sdk.js CHANGED
@@ -47,6 +47,8 @@ export const MarketFlag = {
47
47
  mayhem: 128,
48
48
  feeWithoutToken: 256,
49
49
  invertedPool: 512,
50
+ virtualTokenReserve: 1024,
51
+ virtualQuoteReserve: 2048,
50
52
  };
51
53
  export function isFinal(result) {
52
54
  return result.status !== "queued" && result.status !== "running";
@@ -71,6 +73,18 @@ export function isCompletion(args) {
71
73
  args.kind === "completion" &&
72
74
  typeof args.executionId === "string");
73
75
  }
76
+ export function computeRows(r) {
77
+ const names = [...r.keys, ...r.measures];
78
+ const out = [];
79
+ for (let i = 0; i < r.length; i++) {
80
+ const row = {};
81
+ for (const n of names)
82
+ row[n] =
83
+ r.columns[n][i] ?? null;
84
+ out.push(row);
85
+ }
86
+ return out;
87
+ }
74
88
  export const SDK_MARKER = "__zyrkSdk";
75
89
  export const SDK_VERSION = "0.2";
76
90
  export function defineProgram(program) {
package/dist/stream.d.ts CHANGED
@@ -15,18 +15,66 @@ export interface StreamOptions {
15
15
  readonly apiKey: string;
16
16
  /** Resume after this sequence number. */
17
17
  readonly afterSeq?: number;
18
+ /**
19
+ * How long the server must keep refusing the key, with no successful join
20
+ * in between, before the stream ends with `invalid_key` (or `unauthorized`).
21
+ * Default 360 000 ms (6 min). See {@link executionEvents}: below the
22
+ * server's longest key sync delay, a key created just before the stream
23
+ * started could end it.
24
+ */
25
+ readonly keyRefusalWindowMs?: number;
18
26
  }
19
27
  /**
20
- * Live execution events of the account. Gaps are emitted as values; the
21
- * stream fails on undecodable payloads or when the server refuses the join.
22
- * The socket is closed when the stream is interrupted or ends.
28
+ * Live execution events of the account. Gaps are emitted as values.
29
+ *
30
+ * The stream reconnects by itself after a dropped or closed connection (no
31
+ * network, a server restart or deploy, a connection the server closed) and
32
+ * resumes after the last event. It fails, once, with:
33
+ * - a {@link DecodeError} on an undecodable payload;
34
+ * - a {@link NetworkError} when the server refuses the join, with the
35
+ * server's `reason` (`functions_disabled`, `functions_unavailable`);
36
+ * - a {@link NetworkError} whose `reason` is `functions_disabled` (Functions
37
+ * access removed) or `channel_closed` (the server closed the channel:
38
+ * subscribe again with `afterSeq`);
39
+ * - a {@link NetworkError} whose `reason` is `invalid_key` (the key was
40
+ * revoked, replaced or is unknown, or its account is not active) or
41
+ * `unauthorized` (the same, seen at the join): the server kept refusing
42
+ * the key for {@link StreamOptions.keyRefusalWindowMs} (default 6 min)
43
+ * with no successful join in between. A single refusal never ends the
44
+ * stream: a key created or changed less than a key sync ago, or a server
45
+ * whose key data is briefly behind, is refused too; the stream retries
46
+ * (every 5 s at most) and goes on as soon as a join succeeds. A refusal
47
+ * that the server does not name (a server starting, a network failure,
48
+ * the connection limit) is retried with no time limit;
49
+ * - a {@link NetworkError} whose `reason` is `account_changed`: a
50
+ * reconnection joined another account than the first join (the key was
51
+ * moved to another account). No event of the other account is delivered.
52
+ * This check needs a server that names the account in its join reply: a
53
+ * join answered without `account` (an older server, e.g. during a rollout
54
+ * or rollback) is accepted unchecked.
55
+ *
56
+ * A transient `status` `{available: false}` does not end it. An older
57
+ * server that does not say why it refused a connection gives no
58
+ * `invalid_key`: the stream then keeps reconnecting, as before. The socket
59
+ * is closed and no reconnection happens once the stream is interrupted or
60
+ * has failed.
23
61
  */
24
62
  export declare const executionEvents: (options: StreamOptions) => Stream.Stream<FunctionsMessage, StreamError>;
25
- /** Callback API kept for existing users; errors are tagged `StreamError`s or raw socket errors. */
63
+ /**
64
+ * Callback API kept for existing users; errors are tagged `StreamError`s or
65
+ * raw socket errors (transient: it reconnects by itself). While the server
66
+ * refuses the key (see {@link executionEvents}) nothing is reported: it
67
+ * retries silently, and reports once if the refusal lasts the whole window.
68
+ * After a `NetworkError` (`functions_disabled`, `functions_unavailable`,
69
+ * `channel_closed`, `invalid_key`, `unauthorized`, `account_changed`) the
70
+ * socket is closed and nothing more arrives.
71
+ */
26
72
  export declare function subscribeFunctions(options: {
27
73
  url: string;
28
74
  apiKey: string;
29
75
  afterSeq?: number;
76
+ /** See {@link StreamOptions.keyRefusalWindowMs}. */
77
+ keyRefusalWindowMs?: number;
30
78
  onEvent: (event: ExecutionEvent) => void;
31
79
  onGap?: (gap: Gap) => void;
32
80
  onError?: (error: unknown) => void;