shogun-core 1.2.0 → 1.2.3

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.
Files changed (37) hide show
  1. package/README.md +6 -6
  2. package/dist/browser/shogun-core.js +1 -1
  3. package/dist/browser/shogun-core.light.js +1 -0
  4. package/dist/browser/shogun-core.vendors.light.js +1 -0
  5. package/dist/browser.js +11 -11
  6. package/dist/core.js +46 -45
  7. package/dist/gundb/gun.js +112 -92
  8. package/dist/plugins/index.js +4 -4
  9. package/dist/plugins/{bitcoin → nostr}/nostrConnectorPlugin.js +7 -8
  10. package/dist/plugins/{ethereum → web3}/web3ConnectorPlugin.js +7 -7
  11. package/dist/types/browser.d.ts +4 -4
  12. package/dist/types/core.d.ts +1 -2
  13. package/dist/types/gundb/gun.d.ts +4 -10
  14. package/dist/types/plugins/index.d.ts +6 -6
  15. package/dist/types/shogun.js +2 -2
  16. package/dist/types/types/shogun.d.ts +5 -23
  17. package/package.json +1 -1
  18. package/dist/gundb/models/auth/auth.js +0 -207
  19. package/dist/gundb/models/auth/state-machine.js +0 -216
  20. package/dist/gundb/models/streams.js +0 -116
  21. package/dist/types/gundb/models/auth/auth.d.ts +0 -121
  22. package/dist/types/gundb/models/auth/state-machine.d.ts +0 -70
  23. package/dist/types/gundb/models/streams.d.ts +0 -67
  24. /package/dist/plugins/{bitcoin → nostr}/index.js +0 -0
  25. /package/dist/plugins/{bitcoin → nostr}/nostrConnector.js +0 -0
  26. /package/dist/plugins/{bitcoin → nostr}/types.js +0 -0
  27. /package/dist/plugins/{ethereum → web3}/index.js +0 -0
  28. /package/dist/plugins/{ethereum → web3}/types.js +0 -0
  29. /package/dist/plugins/{ethereum → web3}/web3Connector.js +0 -0
  30. /package/dist/types/plugins/{bitcoin → nostr}/index.d.ts +0 -0
  31. /package/dist/types/plugins/{bitcoin → nostr}/nostrConnector.d.ts +0 -0
  32. /package/dist/types/plugins/{bitcoin → nostr}/nostrConnectorPlugin.d.ts +0 -0
  33. /package/dist/types/plugins/{bitcoin → nostr}/types.d.ts +0 -0
  34. /package/dist/types/plugins/{ethereum → web3}/index.d.ts +0 -0
  35. /package/dist/types/plugins/{ethereum → web3}/types.d.ts +0 -0
  36. /package/dist/types/plugins/{ethereum → web3}/web3Connector.d.ts +0 -0
  37. /package/dist/types/plugins/{ethereum → web3}/web3ConnectorPlugin.d.ts +0 -0
@@ -1,25 +1,21 @@
1
1
  /**
2
2
  * GunDB class with enhanced features:
3
- * - Dynamic auth token usage
4
- * - Concurrency-safe authentication
5
3
  * - Dynamic peer linking
6
4
  * - Support for remove/unset operations
5
+ * - Direct authentication through Gun.user()
7
6
  */
8
7
  import { IGunUserInstance, IGunInstance, IGunChain } from "gun";
9
8
  import { GunRxJS } from "./rxjs-integration";
10
9
  import * as GunErrors from "./errors";
11
10
  import * as crypto from "./crypto";
12
11
  import * as utils from "./utils";
