@feathersjs/transport-commons 5.0.0-pre.9 → 5.0.1

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 (49) hide show
  1. package/CHANGELOG.md +198 -225
  2. package/LICENSE +1 -1
  3. package/README.md +2 -2
  4. package/client.d.ts +1 -1
  5. package/lib/channels/channel/base.d.ts +1 -3
  6. package/lib/channels/channel/base.js +2 -2
  7. package/lib/channels/channel/base.js.map +1 -1
  8. package/lib/channels/channel/combined.d.ts +2 -1
  9. package/lib/channels/channel/combined.js +2 -2
  10. package/lib/channels/channel/combined.js.map +1 -1
  11. package/lib/channels/index.d.ts +14 -12
  12. package/lib/channels/index.js +15 -10
  13. package/lib/channels/index.js.map +1 -1
  14. package/lib/channels/mixins.d.ts +3 -3
  15. package/lib/channels/mixins.js +6 -6
  16. package/lib/channels/mixins.js.map +1 -1
  17. package/lib/client.d.ts +2 -2
  18. package/lib/client.js +10 -12
  19. package/lib/client.js.map +1 -1
  20. package/lib/http.d.ts +14 -9
  21. package/lib/http.js +30 -20
  22. package/lib/http.js.map +1 -1
  23. package/lib/index.d.ts +3 -2
  24. package/lib/index.js +8 -2
  25. package/lib/index.js.map +1 -1
  26. package/lib/routing/index.d.ts +9 -4
  27. package/lib/routing/index.js +26 -16
  28. package/lib/routing/index.js.map +1 -1
  29. package/lib/routing/router.d.ts +4 -1
  30. package/lib/routing/router.js +37 -4
  31. package/lib/routing/router.js.map +1 -1
  32. package/lib/socket/index.d.ts +1 -2
  33. package/lib/socket/index.js +10 -10
  34. package/lib/socket/index.js.map +1 -1
  35. package/lib/socket/utils.d.ts +1 -2
  36. package/lib/socket/utils.js +43 -53
  37. package/lib/socket/utils.js.map +1 -1
  38. package/package.json +19 -14
  39. package/src/channels/channel/base.ts +28 -31
  40. package/src/channels/channel/combined.ts +32 -31
  41. package/src/channels/index.ts +67 -61
  42. package/src/channels/mixins.ts +49 -46
  43. package/src/client.ts +70 -70
  44. package/src/http.ts +55 -43
  45. package/src/index.ts +6 -5
  46. package/src/routing/index.ts +45 -28
  47. package/src/routing/router.ts +80 -42
  48. package/src/socket/index.ts +43 -44
  49. package/src/socket/utils.ts +71 -59
package/src/http.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { MethodNotAllowed } from '@feathersjs/errors/lib';
2
- import { HookContext, NullableId, Params } from '@feathersjs/feathers';
3
- import { BaseHookContext } from '@feathersjs/hooks';
1
+ import { MethodNotAllowed } from '@feathersjs/errors/lib'
2
+ import { HookContext, NullableId, Params } from '@feathersjs/feathers'
3
+ import encodeUrl from 'encodeurl'
4
4
 
5
- export const METHOD_HEADER = 'x-service-method';
5
+ export const METHOD_HEADER = 'x-service-method'
6
6
 
7
7
  export interface ServiceParams {
8
- id: NullableId,
9
- data: any,
8
+ id: NullableId
9
+ data: any
10
10
  params: Params
11
11
  }
12
12
 
@@ -14,70 +14,82 @@ export const statusCodes = {
14
14
  created: 201,
15
15
  noContent: 204,
16
16
  methodNotAllowed: 405,
17
- success: 200
18
- };
17
+ success: 200,
18
+ seeOther: 303
19
+ }
19
20
 
