@rilong/grammyjs-conversations-esm 2.0.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/LICENSE +21 -0
- package/README.md +59 -0
- package/out/conversation.d.ts +885 -0
- package/out/conversation.js +832 -0
- package/out/deps.node.d.ts +2 -0
- package/out/deps.node.js +1 -0
- package/out/engine.d.ts +212 -0
- package/out/engine.js +238 -0
- package/out/form.d.ts +530 -0
- package/out/form.js +598 -0
- package/out/menu.d.ts +593 -0
- package/out/menu.js +698 -0
- package/out/mod.d.ts +8 -0
- package/out/mod.js +8 -0
- package/out/nope.d.ts +16 -0
- package/out/nope.js +35 -0
- package/out/plugin.d.ts +678 -0
- package/out/plugin.js +578 -0
- package/out/resolve.d.ts +43 -0
- package/out/resolve.js +21 -0
- package/out/state.d.ts +147 -0
- package/out/state.js +125 -0
- package/out/storage.d.ts +169 -0
- package/out/storage.js +105 -0
- package/package.json +43 -0
package/out/state.d.ts
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
/**
|
2
|
+
* A replay state.
|
3
|
+
*
|
4
|
+
* A replay state consists of two logs of operations.
|
5
|
+
*
|
6
|
+
* 1. A send log which records send operations in the shape of {@link SendOp}
|
7
|
+
* 2. A receive log which records receive operations in the shape of
|
8
|
+
* {@link ReceiveOp}
|
9
|
+
*
|
10
|
+
* Note that each receive op links to a specific send op. A valid replay state
|
11
|
+
* should only contain receive ops that point to send ops contained in the same
|
12
|
+
* replay state.
|
13
|
+
*
|
14
|
+
* A replay state can be created using {@link create}.
|
15
|
+
*/
|
16
|
+
export interface ReplayState {
|
17
|
+
/** The send log of the replay state */
|
18
|
+
send: SendOp[];
|
19
|
+
/** The receive log of the replay state */
|
20
|
+
receive: ReceiveOp[];
|
21
|
+
}
|
22
|
+
/** A send operation */
|
23
|
+
export interface SendOp {
|
24
|
+
/** Any string payload for the send operation */
|
25
|
+
payload: string;
|
26
|
+
}
|
27
|
+
/** A receive operation */
|
28
|
+
export interface ReceiveOp {
|
29
|
+
/** The identifier (index in a send log) of a send op */
|
30
|
+
send: number;
|
31
|
+
/** The received value */
|
32
|
+
returnValue: unknown;
|
33
|
+
}
|
34
|
+
/** A checkpoint in a replay log */
|
35
|
+
export type Checkpoint = [number, number];
|
36
|
+
/**
|
37
|
+
* Creates and returns an empty {@link ReplayState} object.
|
38
|
+
*
|
39
|
+
* The returned replay state can be inspected via {@link inspect}, mutated via
|
40
|
+
* {@link mutate}, and replayed via {@link cursor}.
|
41
|
+
*/
|
42
|
+
export declare function create(): ReplayState;
|
43
|
+
/**
|
44
|
+
* Holds a number of tools that can be used to inspect a replay state.
|
45
|
+
*
|
46
|
+
* This object is typically created via {@link inspect}.
|
47
|
+
*/
|
48
|
+
export interface InspectTools {
|
49
|
+
/** Gets the number of send ops */
|
50
|
+
opCount(): number;
|
51
|
+
/** Gets the number of receive ops */
|
52
|
+
doneCount(): number;
|
53
|
+
/** Looks up the payload of a send op */
|
54
|
+
payload(op: number): string;
|
55
|
+
/** Creates a checkpoint for the current replay state */
|
56
|
+
checkpoint(): Checkpoint;
|
57
|
+
}
|
58
|
+
/**
|
59
|
+
* Provides inspections tools for a given replay state.
|
60
|
+
*
|
61
|
+
* @param state The replay state to inspect
|
62
|
+
*/
|
63
|
+
export declare function inspect(state: ReplayState): InspectTools;
|
64
|
+
/**
|
65
|
+
* Holds a number of tools that can be used to mutate a replay state.
|
66
|
+
*
|
67
|
+
* This object is typically created via {@link mutate}.
|
68
|
+
*/
|
69
|
+
export interface MutateTools {
|
70
|
+
/**
|
71
|
+
* Begins an op by recording a send op. Returns the send op identifier.
|
72
|
+
*
|
73
|
+
* @param payload A payload to send
|
74
|
+
*/
|
75
|
+
op(payload: string): number;
|
76
|
+
/**
|
77
|
+
* Completes an op by recording a receive op for a given send op.
|
78
|
+
*
|
79
|
+
* @param op The identifier of the send op to complete.
|
80
|
+
* @param result The result of the op
|
81
|
+
*/
|
82
|
+
done(op: number, result: unknown): void;
|
83
|
+
/**
|
84
|
+
* Resets the replay state to a given checkpoint that was obtained
|
85
|
+
* previously through {@link inspect}ion of the replay state.
|
86
|
+
*
|
87
|
+
* @param checkpoint The known checkpoint
|
88
|
+
*/
|
89
|
+
reset([op, done]: Checkpoint): void;
|
90
|
+
}
|
91
|
+
/**
|
92
|
+
* Provides tools to mutate a given replay state.
|
93
|
+
*
|
94
|
+
* @param state The replay state to mutate
|
95
|
+
*/
|
96
|
+
export declare function mutate(state: ReplayState): MutateTools;
|
97
|
+
/**
|
98
|
+
* Can be used to iterate a given replay state.
|
99
|
+
*
|
100
|
+
* This object is typically created via {@link cursor}.
|
101
|
+
*
|
102
|
+
* Note that this object holds state outside of the replay state itself, namely
|
103
|
+
* the current position of the cursor.
|
104
|
+
*/
|
105
|
+
export interface ReplayCursor {
|
106
|
+
/**
|
107
|
+
* Performs an action at the current position of the replay cursor, records
|
108
|
+
* its result in the replay state, and advances the cursor.
|
109
|
+
*
|
110
|
+
* Note that if the cursor has not reached the end of the replay state yet,
|
111
|
+
* the action will be replayed from the log.
|
112
|
+
*
|
113
|
+
* @param action The action to perform, receiving a send op identifer
|
114
|
+
* @param payload The payload to assign to this action
|
115
|
+
*/
|
116
|
+
perform(action: (op: number) => unknown | Promise<unknown>, payload: string): Promise<unknown>;
|
117
|
+
/**
|
118
|
+
* Begins a new op at the current position of the replay cursor, and
|
119
|
+
* advances the cursor.
|
120
|
+
*
|
121
|
+
* Note that if the cursor has not reached the end of the replay state yet,
|
122
|
+
* the op will be taken from the log.
|
123
|
+
*
|
124
|
+
* @param payload The payload to assign to this op
|
125
|
+
*/
|
126
|
+
op(payload: string): number;
|
127
|
+
/**
|
128
|
+
* Completes a given op with the result obtained from a callback function,
|
129
|
+
* and advances the cursor.
|
130
|
+
*
|
131
|
+
* Note that if the cursor has not reached the end of the replay state yet,
|
132
|
+
* the callback function will not be invoked. Instead, the result will be
|
133
|
+
* replayed from the log.
|
134
|
+
*
|
135
|
+
* @param op The op to complete
|
136
|
+
* @param result The result to record
|
137
|
+
*/
|
138
|
+
done(op: number, result: () => unknown | Promise<unknown>): Promise<unknown>;
|
139
|
+
/** Creates a checkpoint at the current state of the cursor */
|
140
|
+
checkpoint(): Checkpoint;
|
141
|
+
}
|
142
|
+
/**
|
143
|
+
* Provides tools to iterate a given replay state.
|
144
|
+
*
|
145
|
+
* @param state The replay state to iterate
|
146
|
+
*/
|
147
|
+
export declare function cursor(state: ReplayState): ReplayCursor;
|
package/out/state.js
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
import { resolver } from "./resolve.js";
|
2
|
+
/**
|
3
|
+
* Creates and returns an empty {@link ReplayState} object.
|
4
|
+
*
|
5
|
+
* The returned replay state can be inspected via {@link inspect}, mutated via
|
6
|
+
* {@link mutate}, and replayed via {@link cursor}.
|
7
|
+
*/
|
8
|
+
export function create() {
|
9
|
+
return { send: [], receive: [] };
|
10
|
+
}
|
11
|
+
/**
|
12
|
+
* Provides inspections tools for a given replay state.
|
13
|
+
*
|
14
|
+
* @param state The replay state to inspect
|
15
|
+
*/
|
16
|
+
export function inspect(state) {
|
17
|
+
function opCount() {
|
18
|
+
return state.send.length;
|
19
|
+
}
|
20
|
+
function doneCount() {
|
21
|
+
return state.receive.length;
|
22
|
+
}
|
23
|
+
function payload(op) {
|
24
|
+
if (op < 0)
|
25
|
+
throw new Error(`Op ${op} is invalid`);
|
26
|
+
if (op >= state.send.length)
|
27
|
+
throw new Error(`No op ${op} in state`);
|
28
|
+
return state.send[op].payload;
|
29
|
+
}
|
30
|
+
function checkpoint() {
|
31
|
+
return [opCount(), doneCount()];
|
32
|
+
}
|
33
|
+
return { opCount, doneCount, payload, checkpoint };
|
34
|
+
}
|
35
|
+
/**
|
36
|
+
* Provides tools to mutate a given replay state.
|
37
|
+
*
|
38
|
+
* @param state The replay state to mutate
|
39
|
+
*/
|
40
|
+
export function mutate(state) {
|
41
|
+
function op(payload) {
|
42
|
+
const index = state.send.length;
|
43
|
+
state.send.push({ payload });
|
44
|
+
return index;
|
45
|
+
}
|
46
|
+
function done(op, result) {
|
47
|
+
if (op < 0)
|
48
|
+
throw new Error(`Op ${op} is invalid`);
|
49
|
+
if (op >= state.send.length)
|
50
|
+
throw new Error(`No op ${op} in state`);
|
51
|
+
state.receive.push({ send: op, returnValue: result });
|
52
|
+
}
|
53
|
+
function reset([op, done]) {
|
54
|
+
if (op < 0 || done < 0)
|
55
|
+
throw new Error("Invalid checkpoint");
|
56
|
+
state.send.splice(op);
|
57
|
+
state.receive.splice(done);
|
58
|
+
}
|
59
|
+
return { op, done, reset };
|
60
|
+
}
|
61
|
+
/**
|
62
|
+
* Provides tools to iterate a given replay state.
|
63
|
+
*
|
64
|
+
* @param state The replay state to iterate
|
65
|
+
*/
|
66
|
+
export function cursor(state) {
|
67
|
+
let changes = resolver();
|
68
|
+
function notify() {
|
69
|
+
changes.resolve();
|
70
|
+
changes = resolver();
|
71
|
+
}
|
72
|
+
let send = 0; // 0 <= send <= state.send.length
|
73
|
+
let receive = 0; // 0 <= receive <= state.receive.length
|
74
|
+
function op(payload) {
|
75
|
+
if (send < state.send.length) {
|
76
|
+
// replay existing data (do nothing)
|
77
|
+
const expected = state.send[send].payload;
|
78
|
+
if (expected !== payload) {
|
79
|
+
throw new Error(`Bad replay, expected op '${expected}'`);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
else { // send === state.send.length
|
83
|
+
// log new data
|
84
|
+
state.send.push({ payload });
|
85
|
+
}
|
86
|
+
const index = send++;
|
87
|
+
notify();
|
88
|
+
return index;
|
89
|
+
}
|
90
|
+
async function done(op, result) {
|
91
|
+
if (op < 0)
|
92
|
+
throw new Error(`Op ${op} is invalid`);
|
93
|
+
if (op >= state.send.length)
|
94
|
+
throw new Error(`No op ${op} in state`);
|
95
|
+
let data;
|
96
|
+
if (receive < state.receive.length) {
|
97
|
+
// replay existing data (do nothing)
|
98
|
+
while (state.receive[receive].send !== op) {
|
99
|
+
// make sure we resolve only when it is our turn
|
100
|
+
await changes.promise;
|
101
|
+
if (receive === state.receive.length) {
|
102
|
+
// It will never be our turn, because the replay completed
|
103
|
+
// and we are still here. We will have to call `result`.
|
104
|
+
return await done(op, result);
|
105
|
+
}
|
106
|
+
} // state.receive[receive].send === op
|
107
|
+
data = state.receive[receive].returnValue;
|
108
|
+
}
|
109
|
+
else { // receive === state.receive.length
|
110
|
+
data = await result();
|
111
|
+
state.receive.push({ send: op, returnValue: data });
|
112
|
+
}
|
113
|
+
receive++;
|
114
|
+
notify();
|
115
|
+
return data;
|
116
|
+
}
|
117
|
+
async function perform(action, payload) {
|
118
|
+
const index = op(payload);
|
119
|
+
return await done(index, () => action(index));
|
120
|
+
}
|
121
|
+
function checkpoint() {
|
122
|
+
return [send, receive];
|
123
|
+
}
|
124
|
+
return { perform, op, done, checkpoint };
|
125
|
+
}
|
package/out/storage.d.ts
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
import type { Context } from "./deps.node.js";
|
2
|
+
/** Current data version of this plugin */
|
3
|
+
export declare const PLUGIN_DATA_VERSION = 0;
|
4
|
+
/**
|
5
|
+
* A value with a version.
|
6
|
+
*
|
7
|
+
* The version consists of two pieces.
|
8
|
+
*
|
9
|
+
* The first piece is a number that is defined by the plugin internally and
|
10
|
+
* cannot be changed. When the plugin is updated and it changes its internal
|
11
|
+
* data format, then it can use this part of the version to detect and
|
12
|
+
* automatically migrate the versioned state as necessary.
|
13
|
+
*
|
14
|
+
* The second piece is a number or a string and can be set by the developer. It
|
15
|
+
* should be changed whenever the application code changes in a way that
|
16
|
+
* invalidates the state. The plugin can then discard and re-create the state as
|
17
|
+
* necesarry.
|
18
|
+
*
|
19
|
+
* Versioned states are typically created via the {@link pinVersion} function.
|
20
|
+
*
|
21
|
+
* @typeParam S The type of the state to be versioned
|
22
|
+
*/
|
23
|
+
export interface VersionedState<S> {
|
24
|
+
/** The version of the state */
|
25
|
+
version: [typeof PLUGIN_DATA_VERSION, string | number];
|
26
|
+
/** The state to be versioned */
|
27
|
+
state: S;
|
28
|
+
}
|
29
|
+
/**
|
30
|
+
* A container for two functions that are pinned to a specific version. The two
|
31
|
+
* functions can be used to add the bound version to data, and to unpack the
|
32
|
+
* data again. This container is typically created using {@link pinVersion}.
|
33
|
+
*/
|
34
|
+
export interface PinnedVersion {
|
35
|
+
/**
|
36
|
+
* Adds a version to some data.
|
37
|
+
*
|
38
|
+
* @param state Some data
|
39
|
+
*/
|
40
|
+
versionify<S>(state: S): VersionedState<S>;
|
41
|
+
/**
|
42
|
+
* Unpacks some versioned data. Returns the original data if the data is
|
43
|
+
* correct, and `undefined` otherwise. If `undefined` is passed, then
|
44
|
+
* `undefined` will be returned.
|
45
|
+
*
|
46
|
+
* @param data Some versioned data or `undefined`
|
47
|
+
*/
|
48
|
+
unpack<S>(data?: VersionedState<S>): S | undefined;
|
49
|
+
}
|
50
|
+
/**
|
51
|
+
* Takes a version number and state management functions that are pinned to this
|
52
|
+
* version.
|
53
|
+
*
|
54
|
+
* The two functions it returns are `versionify` and `unpack`. The former can be
|
55
|
+
* used to add a version to some data. The latter can be used to unpack the data
|
56
|
+
* again, validating the version on the fly.
|
57
|
+
*
|
58
|
+
* ```ts
|
59
|
+
* import { assert } from "jsr:@std/assert";
|
60
|
+
*
|
61
|
+
* const { versionify, unpack } = pinVersion(42);
|
62
|
+
*
|
63
|
+
* const data = { prop: "pizza" };
|
64
|
+
* const versioned = versionify(data);
|
65
|
+
* const unpacked = unpack(versioned);
|
66
|
+
* assert(data === unpacked);
|
67
|
+
* ```
|
68
|
+
*
|
69
|
+
* @param version the version to use for pinning
|
70
|
+
*/
|
71
|
+
export declare function pinVersion(version: string | number): PinnedVersion;
|
72
|
+
/**
|
73
|
+
* A value or a promise of a value.
|
74
|
+
*
|
75
|
+
* @typeParam T The type of value
|
76
|
+
*/
|
77
|
+
export type MaybePromise<T> = T | Promise<T>;
|
78
|
+
/**
|
79
|
+
* A storage for versioned state.
|
80
|
+
*
|
81
|
+
* Specify this to define how to persist data.
|
82
|
+
*
|
83
|
+
* This type is a union of three types, each representing a different way to
|
84
|
+
* store data.
|
85
|
+
*
|
86
|
+
* 1. A {@link VersionedStateStorage} directly provides definitions for reading,
|
87
|
+
* writing, and deleting data based on `ctx.chatId`. No versions can be
|
88
|
+
* specified and the storage key function cannot be changed.
|
89
|
+
* 2. A {@link ConversationKeyStorage}, disambiguated via `{ type: "key" }`, is
|
90
|
+
* more general. It supports versioning the data and changing the storage key
|
91
|
+
* function.
|
92
|
+
* 3. A {@link ConversationContextStorage}, disambiguated via `{ type: "context"
|
93
|
+
* }`, is even more general. It no longer needs a storage key function.
|
94
|
+
* Instead, it provides read, write, and delete operations for data based on
|
95
|
+
* the context object directly. It also supports versioning data.
|
96
|
+
*
|
97
|
+
* @typeParam C A custom context type
|
98
|
+
* @typeParam S A type for the state to version and store
|
99
|
+
*/
|
100
|
+
export type ConversationStorage<C extends Context, S> = {
|
101
|
+
type?: never;
|
102
|
+
version?: never;
|
103
|
+
} & VersionedStateStorage<string, S> | ConversationContextStorage<C, S> | ConversationKeyStorage<C, S>;
|
104
|
+
/**
|
105
|
+
* An object that defines how to read, write, and delete versioned data based on
|
106
|
+
* a key.
|
107
|
+
*
|
108
|
+
* @typeParam K The type of key to use
|
109
|
+
* @typeParam S The type of data to store
|
110
|
+
*/
|
111
|
+
export interface VersionedStateStorage<K, S> {
|
112
|
+
/**
|
113
|
+
* Reads the data for a given key.
|
114
|
+
*
|
115
|
+
* @param key A key to identify the data
|
116
|
+
*/
|
117
|
+
read(key: K): MaybePromise<VersionedState<S> | undefined>;
|
118
|
+
/**
|
119
|
+
* Writes some data to the storage for a given key.
|
120
|
+
*
|
121
|
+
* @param key A key to identify the data
|
122
|
+
* @param state The data to write
|
123
|
+
*/
|
124
|
+
write(key: K, state: VersionedState<S>): MaybePromise<void>;
|
125
|
+
/**
|
126
|
+
* Deletes some data from the storage for a given key.
|
127
|
+
*
|
128
|
+
* @param key A key to identify the data
|
129
|
+
*/
|
130
|
+
delete(key: K): MaybePromise<void>;
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* An object that defines how to read, write, or delete versioned data based on
|
134
|
+
* a context object.
|
135
|
+
*/
|
136
|
+
export interface ConversationContextStorage<C extends Context, S> {
|
137
|
+
/** The type of storage, always `"context"` */
|
138
|
+
type: "context";
|
139
|
+
/** An optional version for the data, defaults to `0` */
|
140
|
+
version?: string | number;
|
141
|
+
/** The underlying storage that defines how to read and write raw data */
|
142
|
+
adapter: VersionedStateStorage<C, S>;
|
143
|
+
}
|
144
|
+
export interface ConversationKeyStorage<C extends Context, S> {
|
145
|
+
/** The type of storage, always `"key"` */
|
146
|
+
type: "key";
|
147
|
+
/** An optional version for the data, defaults to `0` */
|
148
|
+
version?: string | number;
|
149
|
+
/** An optional prefix to prepend to the storage key */
|
150
|
+
prefix?: string;
|
151
|
+
/** An optional storage key function, defaults to `ctx.chatId` */
|
152
|
+
getStorageKey?(ctx: C): string | undefined;
|
153
|
+
/** The underlying storage that defines how to read and write raw data */
|
154
|
+
adapter: VersionedStateStorage<string, S>;
|
155
|
+
}
|
156
|
+
/**
|
157
|
+
* Coerces different storages to a single uniform abstraction.
|
158
|
+
*
|
159
|
+
* This function takes a {@link ConversationStorage} object and unifies its
|
160
|
+
* union members behind a common abstraction that simply exposes a read, write,
|
161
|
+
* and delete method for a given context object.
|
162
|
+
*
|
163
|
+
* @param storage An object defining how to store data
|
164
|
+
*/
|
165
|
+
export declare function uniformStorage<C extends Context, S>(storage?: ConversationStorage<C, S>): (ctx: C) => {
|
166
|
+
read: () => MaybePromise<S | undefined>;
|
167
|
+
write: (state: S) => MaybePromise<void>;
|
168
|
+
delete: () => MaybePromise<void>;
|
169
|
+
};
|
package/out/storage.js
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
/** Current data version of this plugin */
|
2
|
+
export const PLUGIN_DATA_VERSION = 0;
|
3
|
+
/**
|
4
|
+
* Takes a version number and state management functions that are pinned to this
|
5
|
+
* version.
|
6
|
+
*
|
7
|
+
* The two functions it returns are `versionify` and `unpack`. The former can be
|
8
|
+
* used to add a version to some data. The latter can be used to unpack the data
|
9
|
+
* again, validating the version on the fly.
|
10
|
+
*
|
11
|
+
* ```ts
|
12
|
+
* import { assert } from "jsr:@std/assert";
|
13
|
+
*
|
14
|
+
* const { versionify, unpack } = pinVersion(42);
|
15
|
+
*
|
16
|
+
* const data = { prop: "pizza" };
|
17
|
+
* const versioned = versionify(data);
|
18
|
+
* const unpacked = unpack(versioned);
|
19
|
+
* assert(data === unpacked);
|
20
|
+
* ```
|
21
|
+
*
|
22
|
+
* @param version the version to use for pinning
|
23
|
+
*/
|
24
|
+
export function pinVersion(version) {
|
25
|
+
function versionify(state) {
|
26
|
+
return { version: [PLUGIN_DATA_VERSION, version], state };
|
27
|
+
}
|
28
|
+
function unpack(data) {
|
29
|
+
if (data === undefined)
|
30
|
+
return undefined;
|
31
|
+
if (!Array.isArray(data.version)) {
|
32
|
+
throw new Error("Unknown data format, cannot parse version");
|
33
|
+
}
|
34
|
+
const [pluginVersion, dataVersion] = data.version;
|
35
|
+
if (dataVersion !== version)
|
36
|
+
return undefined;
|
37
|
+
if (pluginVersion !== PLUGIN_DATA_VERSION) {
|
38
|
+
// In the future, we might want to migrate the data from an old
|
39
|
+
// plugin version to a new one here.
|
40
|
+
return undefined;
|
41
|
+
}
|
42
|
+
return data.state;
|
43
|
+
}
|
44
|
+
return { versionify, unpack };
|
45
|
+
}
|
46
|
+
function defaultStorageKey(ctx) {
|
47
|
+
var _a;
|
48
|
+
return (_a = ctx.chatId) === null || _a === void 0 ? void 0 : _a.toString();
|
49
|
+
}
|
50
|
+
function defaultStorage() {
|
51
|
+
const store = new Map();
|
52
|
+
return {
|
53
|
+
type: "key",
|
54
|
+
adapter: {
|
55
|
+
read: (key) => store.get(key),
|
56
|
+
write: (key, state) => void store.set(key, state),
|
57
|
+
delete: (key) => void store.delete(key),
|
58
|
+
},
|
59
|
+
};
|
60
|
+
}
|
61
|
+
/**
|
62
|
+
* Coerces different storages to a single uniform abstraction.
|
63
|
+
*
|
64
|
+
* This function takes a {@link ConversationStorage} object and unifies its
|
65
|
+
* union members behind a common abstraction that simply exposes a read, write,
|
66
|
+
* and delete method for a given context object.
|
67
|
+
*
|
68
|
+
* @param storage An object defining how to store data
|
69
|
+
*/
|
70
|
+
export function uniformStorage(storage) {
|
71
|
+
var _a;
|
72
|
+
storage !== null && storage !== void 0 ? storage : (storage = defaultStorage());
|
73
|
+
if (storage.type === undefined) {
|
74
|
+
return uniformStorage({ type: "key", adapter: storage });
|
75
|
+
}
|
76
|
+
const version = (_a = storage.version) !== null && _a !== void 0 ? _a : 0;
|
77
|
+
const { versionify, unpack } = pinVersion(version);
|
78
|
+
if (storage.type === "key") {
|
79
|
+
const { getStorageKey = defaultStorageKey, prefix = "", adapter } = storage;
|
80
|
+
return (ctx) => {
|
81
|
+
const key = prefix + getStorageKey(ctx);
|
82
|
+
return key === undefined
|
83
|
+
? {
|
84
|
+
read: () => undefined,
|
85
|
+
write: () => undefined,
|
86
|
+
delete: () => undefined,
|
87
|
+
}
|
88
|
+
: {
|
89
|
+
read: async () => unpack(await adapter.read(key)),
|
90
|
+
write: (state) => adapter.write(key, versionify(state)),
|
91
|
+
delete: () => adapter.delete(key),
|
92
|
+
};
|
93
|
+
};
|
94
|
+
}
|
95
|
+
else {
|
96
|
+
const { adapter } = storage;
|
97
|
+
return (ctx) => {
|
98
|
+
return {
|
99
|
+
read: async () => unpack(await adapter.read(ctx)),
|
100
|
+
write: (state) => adapter.write(ctx, versionify(state)),
|
101
|
+
delete: () => adapter.delete(ctx),
|
102
|
+
};
|
103
|
+
};
|
104
|
+
}
|
105
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
{
|
2
|
+
"name": "@rilong/grammyjs-conversations-esm",
|
3
|
+
"description": "Conversational interfaces for grammY",
|
4
|
+
"version": "2.0.2",
|
5
|
+
"author": "KnorpelSenf",
|
6
|
+
"license": "MIT",
|
7
|
+
"engines": {
|
8
|
+
"node": "^12.20.0 || >=14.13.1"
|
9
|
+
},
|
10
|
+
"homepage": "https://grammy.dev/",
|
11
|
+
"repository": {
|
12
|
+
"type": "git",
|
13
|
+
"url": "https://github.com/grammyjs/grammY"
|
14
|
+
},
|
15
|
+
"scripts": {
|
16
|
+
"prepare": "npm run backport",
|
17
|
+
"backport": "deno2node tsconfig.json"
|
18
|
+
},
|
19
|
+
"peerDependencies": {
|
20
|
+
"grammy": "^1.20.1"
|
21
|
+
},
|
22
|
+
"devDependencies": {
|
23
|
+
"@types/node": "^12.20.55",
|
24
|
+
"deno2node": "^1.14.0"
|
25
|
+
},
|
26
|
+
"files": [
|
27
|
+
"out/"
|
28
|
+
],
|
29
|
+
"main": "./out/mod.js",
|
30
|
+
"types": "./out/mod.d.ts",
|
31
|
+
"keywords": [
|
32
|
+
"telegram",
|
33
|
+
"bot",
|
34
|
+
"api",
|
35
|
+
"client",
|
36
|
+
"framework",
|
37
|
+
"library",
|
38
|
+
"grammy",
|
39
|
+
"conversations",
|
40
|
+
"scenes",
|
41
|
+
"wizards"
|
42
|
+
]
|
43
|
+
}
|