diff --git a/package.json b/package.json index 8bb52f4f..db6fd11a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "powership", - "version": "3.3.7", + "version": "3.3.9", "private": true, "scripts": { "pack": "run-s pack:*", diff --git a/packages/accounts/package.json b/packages/accounts/package.json index 60bba581..f065159c 100644 --- a/packages/accounts/package.json +++ b/packages/accounts/package.json @@ -1,6 +1,6 @@ { "name": "@powership/accounts", - "version": "3.3.7", + "version": "3.3.9", "description": "Powership accounts", "type": "module", "main": "./out/index.cjs", @@ -91,8 +91,8 @@ "peerDependencies": { "scrypt-kdf": "*", "jsonwebtoken": "*", - "@powership/schema": "3.3.7", - "@powership/utils": "3.3.7", + "@powership/schema": "3.3.9", + "@powership/utils": "3.3.9", "dataloader": "*", "plugin-hooks": "*", "sift": "*", @@ -135,7 +135,7 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/transporter": "3.3.7", - "@powership/entity": "3.3.7" + "@powership/transporter": "3.3.9", + "@powership/entity": "3.3.9" } } diff --git a/packages/babel-plugins/package.json b/packages/babel-plugins/package.json index da5f7a75..e0bf506f 100644 --- a/packages/babel-plugins/package.json +++ b/packages/babel-plugins/package.json @@ -1,6 +1,6 @@ { "name": "@powership/babel-plugins", - "version": "3.3.7", + "version": "3.3.9", "main": "./out/index.js", "sideEffects": false, "typings": "./out/index.d.ts", diff --git a/packages/boilerplate/package.json b/packages/boilerplate/package.json index 1c874c95..3613949f 100644 --- a/packages/boilerplate/package.json +++ b/packages/boilerplate/package.json @@ -1,6 +1,6 @@ { "name": "@powership/boilerplate", - "version": "3.3.7", + "version": "3.3.9", "author": "antoniopresto ", "sideEffects": false, "type": "module", @@ -61,7 +61,7 @@ "ts-jest": "*", "typedoc": "*", "typescript": "*", - "@powership/babel-plugins": "3.3.7", + "@powership/babel-plugins": "3.3.9", "@babel/preset-typescript": "*", "@babel/preset-env": "*", "@babel/plugin-transform-typescript": "*", diff --git a/packages/deepstate/package.json b/packages/deepstate/package.json index 4c1c69bc..e15414db 100644 --- a/packages/deepstate/package.json +++ b/packages/deepstate/package.json @@ -1,6 +1,6 @@ { "name": "@powership/deepstate", - "version": "3.3.7", + "version": "3.3.9", "main": "out/index.cjs", "module": "out/index.mjs", "sideEffects": false, @@ -120,7 +120,7 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7", - "@powership/schema": "3.3.7" + "@powership/utils": "3.3.9", + "@powership/schema": "3.3.9" } } diff --git a/packages/entity/package.json b/packages/entity/package.json index bd697ef3..8b40fdef 100644 --- a/packages/entity/package.json +++ b/packages/entity/package.json @@ -1,6 +1,6 @@ { "name": "@powership/entity", - "version": "3.3.7", + "version": "3.3.9", "type": "module", "main": "./out/index.cjs", "module": "./out/index.mjs", @@ -138,8 +138,8 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7", - "@powership/schema": "3.3.7", - "@powership/transporter": "3.3.7" + "@powership/utils": "3.3.9", + "@powership/schema": "3.3.9", + "@powership/transporter": "3.3.9" } } diff --git a/packages/logstorm/package.json b/packages/logstorm/package.json index c5e21991..ad31ed55 100644 --- a/packages/logstorm/package.json +++ b/packages/logstorm/package.json @@ -1,6 +1,6 @@ { "name": "logstorm", - "version": "3.3.7", + "version": "3.3.9", "typings": "out", "author": "antoniopresto ", "type": "module", @@ -124,6 +124,6 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7" + "@powership/utils": "3.3.9" } } diff --git a/packages/mongo/package.json b/packages/mongo/package.json index 76f8324c..df69d234 100644 --- a/packages/mongo/package.json +++ b/packages/mongo/package.json @@ -1,6 +1,6 @@ { "name": "@powership/mongo", - "version": "3.3.7", + "version": "3.3.9", "type": "module", "main": "./out/index.cjs", "module": "./out/index.mjs", @@ -130,9 +130,9 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7", - "@powership/schema": "3.3.7", - "@powership/transporter": "3.3.7", + "@powership/utils": "3.3.9", + "@powership/schema": "3.3.9", + "@powership/transporter": "3.3.9", "mongodb": "*" }, "files": [ diff --git a/packages/plugin-engine/package.json b/packages/plugin-engine/package.json index 6f85ab59..ca545630 100644 --- a/packages/plugin-engine/package.json +++ b/packages/plugin-engine/package.json @@ -1,6 +1,6 @@ { "name": "plugin-engine", - "version": "3.3.7", + "version": "3.3.9", "type": "module", "main": "./out/index.cjs", "module": "./out/index.mjs", @@ -96,9 +96,9 @@ }, "peerDependencies": { "highlight.js": "*", - "@powership/schema": "3.3.7", - "@powership/transporter": "3.3.7", - "@powership/utils": "3.3.7", + "@powership/schema": "3.3.9", + "@powership/transporter": "3.3.9", + "@powership/utils": "3.3.9", "dataloader": "*", "plugin-hooks": "*", "sift": "*", @@ -141,6 +141,6 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/entity": "3.3.7" + "@powership/entity": "3.3.9" } } diff --git a/packages/powership/package.json b/packages/powership/package.json index d93afde4..70ae2117 100644 --- a/packages/powership/package.json +++ b/packages/powership/package.json @@ -1,6 +1,6 @@ { "name": "powership", - "version": "3.3.7", + "version": "3.3.9", "author": "antoniopresto ", "type": "module", "main": "./out/index.cjs", @@ -105,11 +105,11 @@ "tsconfig": "./tsconfig.module.json" }, "peerDependencies": { - "@powership/utils": "3.3.7", - "@powership/schema": "3.3.7", - "@powership/entity": "3.3.7", + "@powership/utils": "3.3.9", + "@powership/schema": "3.3.9", + "@powership/entity": "3.3.9", "highlight.js": "*", - "@powership/transporter": "3.3.7", + "@powership/transporter": "3.3.9", "dataloader": "*", "plugin-hooks": "*", "sift": "*", @@ -152,12 +152,12 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "plugin-engine": "3.3.7", + "plugin-engine": "3.3.9", "body-parser": "*", "graphql-playground-html": "*", "http-errors": "*", "http-status-codes": "*", - "logstorm": "3.3.7", - "@powership/server": "3.3.7" + "logstorm": "3.3.9", + "@powership/server": "3.3.9" } } diff --git a/packages/runmate/package.json b/packages/runmate/package.json index 38f16899..0b5faf03 100644 --- a/packages/runmate/package.json +++ b/packages/runmate/package.json @@ -1,6 +1,6 @@ { "name": "runmate", - "version": "3.3.7", + "version": "3.3.9", "typings": "out", "author": "antoniopresto ", "license": "MIT", @@ -141,8 +141,8 @@ "ts-toolbelt": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7", - "logstorm": "3.3.7", + "@powership/utils": "3.3.9", + "logstorm": "3.3.9", "@types/vorpal": "*", "@types/glob": "*" } diff --git a/packages/schema/package.json b/packages/schema/package.json index fd957b5a..f7df86f2 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,6 +1,6 @@ { "name": "@powership/schema", - "version": "3.3.7", + "version": "3.3.9", "type": "module", "main": "./out/index.cjs", "module": "./out/index.mjs", @@ -144,6 +144,6 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7" + "@powership/utils": "3.3.9" } } diff --git a/packages/server/package.json b/packages/server/package.json index affde6a8..207fd0b7 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@powership/server", - "version": "3.3.7", + "version": "3.3.9", "type": "module", "main": "./out/index.cjs", "module": "./out/index.mjs", @@ -114,7 +114,7 @@ "plugin-hooks": "*", "url-pattern": "*", "qs": "*", - "@powership/utils": "3.3.7", + "@powership/utils": "3.3.9", "@types/dateformat": "*", "@types/fs-extra": "*", "@types/lodash": "*", @@ -152,11 +152,11 @@ "ts-toolbelt": "*", "tsx": "*", "ulid": "*", - "logstorm": "3.3.7", + "logstorm": "3.3.9", "http-status-codes": "*", "http-errors": "*", "graphql-playground-html": "*", - "@powership/schema": "3.3.7", + "@powership/schema": "3.3.9", "body-parser": "*" } } diff --git a/packages/transporter/package.json b/packages/transporter/package.json index f282f9b6..ed01711e 100644 --- a/packages/transporter/package.json +++ b/packages/transporter/package.json @@ -1,6 +1,6 @@ { "name": "@powership/transporter", - "version": "3.3.7", + "version": "3.3.9", "type": "module", "main": "./out/index.cjs", "module": "./out/index.mjs", @@ -140,7 +140,7 @@ "tsx": "*", "ulid": "*", "url-pattern": "*", - "@powership/utils": "3.3.7", - "@powership/schema": "3.3.7" + "@powership/utils": "3.3.9", + "@powership/schema": "3.3.9" } } diff --git a/packages/utils/package.json b/packages/utils/package.json index 867f3b54..2d6dc187 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@powership/utils", - "version": "3.3.7", + "version": "3.3.9", "typings": "out", "author": "antoniopresto ", "license": "MIT", diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index d8a6dd45..b0ea119a 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -103,3 +103,4 @@ export * from './parsePhoneNumber'; export { TU }; export * from './hey'; +export * from './watchable'; diff --git a/packages/utils/src/watchable.spec.ts b/packages/utils/src/watchable.spec.ts new file mode 100644 index 00000000..301eac13 --- /dev/null +++ b/packages/utils/src/watchable.spec.ts @@ -0,0 +1,89 @@ +import { watchable } from './watchable'; + +describe('watchable', () => { + test('should delay execution until accessed', async () => { + let executed = false; + const watchableFunction = watchable(() => { + executed = true; + return { message: 'Hello World' }; + }); + + expect(executed).toBe(false); + + expect(watchableFunction.message).toBe('Hello World'); + expect(executed).toBe(true); + }); + + test('should handle promise results properly', async () => { + const asyncFunction = watchable( + () => + new Promise<{ message: string }>((resolve) => + setTimeout(() => resolve({ message: 'Async Hello World' }), 100) + ) + ); + + expect(asyncFunction.then).toBeDefined(); + const data = await asyncFunction; + expect(data.message).toBe('Async Hello World'); + }); + + test('should allow access to the current value', () => { + const watchableFunction = watchable(() => { + return { message: 'Current Value' }; + }); + + // before access + expect(watchableFunction.current()).toBeUndefined(); + + // force run + expect(watchableFunction.message).toBe('Current Value'); + + // after access + expect(watchableFunction.current()).toEqual({ message: 'Current Value' }); + }); + + test('should throw if trying to access rejected promise', async () => { + const failingFunction = watchable( + () => + new Promise((_, reject) => + setTimeout(() => reject(new Error('Failed')), 100) + ) + ); + + let err: any = undefined; + try { + await failingFunction; + } catch (error: any) { + err = error; + } + + expect(err).toBeInstanceOf(Error); + expect(err.message).toBe('Failed'); + }); + + test('should resolve subscribers in the order they were added', async () => { + const asyncFunction = watchable( + () => + new Promise((resolve) => + setTimeout(() => resolve({ value: 'Ordered' }), 100) + ) + ); + + const results: string[] = []; + + asyncFunction.then(() => results.push('first')); + asyncFunction.then(() => results.push('second')); + + await new Promise((resolve) => setTimeout(resolve, 200)); // Espera a resolução + + expect(results).toEqual(['first', 'second']); + + expect(await asyncFunction).toEqual({ + value: 'Ordered', + }); + + expect(await asyncFunction).toEqual({ + value: 'Ordered', + }); + }); +}); diff --git a/packages/utils/src/watchable.ts b/packages/utils/src/watchable.ts new file mode 100644 index 00000000..4ba92414 --- /dev/null +++ b/packages/utils/src/watchable.ts @@ -0,0 +1,102 @@ +export type Status = 'pending' | 'resolved' | 'rejected'; + +export type WatchableResult = + | { status: 'pending'; error?: undefined; value?: undefined } + | { + status: 'rejected'; + value?: undefined; + error: any; + } + | { + status: 'resolved'; + value: T; + error?: undefined; + }; + +export function watchable( + callback: () => T +): T & { + (): T; + then: Promise['then']; + catch: Promise['catch']; + finally: Promise['finally']; + current: () => T | undefined; +} { + let result: WatchableResult> = { status: 'pending' }; + const subscribers: { resolve: Function; reject: Function }[] = []; + + function promiseHandler( + resolve: (value: T) => void, + reject: (reason?: any) => void + ) { + if (result.status === 'resolved') { + resolve(result.value as T); + } else if (result.status === 'rejected') { + reject(result.error); + } else { + subscribers.push({ resolve, reject }); + } + } + + let dispatched = false; + function executeCallback() { + if (dispatched) return; + dispatched = true; + try { + const value = callback(); + if ( + value && + (typeof value === 'object' || typeof value === 'function') && + ('then' in value || 'catch' in value) + ) { + (value as unknown as Promise).then( + (resolvedValue) => { + result = { status: 'resolved', value: resolvedValue }; + subscribers.forEach((subscriber) => + subscriber.resolve(resolvedValue) + ); + }, + (error) => { + result = { status: 'rejected', error }; + subscribers.forEach((subscriber) => subscriber.reject(error)); + } + ); + } else { + result = { status: 'resolved', value }; + subscribers.forEach((subscriber) => subscriber.resolve(value)); + } + } catch (error) { + result = { status: 'rejected', error }; + subscribers.forEach((subscriber) => subscriber.reject(error)); + } + } + + const proxy = new Proxy(callback, { + get(_target, prop, receiver) { + if (prop === 'then' || prop === 'catch' || prop === 'finally') { + if (result.status === 'pending') { + setTimeout(executeCallback, 0); // Execute callback in the next tick + } + return promiseHandler.bind(promiseHandler); + } + if (prop === 'current') { + return () => result.value; + } + if (result.status === 'pending') { + executeCallback(); + } + if (result.status === 'resolved') { + return Reflect.get(result.value!, prop, receiver); + } + throw new Error('The promise is rejected or not resolved yet.'); + }, + }); + + return proxy as unknown as T & { + (): T; + then: Promise['then']; + catch: Promise['catch']; + finally: Promise['finally']; + current: () => T | undefined; + }; +}