13
- import AuthManager from "./models/auth/auth";
14
12
  declare class GunDB {
15
13
  gun: IGunInstance<any>;
16
14
  user: IGunUserInstance<any> | null;
17
15
  crypto: typeof crypto;
18
16
  utils: typeof utils;
19
- auth: AuthManager;
20
17
  node: IGunChain<any, IGunInstance<any>, IGunInstance<any>, string>;
21
18
  private readonly onAuthCallbacks;
22
- private _authenticating;
23
19
  private _rxjs?;
24
20
  constructor(gun: IGunInstance<any>, appScope?: string);
25
21
  private subscribeToAuthEvents;
@@ -107,14 +103,14 @@ declare class GunDB {
107
103
  */
108
104
  remove(path: string): Promise<any>;
109
105
  /**
110
- * Signs up a new user using AuthManager
106
+ * Signs up a new user using direct Gun authentication
111
107
  * @param username Username
112
108
  * @param password Password
113
109
  * @returns Promise resolving to signup result
114
110
  */
115
111
  signUp(username: string, password: string): Promise<any>;
116
112
  /**
117
- * Logs in a user using AuthManager
113
+ * Logs in a user using direct Gun authentication
118
114
  * @param username Username
119
115
  * @param password Password
120
116
  * @param callback Optional callback for login result
@@ -122,10 +118,8 @@ declare class GunDB {
122
118
  */
123
119
  login(username: string, password: string, callback?: (result: any) => void): Promise<any>;
124
120
  private _savePair;
125
- private isAuthenticating;
126
- private _setAuthenticating;
127
121
  /**
128
- * Logs out the current user using AuthManager
122
+ * Logs out the current user using direct Gun authentication
129
123
  */
130
124
  logout(): void;
131
125
  /**
@@ -3,9 +3,9 @@ export type { ShogunPlugin, PluginManager } from "../types/plugin";
3
3
  export { Webauthn } from "./webauthn/webauthn";
4
4
  export { WebauthnPlugin } from "./webauthn/webauthnPlugin";
5
5
  export type { WebauthnPluginInterface } from "./webauthn/types";
6
- export { Web3Connector } from "./ethereum/web3Connector";
7
- export { Web3ConnectorPlugin } from "./ethereum/web3ConnectorPlugin";
8
- export type { Web3ConectorPluginInterface } from "./ethereum/types";
9
- export { NostrConnector } from "./bitcoin/nostrConnector";
10
- export { NostrConnectorPlugin } from "./bitcoin/nostrConnectorPlugin";
11
- export type { NostrConnectorPluginInterface, NostrConnectorCredentials, NostrConnectorKeyPair, NostrConnectorConfig, AlbyProvider, NostrProvider, } from "./bitcoin/types";
6
+ export { Web3Connector } from "./web3/web3Connector";
7
+ export { Web3ConnectorPlugin } from "./web3/web3ConnectorPlugin";
8
+ export type { Web3ConectorPluginInterface } from "./web3/types";
9
+ export { NostrConnector } from "./nostr/nostrConnector";
10
+ export { NostrConnectorPlugin } from "./nostr/nostrConnectorPlugin";
11
+ export type { NostrConnectorPluginInterface, NostrConnectorCredentials, NostrConnectorKeyPair, NostrConnectorConfig, AlbyProvider, NostrProvider, } from "./nostr/types";
@@ -25,9 +25,9 @@ var CorePlugins;
25
25
  /** WebAuthn plugin */
26
26
  CorePlugins["WebAuthn"] = "webauthn";
27
27
  /** Ethereum plugin */
28
- CorePlugins["Ethereum"] = "ethereum";
28
+ CorePlugins["Web3"] = "web3";
29
29
  /** Bitcoin wallet plugin */
30
- CorePlugins["Bitcoin"] = "bitcoin";
30
+ CorePlugins["Nostr"] = "nostr";
31
31
  })(CorePlugins || (exports.CorePlugins = CorePlugins = {}));
32
32
  /**
33
33
  * Authentication states for the state machine
@@ -27,11 +27,11 @@ export declare enum CorePlugins {
27
27
  /** WebAuthn plugin */
28
28
  WebAuthn = "webauthn",
29
29
  /** Ethereum plugin */
30
- Ethereum = "ethereum",
30
+ Web3 = "web3",
31
31
  /** Bitcoin wallet plugin */
32
- Bitcoin = "bitcoin"
32
+ Nostr = "nostr"
33
33
  }