20
- export const knownMethods: { [key: string]: any } = {
21
+ export const knownMethods: { [key: string]: string } = {
21
22
  post: 'create',
22
23
  patch: 'patch',
23
24
  put: 'update',
24
25
  delete: 'remove'
25
- };
26
+ }
27
+
28
+ export function getServiceMethod(_httpMethod: string, id: unknown, headerOverride?: string) {
29
+ const httpMethod = _httpMethod.toLowerCase()
26
30
 
27
- export function getServiceMethod (_httpMethod: string, id: unknown, headerOverride?: string) {
28
- const httpMethod = _httpMethod.toLowerCase();
29
-
30
31
  if (httpMethod === 'post' && headerOverride) {
31
- return headerOverride;
32
+ return headerOverride
32
33
  }
33
34
 
34
- const mappedMethod = knownMethods[httpMethod];
35
+ const mappedMethod = knownMethods[httpMethod]
35
36
 
36
37
  if (mappedMethod) {
37
- return mappedMethod;
38
+ return mappedMethod
38
39
  }
39
40
 
40
41
  if (httpMethod === 'get') {
41
- return id === null ? 'find' : 'get';
42
+ return id === null ? 'find' : 'get'
42
43
  }
43
44
 
44
- throw new MethodNotAllowed(`Method ${_httpMethod} not allowed`);
45
+ throw new MethodNotAllowed(`Method ${_httpMethod} not allowed`)
45
46
  }
46
47
 
47
48
  export const argumentsFor = {
48
- get: ({ id, params }: ServiceParams) => [ id, params ],
49
- find: ({ params }: ServiceParams) => [ params ],
50
- create: ({ data, params }: ServiceParams) => [ data, params ],
51
- update: ({ id, data, params }: ServiceParams) => [ id, data, params ],
52
- patch: ({ id, data, params }: ServiceParams) => [ id, data, params ],
53
- remove: ({ id, params }: ServiceParams) => [ id, params ],
54
- default: ({ data, params }: ServiceParams) => [ data, params ]
49
+ get: ({ id, params }: ServiceParams) => [id, params],
50
+ find: ({ params }: ServiceParams) => [params],
51
+ create: ({ data, params }: ServiceParams) => [data, params],
52
+ update: ({ id, data, params }: ServiceParams) => [id, data, params],
53
+ patch: ({ id, data, params }: ServiceParams) => [id, data, params],
54
+ remove: ({ id, params }: ServiceParams) => [id, params],
55
+ default: ({ data, params }: ServiceParams) => [data, params]
55
56
  }
56
57
 
57
- export function getData (context: HookContext|{ [key: string]: any }) {
58
- if (!(context instanceof BaseHookContext)) {
59
- return context;
58
+ export function getStatusCode(context: HookContext, body: any, location: string | string[]) {
59
+ const { http = {} } = context
60
+
61
+ if (http.status) {
62
+ return http.status
60
63
  }
61
64
 
62
- return context.dispatch !== undefined
63
- ? context.dispatch
64
- : context.result;
65
- }
65
+ if (context.method === 'create') {
66
+ return statusCodes.created
67
+ }
66
68
 
67
- export function getStatusCode (context: HookContext, data?: any) {
68
- if (context instanceof BaseHookContext) {
69
- if (context.statusCode) {
70
- return context.statusCode;
71
- }
69
+ if (location !== undefined) {
70
+ return statusCodes.seeOther
71
+ }
72
72
 
73
- if (context.method === 'create') {
74
- return statusCodes.created;
75
- }
73
+ if (!body) {
74
+ return statusCodes.noContent
76
75
  }
77
76
 
78
- if (!data) {
79
- return statusCodes.noContent;
77
+ return statusCodes.success
78
+ }
79
+
80
+ export function getResponse(context: HookContext) {
81
+ const { http = {} } = context
82
+ const body = context.dispatch !== undefined ? context.dispatch : context.result
83
+
84
+ let headers = http.headers || {}
85
+ let location = headers.Location
86
+
87
+ if (http.location !== undefined) {
88
+ location = encodeUrl(http.location)
89
+ headers = { ...headers, Location: location }
80
90
  }
81
91
 
82
- return statusCodes.success;
92
+ const status = getStatusCode(context, body, location)
93
+
94
+ return { status, headers, body }
83
95
  }
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { socket } from './socket';
2
- import { routing } from './routing';
3
- import { channels } from './channels';
1
+ import { socket } from './socket'
2
+ import { routing } from './routing'
3
+ import { channels, Channel, CombinedChannel } from './channels'
4
+ import { RealTimeConnection } from '@feathersjs/feathers'
4
5
 
5
- export * as http from './http';
6
- export { socket, routing, channels };
6
+ export * as http from './http'
7
+ export { socket, routing, channels, Channel, CombinedChannel, RealTimeConnection }
@@ -1,45 +1,62 @@
1
- import { Application, Service } from '@feathersjs/feathers';
2
- import { Router } from './router';
1
+ import { Application, FeathersService, ServiceOptions } from '@feathersjs/feathers'
2
+ import { Router } from './router'
3
3
 
4
4
  declare module '@feathersjs/feathers/lib/declarations' {
5
5
  interface RouteLookup {
6
- service: Service<any>,
7
- params: { [key: string]: string }
6
+ service: Service
7
+ params: { [key: string]: any }
8
8
  }
9
9
 
10
- interface Application<ServiceTypes, AppSettings> { // eslint-disable-line
11
- routes: Router<any>;
12
- lookup (path: string): RouteLookup;
10
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
+ interface Application<Services, Settings> {
12
+ // eslint-disable-line
13
+ routes: Router<{
14
+ service: Service
15
+ params?: { [key: string]: any }
16
+ }>
17
+ lookup(path: string): RouteLookup
13
18
  }
14
19
  }
15
20
 
16
- export * from './router';
21
+ export * from './router'
17
22
 
18
- export const routing = () => (app: Application) => {
19
- if (typeof app.lookup === 'function') {
20
- return;
23
+ const lookup = function (this: Application, path: string) {
24
+ const result = this.routes.lookup(path)
25
+
26
+ if (result === null) {
27
+ return null
21
28
  }
22
29
 
23
- const routes = new Router();
30
+ const {
31
+ params: colonParams,
32
+ data: { service, params: dataParams }
33
+ } = result
24
34
 
25
- Object.assign(app, {
26
- routes,
27
- lookup (this: Application, path: string) {
28
- const result = this.routes.lookup(path);
35
+ const params = dataParams ? { ...dataParams, ...colonParams } : colonParams
29
36
 
30
- if (result !== null) {
31
- const { params, data: service } = result;
37
+ return { service, params }
38
+ }
32
39
 
33
- return { params, service };
34
- }
40
+ export const routing = () => (app: Application) => {
41
+ if (typeof app.lookup === 'function') {
42
+ return
43
+ }
44
+
45
+ const { unuse } = app
35
46
 
36
- return result;
37
- }
38
- });
47
+ app.routes = new Router()
48
+ app.lookup = lookup
49
+ app.unuse = function (path: string) {
50
+ app.routes.remove(path)
51
+ app.routes.remove(`${path}/:__id`)
52
+ return unuse.call(this, path)
53
+ }
39
54
 
40
55
  // Add a mixin that registers a service on the router
41
- app.mixins.push((service: Service<any>, path: string) => {
42
- app.routes.insert(path, service);
43
- app.routes.insert(`${path}/:__id`, service);
44
- });
45
- };
56
+ app.mixins.push((service: FeathersService, path: string, options: ServiceOptions) => {
57
+ const { routeParams: params = {} } = options
58
+
59
+ app.routes.insert(path, { service, params })
60
+ app.routes.insert(`${path}/:__id`, { service, params })
61
+ })
62
+ }
@@ -1,98 +1,136 @@
1
- import { stripSlashes } from '@feathersjs/commons';
1
+ import { stripSlashes } from '@feathersjs/commons'
2
2
 
3
3
  export interface LookupData {
4
- params: { [key: string]: string };
4
+ params: { [key: string]: string }
5
5
  }
6
6
 
7
7
  export interface LookupResult<T> extends LookupData {
8
- data?: T;
8
+ data?: T
9
9
  }
10
10
 
11
11
  export class RouteNode<T = any> {
12
- data?: T;
13
- children: { [key: string]: RouteNode } = {};
14
- placeholders: RouteNode[] = [];
12
+ data?: T
13
+ children: { [key: string]: RouteNode } = {}
14
+ placeholders: RouteNode[] = []
15
15
 
16
- constructor (public name: string, public depth: number) {}
16
+ constructor(public name: string, public depth: number) {}
17
17
 
18
- insert (path: string[], data: T): RouteNode<T> {
18
+ get hasChildren() {
19
+ return Object.keys(this.children).length !== 0 || this.placeholders.length !== 0
20
+ }
21
+
22
+ insert(path: string[], data: T): RouteNode<T> {
19
23
  if (this.depth === path.length) {
20
24
  if (this.data !== undefined) {
21
- throw new Error(`Path ${path.join('/')} already exists`);
25
+ throw new Error(`Path ${path.join('/')} already exists`)
22
26
  }
23
27
 
24
- this.data = data;
25
- return this;
28
+ this.data = data
29
+ return this
26
30
  }
27
31
 
28
- const current = path[this.depth];
29
- const nextDepth = this.depth + 1;
32
+ const current = path[this.depth]
33
+ const nextDepth = this.depth + 1
30
34
 
31
35
  if (current.startsWith(':')) {
32
36
  // Insert a placeholder node like /messages/:id
33
- const placeholderName = current.substring(1);
34
- let placeholder = this.placeholders.find(p => p.name === placeholderName);
37
+ const placeholderName = current.substring(1)
38
+ let placeholder = this.placeholders.find((p) => p.name === placeholderName)
35
39
 
36
40
  if (!placeholder) {
37
- placeholder = new RouteNode(placeholderName, nextDepth);
38
- this.placeholders.push(placeholder);
41
+ placeholder = new RouteNode(placeholderName, nextDepth)
42
+ this.placeholders.push(placeholder)
39
43
  }
40
44
 
41
- return placeholder.insert(path, data);
45
+ return placeholder.insert(path, data)
42
46
  }
43
47
 
44
- const child = this.children[current] || new RouteNode(current, nextDepth);
48
+ const child = this.children[current] || new RouteNode(current, nextDepth)
45
49
 
46
- this.children[current] = child;
50
+ this.children[current] = child
47
51
 
48
- return child.insert(path, data);
52
+ return child.insert(path, data)
49
53
  }
50
54
 
51
- lookup (path: string[], info: LookupData): LookupResult<T>|null {
55
+ remove(path: string[]) {
52
56
  if (path.length === this.depth) {
53
- return this.data === undefined ? null : {
54
- ...info,
55
- data: this.data
57
+ return
58
+ }
59
+
60
+ const current = path[this.depth]
61
+
62
+ if (current.startsWith(':')) {
63
+ const placeholderName = current.substring(1)
64
+ const placeholder = this.placeholders.find((p) => p.name === placeholderName)
65
+
66
+ placeholder.remove(path)
67
+ this.placeholders = this.placeholders.filter((p) => p !== placeholder)
68
+ } else if (this.children[current]) {
69
+ const child = this.children[current]
70
+
71
+ child.remove(path)
72
+
73
+ if (!child.hasChildren) {
74
+ delete this.children[current]
56
75
  }
57
76
  }
77
+ }
78
+
79
+ lookup(path: string[], info: LookupData): LookupResult<T> | null {
80
+ if (path.length === this.depth) {
81
+ return this.data === undefined
82
+ ? null
83
+ : {
84
+ ...info,
85
+ data: this.data
86
+ }
87
+ }
58
88
 
59
- const current = path[this.depth];
60
- const child = this.children[current];
89
+ const current = path[this.depth]
90
+ const child = this.children[current]
61
91
 
62
92
  if (child) {
63
- return child.lookup(path, info);
93
+ const lookup = child.lookup(path, info)
94
+
95
+ if (lookup !== null) {
96
+ return lookup
97
+ }
64
98
  }
65
99
 
66
100
  // This will return the first placeholder that matches early
67
- for(const placeholder of this.placeholders) {
68
- const result = placeholder.lookup(path, info);
101
+ for (const placeholder of this.placeholders) {
102
+ const result = placeholder.lookup(path, info)
69
103
 
70
104
  if (result !== null) {
71
- result.params[placeholder.name] = current;
72
- return result;
105
+ result.params[placeholder.name] = current
106
+ return result
73
107
  }
74
108
  }
75
109
 
76
- return null;
110
+ return null
77
111
  }
78
112
  }
79
113
 
80
- export class Router<T> {
81
- constructor (public root: RouteNode<T> = new RouteNode<T>('', 0)) {}
114
+ export class Router<T = any> {
115
+ constructor(public root: RouteNode<T> = new RouteNode<T>('', 0)) {}
116
+
117
+ getPath(path: string) {
118
+ return stripSlashes(path).split('/')
119
+ }
82
120
 
83
- getPath (path: string) {
84
- return stripSlashes(path).split('/');
121
+ insert(path: string, data: T) {
122
+ return this.root.insert(this.getPath(path), data)
85
123
  }
86
124
 
87
- insert (path: string, data: T) {
88
- return this.root.insert(this.getPath(path), data);
125
+ remove(path: string) {
126
+ return this.root.remove(this.getPath(path))
89
127
  }
90
128
 
91
- lookup (path: string) {
129
+ lookup(path: string) {
92
130
  if (typeof path !== 'string') {
93
- return null;
131
+ return null
94
132
  }
95
133
 
96
- return this.root.lookup(this.getPath(path), { params: {} });
134
+ return this.root.lookup(this.getPath(path), { params: {} })
97
135
  }
98
136
  }
@@ -1,70 +1,69 @@
1
- import { Application, getServiceOptions, Params } from '@feathersjs/feathers';
2
- import { createDebug } from '@feathersjs/commons';
3
- import { channels } from '../channels';
4
- import { routing } from '../routing';
5
- import { getDispatcher, runMethod } from './utils';
6
- import { RealTimeConnection } from '../channels/channel/base';
1
+ import { Application, getServiceOptions, Params, RealTimeConnection } from '@feathersjs/feathers'
2
+ import { createDebug } from '@feathersjs/commons'
3
+ import { channels } from '../channels'
4
+ import { routing } from '../routing'
5
+ import { getDispatcher, runMethod } from './utils'
7
6
 
8
- const debug = createDebug('@feathersjs/transport-commons');
7
+ const debug = createDebug('@feathersjs/transport-commons')
9
8
 
10
9
  export interface SocketOptions {
11
- done: Promise<any>;
12
- emit: string;
13
- socketMap: WeakMap<RealTimeConnection, any>;
14
- socketKey?: any;
15
- getParams: (socket: any) => RealTimeConnection;
10
+ done: Promise<any>
11
+ emit: string
12
+ socketMap: WeakMap<RealTimeConnection, any>
13
+ socketKey?: any
14
+ getParams: (socket: any) => RealTimeConnection
16
15
  }
17
16
 
18
- export function socket ({ done, emit, socketMap, socketKey, getParams }: SocketOptions) {
17
+ export function socket({ done, emit, socketMap, socketKey, getParams }: SocketOptions) {
19
18
  return (app: Application) => {
20
19
  const leaveChannels = (connection: RealTimeConnection) => {
21
- const { channels } = app;
20
+ const { channels } = app
22
21
 
23
22
  if (channels.length) {
24
- app.channel(app.channels).leave(connection);
23
+ app.channel(app.channels).leave(connection)
25
24
  }
26
- };
25
+ }
27
26
 
28
- app.configure(channels());
29
- app.configure(routing());
27
+ app.configure(channels())
28
+ app.configure(routing())
30
29
 
31
- app.on('publish', getDispatcher(emit, socketMap, socketKey));
32
- app.on('disconnect', leaveChannels);
30
+ app.on('publish', getDispatcher(emit, socketMap, socketKey))
31
+ app.on('disconnect', leaveChannels)
33
32
  app.on('logout', (_authResult: any, params: Params) => {
34
- const { connection } = params;
33
+ const { connection } = params
35
34
 
36
35
  if (connection) {
37
- leaveChannels(connection);
36
+ leaveChannels(connection)
38
37
  }
39
- });
38
+ })
40
39
 
41
40
  // `connection` event
42
- done.then(provider => provider.on('connection', (connection: any) =>
43
- app.emit('connection', getParams(connection)))
44
- );
41
+ done.then((provider) =>
42
+ provider.on('connection', (connection: any) => app.emit('connection', getParams(connection)))
43
+ )
45
44
 
46
45
  // `socket.emit('methodName', 'serviceName', ...args)` handlers
47
- done.then(provider => provider.on('connection', (connection: any) => {
48
- const methodHandlers = Object.keys(app.services).reduce((result, name) => {
49
- const { methods } = getServiceOptions(app.service(name));
46
+ done.then((provider) =>
47
+ provider.on('connection', (connection: any) => {
48
+ const methodHandlers = Object.keys(app.services).reduce((result, name) => {
49
+ const { methods } = getServiceOptions(app.service(name))
50
50
 
51
- methods.forEach(method => {
52
- if (!result[method]) {
53
- result[method] = (...args: any[]) => {
54
- const path = args.shift();
51
+ methods.forEach((method) => {
52
+ if (!result[method]) {
53
+ result[method] = (...args: any[]) => {
54
+ const path = args.shift()
55
55
 
56
- debug(`Got '${method}' call for service '${path}'`);
57
- runMethod(app, getParams(connection), path, method, args);
56
+ debug(`Got '${method}' call for service '${path}'`)
57
+ runMethod(app, getParams(connection), path, method, args)
58
+ }
58
59
  }
59
- }
60
- });
60
+ })
61
61
 
62
- return result;
63
- }, {} as any);
62
+ return result
63
+ }, {} as any)
64
64
 
65
- Object.keys(methodHandlers).forEach(key =>
66
- connection.on(key, methodHandlers[key])
67
- );
68
- }));
69
- };
65
+ Object.keys(methodHandlers).forEach((key) => connection.on(key, methodHandlers[key]))
66
+ })
67
+ )
68
+ }
70
69
  }