@feathersjs/feathers 5.0.0-pre.3 → 5.0.0-pre.30

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 } 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,146 +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)
72
128
  }
73
129
 
74
- use<L extends keyof ServiceTypes & string> (
130
+ get teardown() {
131
+ return this._teardown
132
+ }
133
+
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],
147
+ service: keyof any extends keyof Services ? ServiceInterface | Application : Services[L],
77
148
  options?: ServiceOptions
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)
167
+ const serviceOptions = getServiceOptions(protoService)
97
168
 
98
- debug(`Registering new service at \`${location}\``);
169
+ for (const name of protectedMethods) {
170
+ if (serviceOptions.methods.includes(name)) {
171
+ throw new Error(`'${name}' on service '${location}' is not allowed as a custom method name`)
172
+ }
173
+ }
174
+
175
+ debug(`Registering new service at \`${location}\``)
99
176
 
100
177
  // Add all the mixins
101
- 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
102
181
 
103
182
  // If we ran setup already, set this service up explicitly, this will not `await`
104
183
  if (this._isSetup && typeof protoService.setup === 'function') {
105
- debug(`Setting up service for \`${location}\``);
106
- protoService.setup(this, location);
184
+ debug(`Setting up service for \`${location}\``)
185
+ protoService.setup(this, location)
107
186
  }
108
187
 
109
- this.services[location] = protoService;
110
-
111
- return this;
188
+ return this
112
189
  }
113
190
 
114
- hooks (hookMap: HookOptions<this, any>) {
115
- 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
116
196
 
117
- if (legacyMap.before || legacyMap.after || legacyMap.error) {
118
- return this.legacyHooks(legacyMap);
197
+ if (service && typeof service.teardown === 'function') {
198
+ await service.teardown(this as any, path)
119
199
  }
120
200
 
121
- if (Array.isArray(hookMap)) {
122
- this.appHooks[HOOKS].push(...hookMap as any);
123
- } else {
124
- const methodHookMap = hookMap as HookMap<Application<ServiceTypes, AppSettings>, any>;
125
-
126
- Object.keys(methodHookMap).forEach(key => {
127
- const methodHooks = this.appHooks[key] || [];
201
+ delete this.services[path]
128
202
 
129
- this.appHooks[key] = methodHooks.concat(methodHookMap[key]);
130
- });
131
- }
132
-
133
- return this;
203
+ return service as any
134
204
  }
135
205
 
136
- setup () {
137
- let promise = Promise.resolve();
138
-
139
- // Setup each service (pass the app so that they can look up other services etc.)
140
- for (const path of Object.keys(this.services)) {
141
- promise = promise.then(() => {
142
- const service: any = this.service(path as any);
143
-
144
- if (typeof service.setup === 'function') {
145
- debug(`Setting up service for \`${path}\``);
146
-
147
- return service.setup(this, path);
148
- }
149
- });
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
+ })
150
220
  }
151
221
 
152
- return promise.then(() => {
153
- this._isSetup = true;
154
- return this;
155
- });
222
+ return this
156
223
  }
157
224
  }