foobara-typescript-remote-command-generator 0.0.20 → 0.0.21
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/src/remote_generator/services/auth/setup_generator.rb +19 -0
- data/src/remote_generator/services/typescript_from_manifest_base_generator.rb +4 -1
- data/src/remote_generator/write_typescript_to_disk.rb +8 -0
- data/templates/Foobara/Auth/utils/accessTokens.ts.erb +21 -1
- data/templates/base/Query.ts +125 -0
- data/templates/base/QueryCache.ts +47 -0
- data/templates/base/RemoteCommandTypes.ts +10 -0
- data/templates/hooks/useQuery.ts +75 -0
- data/templates/setup.ts.erb +5 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 894c3cb3bb470bc2ae517516af5eadf72271a842d91b4d9d3091df927a59f7ef
|
4
|
+
data.tar.gz: d78ee07ebf763f5c81459f5eb20c27e30b7f99f36975258e938fef80fb8f2e82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '058e5c94c619269433b72e3ef51caf0eebbe808420334af00482d234bdfc153ab3dc40946c023e6cd65a77f1ee3e56bf2323b256981990403ad928d1ec9bfb25'
|
7
|
+
data.tar.gz: 4b83e9a472967eed6c6aea176f0b966374aa1f688d17a5c6c7a46f45849a499f34dcb3489a24173f7b7d11a35c5f348763158afa34abb2391df7265e79de1847
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Foobara
|
2
|
+
module RemoteGenerator
|
3
|
+
class Services
|
4
|
+
module Auth
|
5
|
+
class SetupGenerator < TypescriptFromManifestBaseGenerator
|
6
|
+
def applicable?
|
7
|
+
relevant_manifest.commands.any? do |command_manifest|
|
8
|
+
command_manifest.full_command_name =~ /\bGetCurrentUser$/
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def template_path
|
13
|
+
"setup.ts.erb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -80,7 +80,10 @@ module Foobara
|
|
80
80
|
when Manifest::ProcessorClass
|
81
81
|
Services::ProcessorClassGenerator
|
82
82
|
when Manifest::RootManifest
|
83
|
-
|
83
|
+
[
|
84
|
+
Services::RootManifestGenerator,
|
85
|
+
Services::Auth::SetupGenerator
|
86
|
+
]
|
84
87
|
when Manifest::Type
|
85
88
|
Services::TypeGenerator
|
86
89
|
else
|
@@ -59,6 +59,7 @@ module Foobara
|
|
59
59
|
|
60
60
|
def run_post_generation_tasks
|
61
61
|
eslint_fix
|
62
|
+
warn_about_adding_setup_to_index
|
62
63
|
end
|
63
64
|
|
64
65
|
def eslint_fix
|
@@ -73,6 +74,13 @@ module Foobara
|
|
73
74
|
end
|
74
75
|
end
|
75
76
|
end
|
77
|
+
|
78
|
+
def warn_about_adding_setup_to_index
|
79
|
+
if paths_to_source_code.key?("setup.ts")
|
80
|
+
warn "WARNING: you should add the following to src/index.ts:\n\n" \
|
81
|
+
"import './domains/setup'"
|
82
|
+
end
|
83
|
+
end
|
76
84
|
end
|
77
85
|
end
|
78
86
|
end
|
@@ -1,11 +1,31 @@
|
|
1
|
+
import type Query from '../../../base/Query'
|
2
|
+
import type RemoteCommand from '../../../base/RemoteCommand'
|
3
|
+
|
4
|
+
let getCurrentUserQuery: Query<RemoteCommand<any, any, any>> | undefined
|
5
|
+
|
6
|
+
export function setGetCurrentUserQuery (query: Query<RemoteCommand<any, any, any>>): void {
|
7
|
+
getCurrentUserQuery = query
|
8
|
+
}
|
9
|
+
|
10
|
+
function setCurrentUserDirty () {
|
11
|
+
console.log('setCurrentUserDirty')
|
12
|
+
if (getCurrentUserQuery != null) {
|
13
|
+
getCurrentUserQuery.setDirty()
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
1
17
|
const accessTokens = new Map<string, string>()
|
2
18
|
|
3
|
-
const logout = (urlBase: string): void => {
|
19
|
+
const logout = (urlBase: string): void => {
|
20
|
+
accessTokens.delete(urlBase)
|
21
|
+
setCurrentUserDirty()
|
22
|
+
}
|
4
23
|
let handleLogout: (baseUrl: string) => void = logout
|
5
24
|
|
6
25
|
const tokenForUrl = (baseUrl: string): string | undefined => accessTokens.get(baseUrl)
|
7
26
|
const handleLogin: (baseUrl: string, accessToken: string) => void = (baseUrl, accessToken) => {
|
8
27
|
accessTokens.set(baseUrl, accessToken)
|
28
|
+
setCurrentUserDirty()
|
9
29
|
}
|
10
30
|
|
11
31
|
if (typeof BroadcastChannel !== 'undefined') {
|
@@ -0,0 +1,125 @@
|
|
1
|
+
import type RemoteCommand from '../base/RemoteCommand'
|
2
|
+
import { type Outcome } from '../base/Outcome'
|
3
|
+
import {
|
4
|
+
type InputsOf, type ResultOf, type ErrorOf, type RemoteCommandConstructor
|
5
|
+
} from './RemoteCommandTypes'
|
6
|
+
|
7
|
+
export default class Query<CommandT extends RemoteCommand<any, any, any>> {
|
8
|
+
inputs: InputsOf<CommandT>
|
9
|
+
CommandClass: RemoteCommandConstructor<CommandT>
|
10
|
+
command: CommandT | undefined
|
11
|
+
isLoading: boolean = false
|
12
|
+
isFailure: boolean = false
|
13
|
+
isDirty: boolean = false
|
14
|
+
ranWhileRunning: boolean = false
|
15
|
+
listeners: Array<() => void> = []
|
16
|
+
inputsChangedListeners: Array<() => void> = []
|
17
|
+
failure: any
|
18
|
+
|
19
|
+
constructor (
|
20
|
+
CommandClass: RemoteCommandConstructor<CommandT>,
|
21
|
+
inputs: InputsOf<CommandT> | undefined = undefined
|
22
|
+
) {
|
23
|
+
this.CommandClass = CommandClass
|
24
|
+
this.inputs = inputs ?? (undefined as unknown as InputsOf<CommandT>)
|
25
|
+
}
|
26
|
+
|
27
|
+
get outcome (): null | Outcome<ResultOf<CommandT>, ErrorOf<CommandT>> {
|
28
|
+
return this.command?.outcome ?? null
|
29
|
+
}
|
30
|
+
|
31
|
+
get result (): null | ResultOf<CommandT> {
|
32
|
+
return this.command?.outcome?.result ?? null
|
33
|
+
}
|
34
|
+
|
35
|
+
get errors (): null | Array<ErrorOf<CommandT>> {
|
36
|
+
return this.command?.outcome?.errors ?? null
|
37
|
+
}
|
38
|
+
|
39
|
+
onChange (callback: () => void): () => void {
|
40
|
+
this.listeners.push(callback)
|
41
|
+
return () => {
|
42
|
+
const index = this.listeners.indexOf(callback)
|
43
|
+
if (index !== -1) {
|
44
|
+
this.listeners.splice(index, 1)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
onInputsChange (callback: () => void): () => void {
|
50
|
+
this.inputsChangedListeners.push(callback)
|
51
|
+
|
52
|
+
return () => {
|
53
|
+
const index = this.inputsChangedListeners.indexOf(callback)
|
54
|
+
if (index !== -1) {
|
55
|
+
this.inputsChangedListeners.splice(index, 1)
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
fireChange (): void {
|
61
|
+
this.listeners.forEach(listener => { listener() })
|
62
|
+
}
|
63
|
+
|
64
|
+
fireInputsChanged (): void {
|
65
|
+
this.inputsChangedListeners.forEach(listener => { listener() })
|
66
|
+
}
|
67
|
+
|
68
|
+
setInputs (inputs: InputsOf<CommandT>): void {
|
69
|
+
this.inputs = inputs
|
70
|
+
this.fireInputsChanged()
|
71
|
+
this.setDirty()
|
72
|
+
}
|
73
|
+
|
74
|
+
setDirty (): void {
|
75
|
+
this.isDirty = true
|
76
|
+
this.run()
|
77
|
+
}
|
78
|
+
|
79
|
+
get isSuccess (): boolean {
|
80
|
+
return !this.isFailure && (this.command?.outcome?.isSuccess() ?? false)
|
81
|
+
}
|
82
|
+
|
83
|
+
get isError (): boolean {
|
84
|
+
if (this.command?.outcome == null) {
|
85
|
+
return false
|
86
|
+
}
|
87
|
+
return !this.command.outcome.isSuccess()
|
88
|
+
}
|
89
|
+
|
90
|
+
get isPending (): boolean {
|
91
|
+
return !this.isLoading || !this.isFailure || this.command == null
|
92
|
+
}
|
93
|
+
|
94
|
+
async run (): Promise<void> {
|
95
|
+
if (this.isLoading) {
|
96
|
+
this.ranWhileRunning = true
|
97
|
+
this.fireChange()
|
98
|
+
return
|
99
|
+
}
|
100
|
+
|
101
|
+
try {
|
102
|
+
this.isLoading = true
|
103
|
+
const command = new this.CommandClass(this.inputs)
|
104
|
+
this.fireChange()
|
105
|
+
|
106
|
+
await command.run()
|
107
|
+
|
108
|
+
this.isFailure = false
|
109
|
+
this.isDirty = false
|
110
|
+
this.command = command
|
111
|
+
this.failure = undefined
|
112
|
+
} catch (error) {
|
113
|
+
this.isFailure = true
|
114
|
+
this.failure = error
|
115
|
+
throw error
|
116
|
+
} finally {
|
117
|
+
this.isLoading = false
|
118
|
+
this.fireChange()
|
119
|
+
if (this.ranWhileRunning) {
|
120
|
+
this.ranWhileRunning = false
|
121
|
+
this.run()
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import type RemoteCommand from '../base/RemoteCommand'
|
2
|
+
import Query from '../base/Query'
|
3
|
+
import { type InputsOf, type RemoteCommandConstructor } from '../base/RemoteCommandTypes'
|
4
|
+
|
5
|
+
const queryCache = new Map<string, Query<RemoteCommand<any, any, any>>>()
|
6
|
+
|
7
|
+
export function getQuery<CommandT extends RemoteCommand<any, any, any>> (
|
8
|
+
CommandClass: RemoteCommandConstructor<CommandT>,
|
9
|
+
inputs: InputsOf<CommandT> | undefined = undefined
|
10
|
+
): Query<CommandT> {
|
11
|
+
const key: string = toKey(CommandClass, inputs)
|
12
|
+
const hit = queryCache.get(key)
|
13
|
+
|
14
|
+
if (hit != null) {
|
15
|
+
return (hit as unknown as Query<CommandT>)
|
16
|
+
}
|
17
|
+
|
18
|
+
let query: Query<CommandT>
|
19
|
+
if (arguments.length === 2) {
|
20
|
+
query = new Query<CommandT>(CommandClass, inputs)
|
21
|
+
query.run()
|
22
|
+
} else {
|
23
|
+
query = new Query<CommandT>(CommandClass)
|
24
|
+
}
|
25
|
+
|
26
|
+
query.onInputsChange(() => {
|
27
|
+
queryCache.delete(key)
|
28
|
+
const newKey = toKey(CommandClass, query.inputs)
|
29
|
+
queryCache.set(newKey, query)
|
30
|
+
})
|
31
|
+
|
32
|
+
queryCache.set(key, query)
|
33
|
+
return query
|
34
|
+
}
|
35
|
+
|
36
|
+
function toKey<CommandT extends RemoteCommand<any, any, any>> (
|
37
|
+
CommandClass: RemoteCommandConstructor<CommandT>,
|
38
|
+
inputs: InputsOf<CommandT> | undefined
|
39
|
+
): string {
|
40
|
+
let key: string = CommandClass.fullCommandName
|
41
|
+
|
42
|
+
if (inputs != null) {
|
43
|
+
key += JSON.stringify(inputs)
|
44
|
+
}
|
45
|
+
|
46
|
+
return key
|
47
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import type RemoteCommand from './RemoteCommand'
|
2
|
+
|
3
|
+
export type InputsOf<CommandClass> = CommandClass extends RemoteCommand<infer Inputs, any, any> ? Inputs : never
|
4
|
+
export type ResultOf<CommandClass> = CommandClass extends RemoteCommand<any, infer Result, any> ? Result : never
|
5
|
+
export type ErrorOf<CommandClass> = CommandClass extends RemoteCommand<any, any, infer Error> ? Error : never
|
6
|
+
|
7
|
+
export interface RemoteCommandConstructor<CommandT extends RemoteCommand<any, any, any>> {
|
8
|
+
new (inputs: InputsOf<CommandT>): CommandT
|
9
|
+
fullCommandName: string
|
10
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import type RemoteCommand from '../base/RemoteCommand'
|
2
|
+
import { type Outcome } from '../base/Outcome'
|
3
|
+
import {
|
4
|
+
type InputsOf, type ResultOf, type ErrorOf, type RemoteCommandConstructor
|
5
|
+
} from '../base/RemoteCommandTypes'
|
6
|
+
import type Query from '../base/Query'
|
7
|
+
import { useState, useRef, useEffect } from 'react'
|
8
|
+
import { getQuery } from '../base/QueryCache'
|
9
|
+
|
10
|
+
interface QueryState<CommandT extends RemoteCommand<any, any, any>> {
|
11
|
+
isLoading: boolean
|
12
|
+
isPending: boolean
|
13
|
+
isFailure: boolean
|
14
|
+
isSuccess: boolean
|
15
|
+
isError: boolean
|
16
|
+
outcome: null | Outcome<ResultOf<CommandT>, ErrorOf<CommandT>>
|
17
|
+
result: null | ResultOf<CommandT>
|
18
|
+
errors: null | Array<ErrorOf<CommandT>>
|
19
|
+
failure: any
|
20
|
+
setInputs: (inputs: InputsOf<CommandT>) => void
|
21
|
+
setDirty: () => void
|
22
|
+
}
|
23
|
+
|
24
|
+
function queryToQueryState<CommandT extends RemoteCommand<any, any, any>> (
|
25
|
+
query: Query<CommandT>
|
26
|
+
): QueryState<CommandT> {
|
27
|
+
return {
|
28
|
+
isLoading: query.isLoading,
|
29
|
+
isPending: query.isPending,
|
30
|
+
isFailure: query.isFailure,
|
31
|
+
isSuccess: query.isSuccess,
|
32
|
+
isError: query.isError,
|
33
|
+
outcome: query.outcome,
|
34
|
+
result: query.result,
|
35
|
+
errors: query.errors,
|
36
|
+
failure: query.failure,
|
37
|
+
setInputs: (inputs: InputsOf<CommandT>) => { query.setInputs(inputs) },
|
38
|
+
setDirty: () => { query.setDirty() }
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
export default function useQuery<CommandT extends RemoteCommand<any, any, any>> (
|
43
|
+
CommandClass: RemoteCommandConstructor<CommandT>,
|
44
|
+
inputs: InputsOf<CommandT> | undefined = undefined
|
45
|
+
): QueryState<CommandT> {
|
46
|
+
const queryRef = useRef<Query<CommandT>>(null)
|
47
|
+
|
48
|
+
let query = queryRef.current
|
49
|
+
|
50
|
+
if (query == null) {
|
51
|
+
if (arguments.length === 2) {
|
52
|
+
query = getQuery(CommandClass, inputs as InputsOf<CommandT>)
|
53
|
+
} else {
|
54
|
+
query = getQuery(CommandClass)
|
55
|
+
}
|
56
|
+
|
57
|
+
queryRef.current = query
|
58
|
+
}
|
59
|
+
|
60
|
+
useEffect(() => {
|
61
|
+
const unsubscribe = query?.onChange(() => {
|
62
|
+
if (query != null) { // just here to satisfy type checker
|
63
|
+
setQueryState(queryToQueryState<CommandT>(query))
|
64
|
+
}
|
65
|
+
})
|
66
|
+
|
67
|
+
return unsubscribe
|
68
|
+
}, [query])
|
69
|
+
|
70
|
+
const [queryState, setQueryState] = useState<QueryState<CommandT>>(
|
71
|
+
queryToQueryState<CommandT>(query)
|
72
|
+
)
|
73
|
+
|
74
|
+
return queryState
|
75
|
+
}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara-typescript-remote-command-generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
10
|
+
date: 2025-05-14 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: foobara-files-generator
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- src/remote_generator/services/auth/refresh_login_generator.rb
|
51
51
|
- src/remote_generator/services/auth/requires_auth_command_generator.rb
|
52
52
|
- src/remote_generator/services/auth/requires_auth_generator.rb
|
53
|
+
- src/remote_generator/services/auth/setup_generator.rb
|
53
54
|
- src/remote_generator/services/command_errors_generator.rb
|
54
55
|
- src/remote_generator/services/command_errors_index_generator.rb
|
55
56
|
- src/remote_generator/services/command_generator.rb
|
@@ -108,7 +109,12 @@ files:
|
|
108
109
|
- templates/base/Error.ts
|
109
110
|
- templates/base/Model.ts
|
110
111
|
- templates/base/Outcome.ts
|
112
|
+
- templates/base/Query.ts
|
113
|
+
- templates/base/QueryCache.ts
|
111
114
|
- templates/base/RemoteCommand.ts
|
115
|
+
- templates/base/RemoteCommandTypes.ts
|
116
|
+
- templates/hooks/useQuery.ts
|
117
|
+
- templates/setup.ts.erb
|
112
118
|
homepage: https://github.com/foobara/typescript-remote-command-generator
|
113
119
|
licenses:
|
114
120
|
- Apache-2.0
|