@feathersjs/feathers 5.0.0-pre.6 → 5.0.0

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.
@@ -1,10 +1,10 @@
1
- import version from './version';
2
- import {
3
- EventEmitter, stripSlashes, createDebug, HOOKS
4
- } from './dependencies';
5
- import { eventHook, eventMixin } from './events';
6
- import { hookMixin } from './hooks/index';
7
- import { wrapService, getServiceOptions, protectedMethods } from './service';
1
+ import version from './version'
2
+ import { EventEmitter } from 'events'
3
+ import { stripSlashes, createDebug } from '@feathersjs/commons'
4
+ import { HOOKS, hooks, middleware } from '@feathersjs/hooks'
5
+ import { eventHook, eventMixin } from './events'
6
+ import { hookMixin } from './hooks'
7
+ import { wrapService, getServiceOptions, protectedMethods } from './service'
8
8
  import {
9
9
  FeathersApplication,
10
10
  ServiceMixin,
@@ -12,152 +12,213 @@ import {
12
12
  ServiceOptions,
13
13
  ServiceInterface,
14
14
  Application,
15
- HookOptions,
16
15
  FeathersService,
17
- HookMap,
18
- LegacyHookMap
19
- } from './declarations';
20
- import { enableLegacyHooks } from './hooks/legacy';
21
-
22
- const debug = createDebug('@feathersjs/feathers');
23
-
24
- export class Feathers<ServiceTypes, AppSettings> extends EventEmitter implements FeathersApplication<ServiceTypes, AppSettings> {
25
- services: ServiceTypes = ({} as ServiceTypes);
26
- settings: AppSettings = ({} as AppSettings);
27
- mixins: ServiceMixin<Application<ServiceTypes, AppSettings>>[] = [ hookMixin, eventMixin ];
28
- version: string = version;
29
- _isSetup = false;
30
- appHooks: HookMap<Application<ServiceTypes, AppSettings>, any> = {
31
- [HOOKS]: [ (eventHook as any) ]
32
- };
33
-
34
- private legacyHooks: (this: any, allHooks: any) => any;
35
-
36
- constructor () {
37
- super();
38
- this.legacyHooks = enableLegacyHooks(this);
16
+ ApplicationHookOptions
17
+ } from './declarations'
18
+ import { enableHooks } from './hooks'
19
+
20
+ const debug = createDebug('@feathersjs/feathers')
21
+
22
+ export class Feathers<Services, Settings>
23
+ extends EventEmitter
24
+ implements FeathersApplication<Services, Settings>
25
+ {
26
+ services: Services = {} as Services
27
+ settings: Settings = {} as Settings
28
+ mixins: ServiceMixin<Application<Services, Settings>>[] = [hookMixin, eventMixin]
29
+ version: string = version
30
+ _isSetup = false
31
+
32
+ protected registerHooks: (this: any, allHooks: any) => any
33
+
34
+ constructor() {
35
+ super()
36
+ this.registerHooks = enableHooks(this)
37
+ this.registerHooks({
38
+ around: [eventHook]
39
+ })
39
40
  }
40
41
 
41
- get<L extends keyof AppSettings & string> (name: L): AppSettings[L] {
42
- return this.settings[name];
42
+ get<L extends keyof Settings & string>(name: L): Settings[L] {
43
+ return this.settings[name]
43
44
  }
44
45
 
45
- set<L extends keyof AppSettings & string> (name: L, value: AppSettings[L]) {
46
- this.settings[name] = value;
47
- return this;
46
+ set<L extends keyof Settings & string>(name: L, value: Settings[L]) {
47
+ this.settings[name] = value
48
+ return this
48
49
  }
49
50
 
50
- configure (callback: (this: this, app: this) => void) {
51
- callback.call(this, this);
51
+ configure(callback: (this: this, app: this) => void) {
52
+ callback.call(this, this)
52
53
 
53
- return this;
54
+ return this
54
55
  }
55
56
 
56
- defaultService (location: string): ServiceInterface<any> {
57
- throw new Error(`Can not find service '${location}'`);
57
+ defaultService(location: string): ServiceInterface {
58
+ throw new Error(`Can not find service '${location}'`)
58
59
  }
59
60
 
60
- service<L extends keyof ServiceTypes & string> (
61
+ service<L extends keyof Services & string>(
61
62
  location: L
62
- ): FeathersService<this, keyof any extends keyof ServiceTypes ? Service<any> : ServiceTypes[L]> {
63
- const path = (stripSlashes(location) || '/') as L;
64
- const current = this.services[path];
63
+ ): FeathersService<this, keyof any extends keyof Services ? Service : Services[L]> {
64
+ const path = (stripSlashes(location) || '/') as L
65
+ const current = this.services[path]
65
66
 
66
67
  if (typeof current === 'undefined') {
67
- this.use(path, this.defaultService(path) as any);
68
- return this.service(path);
68
+ this.use(path, this.defaultService(path) as any)
69
+ return this.service(path)
69
70
  }
70
71
 
71
- return current as any;
72
+ return current as any
73
+ }
74
+
75
+ protected _setup() {
76
+ this._isSetup = true
77
+
78
+ return Object.keys(this.services)
79
+ .reduce(
80
+ (current, path) =>
81
+ current.then(() => {
82
+ const service: any = this.service(path as any)
83
+
84
+ if (typeof service.setup === 'function') {
85
+ debug(`Setting up service for \`${path}\``)
86
+
87
+ return service.setup(this, path)
88
+ }
89
+ }),
90
+ Promise.resolve()
91
+ )
92
+ .then(() => this)
93
+ }
94
+
95
+ get setup() {
96
+ return this._setup
97
+ }
98
+
99
+ set setup(value) {
100
+ this._setup = (value as any)[HOOKS]
101
+ ? value
102
+ : hooks(
103
+ value,
104
+ middleware().params('server').props({
105
+ app: this
106
+ })
107
+ )
108
+ }
109
+
110
+ protected _teardown() {
111
+ this._isSetup = false
112
+
113
+ return Object.keys(this.services)
114
+ .reduce(
115
+ (current, path) =>
116
+ current.then(() => {
117
+ const service: any = this.service(path as any)
118
+
119
+ if (typeof service.teardown === 'function') {
120
+ debug(`Tearing down service for \`${path}\``)
121
+
122
+ return service.teardown(this, path)
123
+ }
124
+ }),
125
+ Promise.resolve()
126
+ )
127
+ .then(() => this)
128
+ }
129
+
130
+ get teardown() {
131
+ return this._teardown
72
132
  }
73
133
 
74
- use<L extends keyof ServiceTypes & string> (
134
+ set teardown(value) {
135
+ this._teardown = (value as any)[HOOKS]
136
+ ? value
137
+ : hooks(
138
+ value,
139
+ middleware().params('server').props({
140
+ app: this
141
+ })
142
+ )
143
+ }
144
+
145
+ use<L extends keyof Services & string>(
75
146
  path: L,
76
- service: keyof any extends keyof ServiceTypes ? ServiceInterface<any> | Application : ServiceTypes[L],
77
- options?: ServiceOptions
147
+ service: keyof any extends keyof Services ? ServiceInterface | Application : Services[L],
148
+ options?: ServiceOptions<keyof any extends keyof Services ? string : keyof Services[L]>
78
149
  ): this {
79
150
  if (typeof path !== 'string') {
80
- throw new Error(`'${path}' is not a valid service path.`);
151
+ throw new Error(`'${path}' is not a valid service path.`)
81
152
  }
82
153
 
83
- const location = (stripSlashes(path) || '/') as L;
84
- const subApp = service as Application;
85
- const isSubApp = typeof subApp.service === 'function' && subApp.services;
154
+ const location = (stripSlashes(path) || '/') as L
155
+ const subApp = service as Application
156
+ const isSubApp = typeof subApp.service === 'function' && subApp.services
86
157
 
87
158
  if (isSubApp) {
88
- Object.keys(subApp.services).forEach(subPath =>
159
+ Object.keys(subApp.services).forEach((subPath) =>
89
160
  this.use(`${location}/${subPath}` as any, subApp.service(subPath) as any)
90
- );
161
+ )
91
162
 
92
- return this;
163
+ return this
93
164
  }
94
165
 
95
- const protoService = wrapService(location, service, options);
96
- const serviceOptions = getServiceOptions(service, options);
166
+ const protoService = wrapService(location, service, options as ServiceOptions)
167
+ const serviceOptions = getServiceOptions(protoService)
97
168
 
98
169
  for (const name of protectedMethods) {
99
170
  if (serviceOptions.methods.includes(name)) {
100
- throw new Error(`'${name}' on service '${location}' is not allowed as a custom method name`);
171
+ throw new Error(`'${name}' on service '${location}' is not allowed as a custom method name`)
101
172
  }
102
173
  }
103
174
 
104
- debug(`Registering new service at \`${location}\``);
175
+ debug(`Registering new service at \`${location}\``)
105
176
 
106
177
  // Add all the mixins
107
- this.mixins.forEach(fn => fn.call(this, protoService, location, serviceOptions));
178
+ this.mixins.forEach((fn) => fn.call(this, protoService, location, serviceOptions))
179
+
180
+ this.services[location] = protoService
108
181
 
109
182
  // If we ran setup already, set this service up explicitly, this will not `await`
110
183
  if (this._isSetup && typeof protoService.setup === 'function') {
111
- debug(`Setting up service for \`${location}\``);
112
- protoService.setup(this, location);
184
+ debug(`Setting up service for \`${location}\``)
185
+ protoService.setup(this, location)
113
186
  }
114
187
 
115
- this.services[location] = protoService;
116
-
117
- return this;
188
+ return this
118
189
  }
119
190
 
120
- hooks (hookMap: HookOptions<this, any>) {
121
- const legacyMap = hookMap as LegacyHookMap<this, any>;
191
+ async unuse<L extends keyof Services & string>(
192
+ location: L
193
+ ): Promise<FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>> {
194
+ const path = (stripSlashes(location) || '/') as L
195
+ const service = this.services[path] as Service
122
196
 
123
- if (legacyMap.before || legacyMap.after || legacyMap.error) {
124
- return this.legacyHooks(legacyMap);
197
+ if (service && typeof service.teardown === 'function') {
198
+ await service.teardown(this as any, path)
125
199
  }
126
200
 
127
- if (Array.isArray(hookMap)) {
128
- this.appHooks[HOOKS].push(...hookMap as any);
129
- } else {
130
- const methodHookMap = hookMap as HookMap<Application<ServiceTypes, AppSettings>, any>;
131
-
132
- Object.keys(methodHookMap).forEach(key => {
133
- const methodHooks = this.appHooks[key] || [];
201
+ delete this.services[path]
134
202
 
135
- this.appHooks[key] = methodHooks.concat(methodHookMap[key]);
136
- });
137
- }
138
-
139
- return this;
203
+ return service as any
140
204
  }
141
205
 
142
- setup () {
143
- let promise = Promise.resolve();
144
-
145
- // Setup each service (pass the app so that they can look up other services etc.)
146
- for (const path of Object.keys(this.services)) {
147
- promise = promise.then(() => {
148
- const service: any = this.service(path as any);
149
-
150
- if (typeof service.setup === 'function') {
151
- debug(`Setting up service for \`${path}\``);
152
-
153
- return service.setup(this, path);
154
- }
155
- });
206
+ hooks(hookMap: ApplicationHookOptions<this>) {
207
+ const untypedMap = hookMap as any
208
+
209
+ if (untypedMap.before || untypedMap.after || untypedMap.error || untypedMap.around) {
210
+ // regular hooks for all service methods
211
+ this.registerHooks(untypedMap)
212
+ } else if (untypedMap.setup || untypedMap.teardown) {
213
+ // .setup and .teardown application hooks
214
+ hooks(this, untypedMap)
215
+ } else {
216
+ // Other registration formats are just `around` hooks
217
+ this.registerHooks({
218
+ around: untypedMap
219
+ })
156
220
  }
157
221
 
158
- return promise.then(() => {
159
- this._isSetup = true;
160
- return this;
161
- });
222
+ return this
162
223
  }
163
224
  }