34
- export type AuthMethod = "password" | "webauthn" | "ethereum" | "bitcoin";
34
+ export type AuthMethod = "password" | "webauthn" | "web3" | "nostr";
35
35
  export interface AuthResult {
36
36
  success: boolean;
37
37
  error?: string;
@@ -104,38 +104,20 @@ export interface ShogunSDKConfig {
104
104
  gunInstance?: IGunInstance<any>;
105
105
  scope?: string;
106
106
  peers?: string[];
107
- /** WebAuthn configuration */
108
107
  webauthn?: WebauthnConfig;
109
- /** MetaMask configuration */
110
- ethereum?: {
111
- /** Enable MetaMask */
108
+ web3?: {
112
109
  enabled?: boolean;
113
110
  };
114
- /** Bitcoin wallet configuration */
115
- bitcoin?: {
116
- /** Enable Bitcoin wallet */
111
+ nostr?: {
117
112
  enabled?: boolean;
118
- /** Bitcoin network to use (default: mainnet) */
119
- network?: "mainnet" | "testnet";
120
- /** Use API for verification (default: false) */
121
- useApi?: boolean;
122
- /** API URL for verification */
123
- apiUrl?: string;
124
113
  };
125
- /** Logging configuration */
126
114
  logging?: LoggingConfig;
127
- /** Timeout configuration in milliseconds */
128
115
  timeouts?: {
129
- /** Login timeout in milliseconds (default: 15000) */
130
116
  login?: number;
131
- /** Signup timeout in milliseconds (default: 20000) */
132
117
  signup?: number;
133
- /** General operation timeout in milliseconds (default: 30000) */
134
118
  operation?: number;
135
119
  };
136
- /** Plugin configuration */
137
120
  plugins?: {
138
- /** List of plugins to automatically register on initialization */
139
121
  autoRegister?: ShogunPlugin[];
140
122
  };
141
123
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shogun-core",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "description": "SHOGUN SDK - Core library for Shogun SDK",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -1,207 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const state_machine_1 = require("./state-machine");
4
- // Simple helper function to replace app_scoped
5
- function app_scoped(text, scope) {
6
- return `${scope}_${text}`;
7
- }
8
- /** An auth manager that wraps gun.user logic. */
9
- class AuthManager {
10
- static INITIAL_STATE = state_machine_1.states.disconnected;
11
- static state = (0, state_machine_1.use_machine)(state_machine_1.auth_state_machine, AuthManager.INITIAL_STATE);
12
- static instance;
13
- gundb;
14
- app_scope = "shogun";
15
- /** Returns the validated alias and password information. This will also be scoped using app_scope */
16
- async validate(alias, password) {
17
- if (password.length < 8)
18
- throw new Error("Passwords in gun must be more than 8 characters long!");
19
- if (alias.length < 1)
20
- throw new Error("User name must be more than 0 characters long!");
21
- const validated_alias = app_scoped(alias, this.app_scope);
22
- const validated_password = app_scoped(password, this.app_scope);
23
- return { alias: validated_alias, password: validated_password };
24
- }
25
- /** A new AuthManager. */
26
- constructor(gundb, appScope = "shogun") {
27
- if (AuthManager.instance) {
28
- this.gundb = AuthManager.instance.gundb;
29
- this.app_scope = AuthManager.instance.app_scope;
30
- return AuthManager.instance;
31
- }
32
- this.gundb = gundb;
33
- this.app_scope = appScope;
34
- AuthManager.instance = this;
35
- }
36
- /** Gets the user chain, if authenticated. */
37
- get chain() {
38
- const pair = this.pair({ strict: true });
39
- return this.gundb.gun.get(pair.pub);
40
- }
41
- pair(options = {}) {
42
- const user = this.gundb.gun.user()._;
43
- if ("sea" in user) {
44
- return user.sea;
45
- }
46
- if (options.strict) {
47
- throw new Error("Failed to get user pair! User is not authenticated");
48
- }
49
- return undefined;
50
- }
51
- /**
52
- * Generate a new gun user pair using alias and password.
53
- *
54
- * @param alias - The user alias.
55
- * @param password - The user password.
56
- * @returns A promise that resolves with gun ack or rejects with gun ack on errors.
57
- */
58
- create = async ({ alias, password, }) => {
59
- // Note: throws if state transitions is not possible.
60
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.create));
61
- // attempt to create user.
62
- try {
63
- const res = await new Promise((resolve, reject) => {
64
- this.gundb.gun.user().create(alias, password, (ack) => {
65
- if ("err" in ack) {
66
- reject(ack);
67
- return;
68
- }
69
- resolve(ack);
70
- });
71
- });
72
- // creation success.
73
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.success));
74
- return res;
75
- }
76
- catch (err) {
77
- // creation failure.
78
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.fail, err));
79
- throw err;
80
- }
81
- };
82
- /**
83
- * Authenicate existing gun user using either a pair or a alias/password combination.
84
- * @returns A promise that resolves with gun ack or rejects with gun ack on errors.
85
- */
86
- auth = async (info) => {
87
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.authenticate));
88
- // attempt to authenticate user.
89
- try {
90
- const res = await new Promise((resolve, reject) => {
91
- if ("pub" in info) {
92
- // Use auth with the pair directly to avoid type errors
93
- // @ts-ignore - Ignoring type errors with GunDB's auth method
94
- this.gundb.gun.user().auth(info, (ack) => {
95
- if ("err" in ack) {
96
- reject(new Error(ack.err));
97
- return;
98
- }
99
- else
100
- resolve(ack);
101
- });
102
- }
103
- else {
104
- // @ts-ignore - Ignoring type errors with GunDB's auth method
105
- this.gundb.gun.user().auth(info.alias, info.password, (ack) => {
106
- if ("err" in ack) {
107
- reject(new Error(ack.err));
108
- return;
109
- }
110
- else
111
- resolve(ack);
112
- });
113
- }
114
- });
115
- // on auth success
116
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.success));
117
- return res;
118
- }
119
- catch (err) {
120
- // on auth error
121
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.fail));
122
- throw err;
123
- }
124
- };
125
- /**
126
- * Un-authenticates the currently authenticated gun user.
127
- */
128
- leave = async () => {
129
- // check if state transition is possible.
130
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.disconnect));
131
- // attempt log out.
132
- try {
133
- const res = await new Promise((resolve, reject) => {
134
- this.gundb.gun.user().leave();
135
- if (this.pair()?.pub) {
136
- reject({ err: "User leave failed!" });
137
- return;
138
- }
139
- resolve({ success: true });
140
- });
141
- // on success.
142
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.success));
143
- return res;
144
- }
145
- catch (err) {
146
- // on fail.
147
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.fail));
148
- throw err;
149
- }
150
- };
151
- /**
152
- * A simple default certificate that will allow everybody to write to the users graph, as long as the key or path contains their public key.
153
- */
154
- certify() {
155
- // Currently not implemented - needs to be added to the crypto module
156
- return null;
157
- }
158
- /**
159
- * Start wallet initialization process
160
- */
161
- startWalletInit() {
162
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.wallet_init_start));
163
- }
164
- /**
165
- * Mark wallet initialization as successful
166
- */
167
- walletInitSuccess() {
168
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.wallet_init_success));
169
- }
170
- /**
171
- * Mark wallet initialization as failed
172
- */
173
- walletInitFail(error) {
174
- AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.wallet_init_fail, error));
175
- }
176
- /**
177
- * Wait for authentication to complete
178
- */
179
- async waitForAuthentication(timeoutMs = 10000) {
180
- return AuthManager.state.waitForState(state_machine_1.states.authorized, timeoutMs);
181
- }
182
- /**
183
- * Wait for wallet to be ready
184
- */
185
- async waitForWalletReady(timeoutMs = 15000) {
186
- return AuthManager.state.waitForState(state_machine_1.states.wallet_ready, timeoutMs);
187
- }
188
- /**
189
- * Check if user is authenticated
190
- */
191
- isAuthenticated() {
192
- return AuthManager.state.isAuthenticated();
193
- }
194
- /**
195
- * Check if wallet is ready
196
- */
197
- isWalletReady() {
198
- return AuthManager.state.isWalletReady();
199
- }
200
- /**
201
- * Get current authentication state
202
- */
203
- getCurrentState() {
204
- return AuthManager.state.getCurrentState();
205
- }
206
- }
207
- exports.default = AuthManager;
@@ -1,216 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.events = exports.states = exports.StateMachineEvent = void 0;
4
- exports.use_machine = use_machine;
5
- exports.auth_state_machine = auth_state_machine;
6
- /** A state machine event with optional data */
7
- class StateMachineEvent {
8
- type;
9
- data;
10
- constructor(type, data = {}) {
11
- this.type = type;
12
- this.data = data;
13
- }
14
- }
15
- exports.StateMachineEvent = StateMachineEvent;
16
- /**
17
- *
18
- * @param machine - A machine function that defines state transitions.
19
- * @param initial - The initial state of the machine.
20
- */
21
- function use_machine(machine, initial) {
22
- let state = initial;
23
- let subs = new Map();
24
- let stateWaiters = new Map();
25
- function subscribe(cb) {
26
- const id = crypto.randomUUID();
27
- subs.set(id, cb);
28
- cb(state);
29
- return () => {
30
- subs.delete(id);
31
- };
32
- }
33
- function set(event) {
34
- const previousState = state;
35
- state = machine(state, event);
36
- // Notify subscribers
37
- for (const sub of subs.values()) {
38
- sub(state);
39
- }
40
- // Notify state waiters
41
- const waiters = stateWaiters.get(state);
42
- if (waiters) {
43
- waiters.forEach((resolve) => resolve(true));
44
- stateWaiters.delete(state);
45
- }
46
- }
47
- function getCurrentState() {
48
- return state;
49
- }
50
- function waitForState(targetState, timeoutMs = 10000) {
51
- return new Promise((resolve) => {
52
- // If already in target state, resolve immediately
53
- if (state === targetState) {
54
- resolve(true);
55
- return;
56
- }
57
- // Add to waiters
58
- if (!stateWaiters.has(targetState)) {
59
- stateWaiters.set(targetState, []);
60
- }
61
- stateWaiters.get(targetState).push(resolve);
62
- // Set timeout
63
- setTimeout(() => {
64
- const waiters = stateWaiters.get(targetState);
65
- if (waiters) {
66
- const index = waiters.indexOf(resolve);
67
- if (index > -1) {
68
- waiters.splice(index, 1);
69
- if (waiters.length === 0) {
70
- stateWaiters.delete(targetState);
71
- }
72
- }
73
- }
74
- resolve(false);
75
- }, timeoutMs);
76
- });
77
- }
78
- function isAuthenticated() {
79
- return (state === exports.states.authorized ||
80
- state === exports.states.wallet_initializing ||
81
- state === exports.states.wallet_ready);
82
- }
83
- function isWalletReady() {
84
- return state === exports.states.wallet_ready;
85
- }
86
- return {
87
- /**
88
- * Subscribe to state updates.
89
- * @returns an unsubscriber */
90
- subscribe,
91
- /** attempt to update the state machine */
92
- set,
93
- /** Get the current state */
94
- getCurrentState,
95
- /** Wait for a specific state */
96
- waitForState,
97
- /** Check if user is authenticated */
98
- isAuthenticated,
99
- /** Check if wallet is ready */
100
- isWalletReady,
101
- };
102
- }
103
- /** Possible states that the auth-manager can be in. */
104
- exports.states = {
105
- /** The user is in an un-busy and unauthorized state.*/
106
- disconnected: "disconnected",
107
- /** A user is currently being created. */
108
- creating: "creating",
109
- /** A user is currently being authorized. */
110
- pending: "pending",
111
- /** The user is in an un-busy and authorized state. */
112
- authorized: "authorized",
113
- /** The user is currently logging out. */
114
- leaving: "leaving",
115
- /** Wallet initialization is in progress. */
116
- wallet_initializing: "wallet_initializing",
117
- /** Wallet is ready and available. */
118
- wallet_ready: "wallet_ready",
119
- };
120
- /** Possible events that the auth-manager can take. */
121
- exports.events = {
122
- create: "create",
123
- authenticate: "authenticate",
124
- disconnect: "disconnect",
125
- fail: "fail",
126
- success: "success",
127
- wallet_init_start: "wallet_init_start",
128
- wallet_init_success: "wallet_init_success",
129
- wallet_init_fail: "wallet_init_fail",
130
- };
131
- class StateTransitionError extends Error {
132
- state;
133
- event;
134
- constructor(message, state, event) {
135
- super(message);
136
- this.state = state;
137
- this.event = event;
138
- }
139
- }
140
- /**
141
- * Defines possible transitions from the states in the auth manager.
142
- *
143
- * @param state - The current state.
144
- * @param event The event that has happend.
145
- * @returns The new state.
146
- */
147
- function auth_state_machine(state, event) {
148
- const transition_error = new StateTransitionError("Not a valid state transition", state, event.type);
149
- switch (state) {
150
- // User is disconnected and unbusy
151
- case exports.states.disconnected:
152
- if (event.type === exports.events.create) {
153
- return exports.states.creating;
154
- }
155
- if (event.type === exports.events.authenticate) {
156
- return exports.states.pending;
157
- }
158
- throw transition_error;
159
- // User is creating and busy
160
- case exports.states.creating:
161
- if (event.type === exports.events.fail) {
162
- return exports.states.disconnected;
163
- }
164
- if (event.type === exports.events.success) {
165
- return exports.states.disconnected;
166
- }
167
- throw transition_error;
168
- // User is logging in and busy
169
- case exports.states.pending:
170
- if (event.type === exports.events.fail) {
171
- return exports.states.disconnected;
172
- }
173
- if (event.type === exports.events.success) {
174
- return exports.states.authorized;
175
- }
176
- throw transition_error;
177
- // User is authorized and unbusy
178
- case exports.states.authorized:
179
- if (event.type === exports.events.disconnect) {
180
- return exports.states.leaving;
181
- }
182
- if (event.type === exports.events.wallet_init_start) {
183
- return exports.states.wallet_initializing;
184
- }
185
- throw transition_error;
186
- // User is leaving and busy
187
- case exports.states.leaving:
188
- if (event.type === exports.events.fail) {
189
- return exports.states.authorized;
190
- }
191
- if (event.type === exports.events.success) {
192
- return exports.states.disconnected;
193
- }
194
- throw transition_error;
195
- // Wallet is being initialized
196
- case exports.states.wallet_initializing:
197
- if (event.type === exports.events.wallet_init_success) {
198
- return exports.states.wallet_ready;
199
- }
200
- if (event.type === exports.events.wallet_init_fail) {
201
- return exports.states.authorized;
202
- }
203
- if (event.type === exports.events.disconnect) {
204
- return exports.states.leaving;
205
- }
206
- throw transition_error;
207
- // Wallet is ready
208
- case exports.states.wallet_ready:
209
- if (event.type === exports.events.disconnect) {
210
- return exports.states.leaving;
211
- }
212
- throw transition_error;
213
- default:
214
- throw transition_error;
215
- }
216
- }
@@ -1,116 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.on_stream = on_stream;
4
- exports.to_unique = to_unique;
5
- exports.to_node = to_node;
6
- /**
7
- *
8
- * Only Firefox implements async iterable on ReadableStream. This will add polyfill.
9
- *
10
- * @see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#browser_compatibility
11
- */
12
- (function enable_async_iterator_polyfill() {
13
- ReadableStream.prototype[Symbol.asyncIterator] = async function* () {
14
- const reader = this.getReader();
15
- try {
16
- while (true) {
17
- const { done, value } = await reader.read();
18
- if (done)
19
- return;
20
- yield value;
21
- }
22
- }
23
- finally {
24
- reader.releaseLock();
25
- }
26
- };
27
- })();
28
- /**
29
- *
30
- * Wraps .on call in a stream. Cancelling the stream will unsubscribe from updates from gun.
31
- *
32
- * **Usage:**
33
- * ```
34
- * const stream = on_stream(node)
35
- * for await (const chunk of stream) {
36
- * // Do something with each 'chunk'
37
- * }
38
- * ```
39
- */
40
- function on_stream(chain) {
41
- let ev;
42
- const stream = new ReadableStream({
43
- start(controller) {
44
- console.log("stream started");
45
- chain.on(function (value, key, _, event) {
46
- ev = event;
47
- console.log(`from stream, ${key}`);
48
- controller.enqueue({ value, key, chain: this });
49
- });
50
- },
51
- cancel() {
52
- console.log("stream cancelled");
53
- if (!ev) {
54
- // TODO log
55
- return;
56
- }
57
- ev.off();
58
- },
59
- });
60
- return stream;
61
- }
62
- /**
63
- *
64
- * Takes an incoming stream, but only issues updates if the data changes from valid data to null data.
65
- * You can use this to keep a list in sync with the gun state. If data is tombstoned, it can be removed from the list.
66
- *
67
- * **Example:**
68
- * ```
69
- * const map = new Map();
70
- * const items = [];
71
- * const stream = on_stream(node).pipeThrough(unique_transformer());
72
- * for await (const chunk of stream) {
73
- * chunk.value === null ? map.delete(chunk.key) : map.set(chunk.key, chunk.chain);
74
- items.splice(0, items.length, ...map.values());
75
- * }
76
- * ```
77
- */
78
- function to_unique() {
79
- const map = new Map();
80
- const transformer = new TransformStream({
81
- transform(chuck, controller) {
82
- if (!map.has(chuck.key)) {
83
- pass(controller, chuck);
84
- return;
85
- }
86
- const old_value = map.get(chuck.key);
87
- if (chuck.value === null && old_value !== null) {
88
- pass(controller, chuck);
89
- return;
90
- }
91
- if (chuck.value !== null && old_value === null) {
92
- pass(controller, chuck);
93
- return;
94
- }
95
- function pass(controller, chuck) {
96
- map.set(chuck.key, chuck.chain);
97
- controller.enqueue(chuck);
98
- }
99
- },
100
- });
101
- return transformer;
102
- }
103
- /**
104
- * Transoforms a stream of gun chains into a stream of gun nodes.
105
- */
106
- function to_node(target) {
107
- const transformer = new TransformStream({
108
- transform(chunk, controller) {
109
- const new_chunk = chunk.chain
110
- ? { value: chunk.value, key: chunk.key, node: new target(chunk.chain) }
111
- : { value: chunk.value, key: chunk.key, node: chunk.chain };
112
- controller.enqueue(new_chunk);
113
- },
114
- });
115
- return transformer;
116
- }