@prosody-events/prosody 0.5.1 → 0.6.1
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/README.md +161 -57
- package/bindings.d.ts +302 -404
- package/bindings.js +168 -85
- package/index.d.ts +30 -962
- package/index.js +42 -1898
- package/lib/client.d.ts +232 -0
- package/lib/client.js +347 -0
- package/lib/context.d.ts +161 -0
- package/lib/context.js +86 -0
- package/lib/errors.d.ts +103 -0
- package/lib/errors.js +102 -0
- package/lib/logging.d.ts +75 -0
- package/lib/logging.js +99 -0
- package/lib/payload.d.ts +59 -0
- package/lib/state/bridge.js +103 -0
- package/lib/state/codec.js +206 -0
- package/lib/state/definitions.d.ts +233 -0
- package/lib/state/definitions.js +151 -0
- package/lib/state/deque.d.ts +75 -0
- package/lib/state/deque.js +77 -0
- package/lib/state/handle.d.ts +25 -0
- package/lib/state/handle.js +26 -0
- package/lib/state/iterator.js +66 -0
- package/lib/state/map.d.ts +94 -0
- package/lib/state/map.js +79 -0
- package/lib/state/published.d.ts +113 -0
- package/lib/state/published.js +147 -0
- package/lib/state/query.d.ts +85 -0
- package/lib/state/query.js +206 -0
- package/lib/state/set.d.ts +52 -0
- package/lib/state/set.js +54 -0
- package/lib/state/value.d.ts +33 -0
- package/lib/state/value.js +31 -0
- package/package.json +21 -20
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only readers of published value, map, set, and deque collections.
|
|
3
|
+
* @module lib/state/published
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { defineHidden, stateOp } = require("./bridge");
|
|
8
|
+
const { jsonItems } = require("./codec");
|
|
9
|
+
const { stateIterator } = require("./iterator");
|
|
10
|
+
const { dequePosition, keyQuery, positionQuery } = require("./query");
|
|
11
|
+
|
|
12
|
+
/** Read-only handle over a published single-value collection. */
|
|
13
|
+
class PublishedValue {
|
|
14
|
+
constructor(native) {
|
|
15
|
+
defineHidden(this, { native });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async get(key) {
|
|
19
|
+
return jsonItems.decode(
|
|
20
|
+
await stateOp((carrier) => this.native.get(key, carrier)),
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Read-only handle over a published map collection. */
|
|
26
|
+
class PublishedMap {
|
|
27
|
+
constructor(native) {
|
|
28
|
+
defineHidden(this, { native });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async get(key, mapKey) {
|
|
32
|
+
return jsonItems.decode(
|
|
33
|
+
await stateOp((carrier) => this.native.get(key, mapKey, carrier)),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async getMany(key, mapKeys) {
|
|
38
|
+
const values = await stateOp((carrier) =>
|
|
39
|
+
this.native.getMany(key, mapKeys, carrier),
|
|
40
|
+
);
|
|
41
|
+
return values.map(jsonItems.decode);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
has(key, mapKey) {
|
|
45
|
+
return stateOp((carrier) => this.native.contains(key, mapKey, carrier));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
hasMany(key, mapKeys) {
|
|
49
|
+
return stateOp((carrier) =>
|
|
50
|
+
this.native.containsMany(key, mapKeys, carrier),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
isEmpty(key) {
|
|
55
|
+
return stateOp((carrier) => this.native.isEmpty(key, carrier));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
entries(key, options) {
|
|
59
|
+
const query = keyQuery(options);
|
|
60
|
+
return stateIterator(this.native.entries(key, query), ([mapKey, value]) => [
|
|
61
|
+
mapKey,
|
|
62
|
+
jsonItems.decode(value),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
keys(key, options) {
|
|
67
|
+
const query = keyQuery(options);
|
|
68
|
+
return stateIterator(this.native.keys(key, query), (mapKey) => mapKey);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
values(key, options) {
|
|
72
|
+
const query = keyQuery(options);
|
|
73
|
+
return stateIterator(this.native.entries(key, query), (entry) =>
|
|
74
|
+
jsonItems.decode(entry[1]),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Read-only handle over a published set collection. */
|
|
80
|
+
class PublishedSet {
|
|
81
|
+
constructor(native) {
|
|
82
|
+
defineHidden(this, { native });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
has(key, member) {
|
|
86
|
+
return stateOp((carrier) => this.native.contains(key, member, carrier));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
hasMany(key, members) {
|
|
90
|
+
return stateOp((carrier) =>
|
|
91
|
+
this.native.containsMany(key, members, carrier),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
isEmpty(key) {
|
|
96
|
+
return stateOp((carrier) => this.native.isEmpty(key, carrier));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
keys(key, options) {
|
|
100
|
+
const query = keyQuery(options);
|
|
101
|
+
return stateIterator(this.native.keys(key, query), (member) => member);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
values(key, options) {
|
|
105
|
+
return this.keys(key, options);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Read-only handle over a published deque collection. */
|
|
110
|
+
class PublishedDeque {
|
|
111
|
+
constructor(native) {
|
|
112
|
+
defineHidden(this, { native });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
length(key) {
|
|
116
|
+
return stateOp((carrier) => this.native.len(key, carrier));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
isEmpty(key) {
|
|
120
|
+
return stateOp((carrier) => this.native.isEmpty(key, carrier));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async at(key, index) {
|
|
124
|
+
if (index === -1) {
|
|
125
|
+
return jsonItems.decode(
|
|
126
|
+
await stateOp((carrier) => this.native.peekBack(key, carrier)),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const position = await dequePosition(index, () => this.length(key));
|
|
130
|
+
if (position === null) return null;
|
|
131
|
+
return jsonItems.decode(
|
|
132
|
+
await stateOp((carrier) => this.native.get(key, position, carrier)),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
values(key, options) {
|
|
137
|
+
const query = positionQuery(options);
|
|
138
|
+
return stateIterator(this.native.values(key, query), jsonItems.decode);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = {
|
|
143
|
+
PublishedDeque,
|
|
144
|
+
PublishedMap,
|
|
145
|
+
PublishedSet,
|
|
146
|
+
PublishedValue,
|
|
147
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The query options of map, set, and deque scans. The runtime checks stay private.
|
|
3
|
+
* @module lib/state/query
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Scan direction over a map or deque collection. `"forward"` visits a map in
|
|
8
|
+
* ascending key order and a deque from front to back; `"backward"` reverses
|
|
9
|
+
* each. Defaults to `"forward"` wherever it is optional.
|
|
10
|
+
*/
|
|
11
|
+
export type ScanDirection = "forward" | "backward";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The start of a query. `from` includes its bound and `after` excludes it.
|
|
15
|
+
* Set at most one. The start is in query order, so a backward query starts
|
|
16
|
+
* at the high end.
|
|
17
|
+
*/
|
|
18
|
+
export type QueryStart<B> =
|
|
19
|
+
| { readonly from?: B; readonly after?: never }
|
|
20
|
+
| { readonly from?: never; readonly after?: B };
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The end of a query. `to` includes its bound and `before` excludes it. Set
|
|
24
|
+
* at most one. The end is in query order.
|
|
25
|
+
*/
|
|
26
|
+
export type QueryEnd<B> =
|
|
27
|
+
| { readonly to?: B; readonly before?: never }
|
|
28
|
+
| { readonly to?: never; readonly before?: B };
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* An ascending, half-open range: `[start, end]` keeps the keys or positions
|
|
32
|
+
* from `start` up to, but not including, `end`. A `null` bound leaves its end
|
|
33
|
+
* open, so `[2, null]` keeps position 2 and every later one. The range applies
|
|
34
|
+
* in both directions, so a backward query yields the same items in the
|
|
35
|
+
* opposite order. A range whose `start` is not below its `end` selects
|
|
36
|
+
* nothing.
|
|
37
|
+
*/
|
|
38
|
+
export type QueryRange<B> = readonly [start: B | null, end: B | null];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The bounds of a query: the edges and an optional range. A query that sets
|
|
42
|
+
* both keeps their overlap.
|
|
43
|
+
*/
|
|
44
|
+
export type QueryBounds<B> = QueryStart<B> &
|
|
45
|
+
QueryEnd<B> & {
|
|
46
|
+
/** Keeps the items within this ascending range. See {@link QueryRange}. */
|
|
47
|
+
readonly range?: QueryRange<B>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** The options that every query accepts. */
|
|
51
|
+
export interface QueryOptions {
|
|
52
|
+
/** The query order. Defaults to `"forward"`. */
|
|
53
|
+
readonly direction?: ScanDirection;
|
|
54
|
+
/**
|
|
55
|
+
* The maximum number of results. Must be a positive safe integer. A
|
|
56
|
+
* `RangeError` reports any other number.
|
|
57
|
+
*/
|
|
58
|
+
readonly limit?: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Query options for map entries, map keys, and set members. Every option is
|
|
63
|
+
* optional. Bounds and `prefix` narrow the selection and never widen it.
|
|
64
|
+
* Setting both edges of a pair, a malformed range, an unknown option, or an
|
|
65
|
+
* unknown direction throws a `TypeError`. The call
|
|
66
|
+
* copies the options, so a later change to the object has no effect on the
|
|
67
|
+
* query.
|
|
68
|
+
*
|
|
69
|
+
* For keyset paging, set `after` to the last key of the previous page and
|
|
70
|
+
* `limit` to the page size. To read the keys from `"a"` up to `"m"` in either
|
|
71
|
+
* direction, set `range: ["a", "m"]`.
|
|
72
|
+
*/
|
|
73
|
+
export type KeyQueryOptions = QueryOptions & {
|
|
74
|
+
/** Keeps keys that start with this prefix. */
|
|
75
|
+
readonly prefix?: string;
|
|
76
|
+
} & QueryBounds<string>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Query options for deque values. Positions count from the front. Each
|
|
80
|
+
* position must be a non-negative safe integer; a `RangeError` reports any
|
|
81
|
+
* other number. Negative positions are not resolved against the length. To
|
|
82
|
+
* read the last N elements, use `values({ direction: "backward", limit: N })`.
|
|
83
|
+
* To read positions 2, 3, and 4 in either direction, set `range: [2, 5]`.
|
|
84
|
+
*/
|
|
85
|
+
export type PositionQueryOptions = QueryOptions & QueryBounds<number>;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks and copies the query options of map, set, and deque scans, and
|
|
3
|
+
* resolves deque `at` indexes.
|
|
4
|
+
* @module lib/state/query
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { TransientStateError } = require("../errors");
|
|
9
|
+
const { describeValue } = require("./bridge");
|
|
10
|
+
|
|
11
|
+
/** The options a map or set query accepts. @private */
|
|
12
|
+
const KEY_QUERY_FIELDS = new Set([
|
|
13
|
+
"direction",
|
|
14
|
+
"limit",
|
|
15
|
+
"prefix",
|
|
16
|
+
"from",
|
|
17
|
+
"after",
|
|
18
|
+
"to",
|
|
19
|
+
"before",
|
|
20
|
+
"range",
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
/** The options a deque query accepts. @private */
|
|
24
|
+
const POSITION_QUERY_FIELDS = new Set([
|
|
25
|
+
"direction",
|
|
26
|
+
"limit",
|
|
27
|
+
"from",
|
|
28
|
+
"after",
|
|
29
|
+
"to",
|
|
30
|
+
"before",
|
|
31
|
+
"range",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
/** The query edges. @private */
|
|
35
|
+
const QUERY_EDGES = ["from", "after", "to", "before"];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Checks the shared query options and copies them into a fresh object. A
|
|
39
|
+
* bare direction string stands for `{ direction }` and gets the same checks.
|
|
40
|
+
* The copy holds only the set, checked fields, so a later change to the
|
|
41
|
+
* caller's object cannot reach the native layer. The copy also holds its own
|
|
42
|
+
* copy of the `range` array. A `range` may combine with the edges; the query
|
|
43
|
+
* then keeps the overlap. A `null` bound leaves that end of the range open.
|
|
44
|
+
* @param {string|object} [options] - A scan direction or a query object.
|
|
45
|
+
* @param {Set<string>} fields - The option names this query accepts.
|
|
46
|
+
* @returns {object} The checked query.
|
|
47
|
+
* @throws {TypeError} If `options` has the wrong type, has an unknown option,
|
|
48
|
+
* sets both edges of an exclusive pair, sets a `range` that is not an array
|
|
49
|
+
* of two bounds, or sets an unknown direction.
|
|
50
|
+
* @throws {RangeError} If `limit` is not a positive safe integer.
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
function queryOptions(options, fields) {
|
|
54
|
+
if (options === undefined) return {};
|
|
55
|
+
const source = typeof options === "string" ? { direction: options } : options;
|
|
56
|
+
if (source === null || typeof source !== "object") {
|
|
57
|
+
throw new TypeError(
|
|
58
|
+
`query: expected a scan direction or an options object, got ${describeValue(options)}`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const query = {};
|
|
62
|
+
for (const [field, value] of Object.entries(source)) {
|
|
63
|
+
if (!fields.has(field)) {
|
|
64
|
+
throw new TypeError(`query: unknown option ${describeValue(field)}`);
|
|
65
|
+
}
|
|
66
|
+
if (value !== undefined) query[field] = value;
|
|
67
|
+
}
|
|
68
|
+
for (const [start, end] of [
|
|
69
|
+
["from", "after"],
|
|
70
|
+
["to", "before"],
|
|
71
|
+
]) {
|
|
72
|
+
if (query[start] !== undefined && query[end] !== undefined) {
|
|
73
|
+
throw new TypeError(`query: set ${start} or ${end}, not both`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (query.range !== undefined) {
|
|
77
|
+
if (
|
|
78
|
+
!Array.isArray(query.range) ||
|
|
79
|
+
query.range.length !== 2 ||
|
|
80
|
+
query.range.includes(undefined)
|
|
81
|
+
) {
|
|
82
|
+
throw new TypeError(
|
|
83
|
+
`range: expected a [start, end] array, got ${describeValue(query.range)}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
query.range = [...query.range];
|
|
87
|
+
}
|
|
88
|
+
const { direction } = query;
|
|
89
|
+
if (
|
|
90
|
+
direction !== undefined &&
|
|
91
|
+
direction !== "forward" &&
|
|
92
|
+
direction !== "backward"
|
|
93
|
+
) {
|
|
94
|
+
throw new TypeError(
|
|
95
|
+
`direction: expected "forward" or "backward", got ${describeValue(direction)}`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
checkCount(query.limit, "limit", 1);
|
|
99
|
+
return query;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Checks a whole-number query option.
|
|
104
|
+
* @param {*} count - The option value, or `undefined` when it is not set.
|
|
105
|
+
* @param {string} field - The option name.
|
|
106
|
+
* @param {number} min - The smallest valid value.
|
|
107
|
+
* @throws {TypeError} If the value is not a number.
|
|
108
|
+
* @throws {RangeError} If the value is not a safe integer of at least `min`.
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
function checkCount(count, field, min) {
|
|
112
|
+
if (count === undefined) return;
|
|
113
|
+
if (typeof count !== "number") {
|
|
114
|
+
throw new TypeError(
|
|
115
|
+
`${field}: expected a number, got ${describeValue(count)}`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (!Number.isSafeInteger(count) || count < min) {
|
|
119
|
+
throw new RangeError(
|
|
120
|
+
`${field}: expected a safe integer of at least ${min}, got ${count}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Checks the options of a map or set query.
|
|
127
|
+
* @param {string|object} [options] - A scan direction or a key query.
|
|
128
|
+
* @returns {object} The key query.
|
|
129
|
+
* @throws {TypeError|RangeError} If an option is invalid.
|
|
130
|
+
* @private
|
|
131
|
+
*/
|
|
132
|
+
function keyQuery(options) {
|
|
133
|
+
const query = queryOptions(options, KEY_QUERY_FIELDS);
|
|
134
|
+
for (const field of ["prefix", ...QUERY_EDGES]) {
|
|
135
|
+
checkKey(query[field], field);
|
|
136
|
+
}
|
|
137
|
+
for (const key of rangeBounds(query)) checkKey(key, "range");
|
|
138
|
+
return query;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Lists the closed bounds of a checked query's range. A `null` bound is open.
|
|
143
|
+
* @param {object} query - A query checked by {@link queryOptions}.
|
|
144
|
+
* @returns {Array<*>} The bounds that are not `null`.
|
|
145
|
+
* @private
|
|
146
|
+
*/
|
|
147
|
+
function rangeBounds(query) {
|
|
148
|
+
return (query.range ?? []).filter((bound) => bound !== null);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Checks a string-key query option.
|
|
153
|
+
* @param {*} key - The option value, or `undefined` when it is not set.
|
|
154
|
+
* @param {string} field - The option name.
|
|
155
|
+
* @throws {TypeError} If the value is not a string.
|
|
156
|
+
* @private
|
|
157
|
+
*/
|
|
158
|
+
function checkKey(key, field) {
|
|
159
|
+
if (key !== undefined && typeof key !== "string") {
|
|
160
|
+
throw new TypeError(
|
|
161
|
+
`${field}: expected a string key, got ${describeValue(key)}`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Checks the options of a deque query. Positions count from the front and
|
|
168
|
+
* must be non-negative.
|
|
169
|
+
* @param {string|object} [options] - A scan direction or a position query.
|
|
170
|
+
* @returns {object} The position query.
|
|
171
|
+
* @throws {TypeError|RangeError} If an option is invalid.
|
|
172
|
+
* @private
|
|
173
|
+
*/
|
|
174
|
+
function positionQuery(options) {
|
|
175
|
+
const query = queryOptions(options, POSITION_QUERY_FIELDS);
|
|
176
|
+
for (const field of QUERY_EDGES) checkCount(query[field], field, 0);
|
|
177
|
+
for (const position of rangeBounds(query)) checkCount(position, "range", 0);
|
|
178
|
+
return query;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Resolves an `at` index to a front position. A negative index counts from
|
|
183
|
+
* the back and reads the length. The handler owns the deque, so nothing
|
|
184
|
+
* changes it between the reads.
|
|
185
|
+
* @param {*} index - The caller's index.
|
|
186
|
+
* @param {() => Promise<number>} length - Reads the deque length.
|
|
187
|
+
* @returns {Promise<number|null>} The position, or null outside the deque.
|
|
188
|
+
* @throws {TransientStateError} If `index` is not a safe integer.
|
|
189
|
+
* @private
|
|
190
|
+
*/
|
|
191
|
+
async function dequePosition(index, length) {
|
|
192
|
+
if (!Number.isSafeInteger(index)) {
|
|
193
|
+
throw new TransientStateError(
|
|
194
|
+
`at: index must be a safe integer, got ${describeValue(index)}`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
const position = index < 0 ? index + (await length()) : index;
|
|
198
|
+
// Native get takes a u32. A larger position is past the end.
|
|
199
|
+
return position < 0 || position > 0xffffffff ? null : position;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = {
|
|
203
|
+
dequePosition,
|
|
204
|
+
keyQuery,
|
|
205
|
+
positionQuery,
|
|
206
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ordered-set keyed-state handle.
|
|
3
|
+
* @module lib/state/set
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { StateTransaction } from "./handle";
|
|
7
|
+
import type { KeyQueryOptions, ScanDirection } from "./query";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handle over a presence-only ordered set of string members, vended by
|
|
11
|
+
* `Context.state()`. It mirrors the JavaScript `Set` with asynchronous
|
|
12
|
+
* methods. Valid only within the handler invocation (attempt) that vended it.
|
|
13
|
+
* A failed call rejects with a {@link PermanentStateError} or a
|
|
14
|
+
* {@link TransientStateError}.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SetState {
|
|
17
|
+
/** Vended only by {@link Context#state}; not constructible directly. */
|
|
18
|
+
private constructor(native: unknown);
|
|
19
|
+
/** Adds `member` to the set. */
|
|
20
|
+
add(member: string): Promise<void>;
|
|
21
|
+
/** Reports whether `member` belongs to the set. */
|
|
22
|
+
has(member: string): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Tests several members in one read. `result[i]` answers `members[i]`.
|
|
25
|
+
*/
|
|
26
|
+
hasMany(members: readonly string[]): Promise<boolean[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Removes `member`. An absent member is not an error. Unlike `Set#delete`,
|
|
29
|
+
* this returns no "was present" flag, because that flag needs a read.
|
|
30
|
+
*/
|
|
31
|
+
delete(member: string): Promise<void>;
|
|
32
|
+
/** Removes every member. */
|
|
33
|
+
clear(): Promise<void>;
|
|
34
|
+
/** Reports whether the set has no live members. */
|
|
35
|
+
isEmpty(): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* Async iterator over the members in order. Pass a direction or a
|
|
38
|
+
* {@link KeyQueryOptions} to select members. Early exit from a `for await` loop
|
|
39
|
+
* closes the underlying cursor.
|
|
40
|
+
*/
|
|
41
|
+
keys(
|
|
42
|
+
options?: ScanDirection | KeyQueryOptions,
|
|
43
|
+
): AsyncIterableIterator<string>;
|
|
44
|
+
/** The same iterator as {@link SetState#keys}, as on the JavaScript `Set`. */
|
|
45
|
+
values(
|
|
46
|
+
options?: ScanDirection | KeyQueryOptions,
|
|
47
|
+
): AsyncIterableIterator<string>;
|
|
48
|
+
/** Forward iteration over the members. */
|
|
49
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<string>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SetState extends StateTransaction {}
|
package/lib/state/set.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ordered-set keyed-state handle.
|
|
3
|
+
* @module lib/state/set
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { stateOp } = require("./bridge");
|
|
8
|
+
const { StateHandle } = require("./handle");
|
|
9
|
+
const { stateIterator } = require("./iterator");
|
|
10
|
+
const { keyQuery } = require("./query");
|
|
11
|
+
|
|
12
|
+
/** Handle over a presence-only ordered set of string members. */
|
|
13
|
+
class SetState extends StateHandle {
|
|
14
|
+
add(member) {
|
|
15
|
+
return stateOp((carrier) => this.native.insert(member, carrier));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
has(member) {
|
|
19
|
+
return stateOp((carrier) => this.native.contains(member, carrier));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
hasMany(members) {
|
|
23
|
+
return stateOp((carrier) => this.native.containsMany(members, carrier));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
delete(member) {
|
|
27
|
+
return stateOp((carrier) => this.native.remove(member, carrier));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
clear() {
|
|
31
|
+
return stateOp((carrier) => this.native.clear(carrier));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
isEmpty() {
|
|
35
|
+
return stateOp((carrier) => this.native.isEmpty(carrier));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
keys(options) {
|
|
39
|
+
const query = keyQuery(options);
|
|
40
|
+
return stateIterator(this.native.keys(query), (member) => member);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
values(options) {
|
|
44
|
+
return this.keys(options);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[Symbol.asyncIterator]() {
|
|
48
|
+
return this.values();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
SetState,
|
|
54
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single-value keyed-state handle.
|
|
3
|
+
* @module lib/state/value
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { JsonValue } from "../payload";
|
|
7
|
+
import type { StateTransaction } from "./handle";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typed handle over a single-value keyed-state collection, vended by
|
|
11
|
+
* `Context.state()`. Valid only within the handler invocation (attempt) that
|
|
12
|
+
* vended it. Every method opens its own per-operation trace span.
|
|
13
|
+
* A failed call rejects with a {@link PermanentStateError} or a
|
|
14
|
+
* {@link TransientStateError}. A write of a value with no JSON form rejects
|
|
15
|
+
* with a {@link TransientStateError}.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ValueState<T = JsonValue> {
|
|
18
|
+
/** Vended only by {@link Context#state}; not constructible directly. */
|
|
19
|
+
private constructor(native: unknown);
|
|
20
|
+
/** Reads the current value, or null when absent/cleared. */
|
|
21
|
+
get(): Promise<T | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Buffers a write of the value. The parameter type excludes `null` and
|
|
24
|
+
* `undefined`, because a top-level `null` is not a storable value. At run
|
|
25
|
+
* time Prosody rejects JSON `null` with a {@link PermanentStateError}; use
|
|
26
|
+
* {@link ValueState#clear} to delete. A nested `null` is stored.
|
|
27
|
+
*/
|
|
28
|
+
set(value: NonNullable<T>): Promise<void>;
|
|
29
|
+
/** Deletes the stored value. */
|
|
30
|
+
clear(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ValueState<T = JsonValue> extends StateTransaction {}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single-value keyed-state handle.
|
|
3
|
+
* @module lib/state/value
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { stateOp } = require("./bridge");
|
|
8
|
+
const { StateHandle } = require("./handle");
|
|
9
|
+
|
|
10
|
+
/** Typed handle over a single-value keyed-state collection. */
|
|
11
|
+
class ValueState extends StateHandle {
|
|
12
|
+
get() {
|
|
13
|
+
return stateOp((carrier) => this.native.get(carrier)).then(
|
|
14
|
+
this.items.decode,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
set(value) {
|
|
19
|
+
return stateOp((carrier) =>
|
|
20
|
+
this.native.set(this.items.encode(value), carrier),
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
clear() {
|
|
25
|
+
return stateOp((carrier) => this.native.clear(carrier));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
ValueState,
|
|
31
|
+
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosody-events/prosody",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.js",
|
|
8
8
|
"index.d.ts",
|
|
9
|
+
"lib",
|
|
9
10
|
"bindings.js",
|
|
10
11
|
"bindings.d.ts",
|
|
11
12
|
"README.md"
|
|
@@ -30,24 +31,24 @@
|
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
33
|
"@opentelemetry/api": "^1.9.1",
|
|
33
|
-
"@opentelemetry/exporter-trace-otlp-proto": "^0.
|
|
34
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.222.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@babel/core": "^8",
|
|
37
38
|
"@babel/plugin-proposal-decorators": "^8",
|
|
38
39
|
"@babel/preset-env": "^8",
|
|
39
|
-
"@napi-rs/cli": "^3.
|
|
40
|
-
"@opentelemetry/auto-instrumentations-node": "^0.
|
|
41
|
-
"@opentelemetry/core": "^2.
|
|
42
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
43
|
-
"@opentelemetry/sdk-metrics": "^2.
|
|
44
|
-
"@opentelemetry/sdk-node": "^0.
|
|
45
|
-
"@opentelemetry/sdk-trace-base": "^2.
|
|
46
|
-
"@opentelemetry/sdk-trace-node": "^2.
|
|
47
|
-
"@sentry/node": "^
|
|
48
|
-
"@types/node": "^
|
|
49
|
-
"jest": "^30.
|
|
50
|
-
"prettier": "^3.9.
|
|
40
|
+
"@napi-rs/cli": "^3.10.5",
|
|
41
|
+
"@opentelemetry/auto-instrumentations-node": "^0.80.0",
|
|
42
|
+
"@opentelemetry/core": "^2.11.0",
|
|
43
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
|
|
44
|
+
"@opentelemetry/sdk-metrics": "^2.11.0",
|
|
45
|
+
"@opentelemetry/sdk-node": "^0.222.0",
|
|
46
|
+
"@opentelemetry/sdk-trace-base": "^2.11.0",
|
|
47
|
+
"@opentelemetry/sdk-trace-node": "^2.11.0",
|
|
48
|
+
"@sentry/node": "^11.1.0",
|
|
49
|
+
"@types/node": "^26",
|
|
50
|
+
"jest": "^30.5.2",
|
|
51
|
+
"prettier": "^3.9.9",
|
|
51
52
|
"typescript": "^7.0.2",
|
|
52
53
|
"yarn-upgrade-all": "^0.8.1"
|
|
53
54
|
},
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
"universal": "napi universalize",
|
|
67
68
|
"version": "napi version"
|
|
68
69
|
},
|
|
69
|
-
"packageManager": "yarn@4.
|
|
70
|
+
"packageManager": "yarn@4.18.1",
|
|
70
71
|
"repository": {
|
|
71
72
|
"type": "git",
|
|
72
73
|
"url": "git+https://github.com/prosody-events/prosody-js.git"
|
|
@@ -77,9 +78,9 @@
|
|
|
77
78
|
"access": "public"
|
|
78
79
|
},
|
|
79
80
|
"optionalDependencies": {
|
|
80
|
-
"@prosody-events/prosody-linux-x64-gnu": "0.
|
|
81
|
-
"@prosody-events/prosody-win32-x64-msvc": "0.
|
|
82
|
-
"@prosody-events/prosody-darwin-arm64": "0.
|
|
83
|
-
"@prosody-events/prosody-linux-arm64-gnu": "0.
|
|
81
|
+
"@prosody-events/prosody-linux-x64-gnu": "0.6.1",
|
|
82
|
+
"@prosody-events/prosody-win32-x64-msvc": "0.6.1",
|
|
83
|
+
"@prosody-events/prosody-darwin-arm64": "0.6.1",
|
|
84
|
+
"@prosody-events/prosody-linux-arm64-gnu": "0.6.1"
|
|
84
85
|
}
|
|
85
|
-
}
|
|
86
|
+
}
|