@wix/sdk 1.12.8 → 1.12.10
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.
- package/build/context.d.ts +2 -2
- package/build/event-handlers-modules.d.ts +46 -2
- package/build/event-handlers-modules.js +99 -1
- package/build/nanoevents.d.ts +69 -0
- package/build/nanoevents.js +37 -0
- package/build/service-plugin-modules.d.ts +32 -7
- package/build/service-plugin-modules.js +71 -3
- package/build/wixClient.d.ts +5 -49
- package/build/wixClient.js +9 -147
- package/cjs/build/context.d.ts +2 -2
- package/cjs/build/event-handlers-modules.d.ts +46 -2
- package/cjs/build/event-handlers-modules.js +100 -2
- package/cjs/build/nanoevents.d.ts +69 -0
- package/cjs/build/nanoevents.js +41 -0
- package/cjs/build/service-plugin-modules.d.ts +32 -7
- package/cjs/build/service-plugin-modules.js +73 -5
- package/cjs/build/wixClient.d.ts +5 -49
- package/cjs/build/wixClient.js +6 -144
- package/package.json +5 -5
package/build/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function elevate<T extends RESTFunctionDescriptor
|
|
1
|
+
import { RESTFunctionDescriptor } from '@wix/sdk-types';
|
|
2
|
+
export declare function elevate<T extends RESTFunctionDescriptor>(restModule: T): T;
|
|
3
3
|
export declare const fetchWithAuth: typeof fetch & ((restModuleOpts: import("@wix/sdk-types").HttpClient) => typeof fetch);
|
|
4
4
|
export { graphql } from './graphql.js';
|
|
5
5
|
export { setGlobalWixContext } from './wix-context.js';
|
|
@@ -1,4 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AuthenticationStrategy, EventDefinition, EventHandler, EventIdentity } from '@wix/sdk-types';
|
|
2
|
+
import { Emitter } from './nanoevents.js';
|
|
2
3
|
export declare const isEventHandlerModule: (val: any) => val is EventDefinition<unknown, string>;
|
|
3
4
|
export declare function buildEventDefinition<T extends EventDefinition<any, string>>(eventDefinition: T, registerHandler: (eventDefinition: T, handler: EventHandler<T>) => void): (handler: EventHandler<T>) => void;
|
|
4
|
-
|
|
5
|
+
type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
|
|
6
|
+
[K in keyof T]: T[K] extends EventDefinition<any> ? {
|
|
7
|
+
eventType: T[K]['type'];
|
|
8
|
+
payload: T[K]['__payload'];
|
|
9
|
+
} : never;
|
|
10
|
+
} extends (infer U)[] ? U : never;
|
|
11
|
+
export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
|
|
12
|
+
instanceId: string;
|
|
13
|
+
identity?: EventIdentity;
|
|
14
|
+
} & (T['length'] extends 0 ? {
|
|
15
|
+
eventType: string;
|
|
16
|
+
payload: unknown;
|
|
17
|
+
} : ResolvePossibleEvents<T>);
|
|
18
|
+
export type EventHandlersClient = Emitter<{
|
|
19
|
+
registered: (event: EventDefinition<any>) => void;
|
|
20
|
+
}> & {
|
|
21
|
+
getRegisteredEvents(): Map<string, {
|
|
22
|
+
eventDefinition: EventDefinition;
|
|
23
|
+
handler: EventHandler<EventDefinition>;
|
|
24
|
+
}[]>;
|
|
25
|
+
process<ExpectedEvents extends EventDefinition<any>[] = []>(jwt: string, opts?: {
|
|
26
|
+
expectedEvents: ExpectedEvents;
|
|
27
|
+
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
28
|
+
processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
|
|
29
|
+
expectedEvents: ExpectedEvents;
|
|
30
|
+
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
31
|
+
parseJWT(jwt: string): Promise<ProcessedEvent>;
|
|
32
|
+
parseRequest(request: Request): Promise<ProcessedEvent>;
|
|
33
|
+
executeHandlers(event: ProcessedEvent): Promise<void>;
|
|
34
|
+
apps: {
|
|
35
|
+
AppInstalled: EventDefinition<{
|
|
36
|
+
appId: string;
|
|
37
|
+
originInstanceId: string;
|
|
38
|
+
}, 'AppInstalled'>;
|
|
39
|
+
AppRemoved: EventDefinition<{
|
|
40
|
+
appId: string;
|
|
41
|
+
}, 'AppRemoved'>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare function eventHandlersModules(authStrategy: AuthenticationStrategy<any>): {
|
|
45
|
+
initModule(eventDefinition: EventDefinition<any, string>): (handler: EventHandler<EventDefinition<any, string>>) => void;
|
|
46
|
+
client: EventHandlersClient;
|
|
47
|
+
};
|
|
48
|
+
export {};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { EventDefinition, } from '@wix/sdk-types';
|
|
2
|
+
import { createNanoEvents } from './nanoevents.js';
|
|
1
3
|
export const isEventHandlerModule = (val) => val.__type === 'event-definition';
|
|
2
4
|
export function buildEventDefinition(eventDefinition, registerHandler) {
|
|
3
5
|
return (handler) => {
|
|
4
6
|
registerHandler(eventDefinition, handler);
|
|
5
7
|
};
|
|
6
8
|
}
|
|
7
|
-
|
|
9
|
+
function runHandler(eventDefinition, handler, payload, baseEventMetadata) {
|
|
8
10
|
let envelope;
|
|
9
11
|
if (eventDefinition.isDomainEvent) {
|
|
10
12
|
const domainEventPayload = payload;
|
|
@@ -46,3 +48,99 @@ export function runHandler(eventDefinition, handler, payload, baseEventMetadata)
|
|
|
46
48
|
const transformFromRESTFn = eventDefinition.transformations ?? ((x) => x);
|
|
47
49
|
return handler(transformFromRESTFn(envelope));
|
|
48
50
|
}
|
|
51
|
+
export function eventHandlersModules(authStrategy) {
|
|
52
|
+
const eventHandlers = new Map();
|
|
53
|
+
const webhooksEmitter = createNanoEvents();
|
|
54
|
+
const client = {
|
|
55
|
+
...webhooksEmitter,
|
|
56
|
+
getRegisteredEvents: () => eventHandlers,
|
|
57
|
+
async process(jwt, opts = {
|
|
58
|
+
expectedEvents: [],
|
|
59
|
+
}) {
|
|
60
|
+
const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
|
|
61
|
+
const allExpectedEvents = [
|
|
62
|
+
...opts.expectedEvents,
|
|
63
|
+
...Array.from(eventHandlers.keys()).map((type) => ({ type })),
|
|
64
|
+
];
|
|
65
|
+
if (allExpectedEvents.length > 0 &&
|
|
66
|
+
!allExpectedEvents.some(({ type }) => type === eventType)) {
|
|
67
|
+
throw new Error(`Unexpected event type: ${eventType}. Expected one of: ${allExpectedEvents
|
|
68
|
+
.map((x) => x.type)
|
|
69
|
+
.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
const handlers = eventHandlers.get(eventType) ?? [];
|
|
72
|
+
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, payload, {
|
|
73
|
+
instanceId,
|
|
74
|
+
identity,
|
|
75
|
+
})));
|
|
76
|
+
return {
|
|
77
|
+
instanceId,
|
|
78
|
+
eventType,
|
|
79
|
+
payload,
|
|
80
|
+
identity,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
async processRequest(request, opts) {
|
|
84
|
+
const body = await request.text();
|
|
85
|
+
return this.process(body, opts);
|
|
86
|
+
},
|
|
87
|
+
async parseJWT(jwt) {
|
|
88
|
+
if (!authStrategy.decodeJWT) {
|
|
89
|
+
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
90
|
+
}
|
|
91
|
+
const { decoded, valid } = await authStrategy.decodeJWT(jwt);
|
|
92
|
+
if (!valid) {
|
|
93
|
+
throw new Error('JWT is not valid');
|
|
94
|
+
}
|
|
95
|
+
if (typeof decoded.data !== 'string') {
|
|
96
|
+
throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
|
|
97
|
+
}
|
|
98
|
+
const parsedDecoded = JSON.parse(decoded.data);
|
|
99
|
+
const eventType = parsedDecoded.eventType;
|
|
100
|
+
const instanceId = parsedDecoded.instanceId;
|
|
101
|
+
const identity = parsedDecoded.identity
|
|
102
|
+
? JSON.parse(parsedDecoded.identity)
|
|
103
|
+
: undefined;
|
|
104
|
+
const payload = JSON.parse(parsedDecoded.data);
|
|
105
|
+
return {
|
|
106
|
+
instanceId,
|
|
107
|
+
eventType,
|
|
108
|
+
payload,
|
|
109
|
+
identity,
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
async parseRequest(request) {
|
|
113
|
+
const jwt = await request.text();
|
|
114
|
+
return this.parseJWT(jwt);
|
|
115
|
+
},
|
|
116
|
+
async executeHandlers(event) {
|
|
117
|
+
const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
|
|
118
|
+
if (allExpectedEvents.length > 0 &&
|
|
119
|
+
!allExpectedEvents.some(({ type }) => type === event.eventType)) {
|
|
120
|
+
throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
|
|
121
|
+
.map((x) => x.type)
|
|
122
|
+
.join(', ')}`);
|
|
123
|
+
}
|
|
124
|
+
const handlers = eventHandlers.get(event.eventType) ?? [];
|
|
125
|
+
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
|
|
126
|
+
instanceId: event.instanceId,
|
|
127
|
+
identity: event.identity,
|
|
128
|
+
})));
|
|
129
|
+
},
|
|
130
|
+
apps: {
|
|
131
|
+
AppInstalled: EventDefinition('AppInstalled')(),
|
|
132
|
+
AppRemoved: EventDefinition('AppRemoved')(),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
initModule(eventDefinition) {
|
|
137
|
+
return (handler) => {
|
|
138
|
+
const handlers = eventHandlers.get(eventDefinition.type) ?? [];
|
|
139
|
+
handlers.push({ eventDefinition, handler });
|
|
140
|
+
eventHandlers.set(eventDefinition.type, handlers);
|
|
141
|
+
webhooksEmitter.emit('registered', eventDefinition);
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
client,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create event emitter.
|
|
3
|
+
*
|
|
4
|
+
* ```js
|
|
5
|
+
* import { createNanoEvents } from 'nanoevents'
|
|
6
|
+
*
|
|
7
|
+
* class Ticker {
|
|
8
|
+
* constructor() {
|
|
9
|
+
* this.emitter = createNanoEvents()
|
|
10
|
+
* }
|
|
11
|
+
* on(...args) {
|
|
12
|
+
* return this.emitter.on(...args)
|
|
13
|
+
* }
|
|
14
|
+
* tick() {
|
|
15
|
+
* this.emitter.emit('tick')
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
* @returns Event emitter.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createNanoEvents<Events extends EventsMap = DefaultEvents>(): Emitter<Events>;
|
|
22
|
+
interface EventsMap {
|
|
23
|
+
[event: string]: any;
|
|
24
|
+
}
|
|
25
|
+
interface DefaultEvents extends EventsMap {
|
|
26
|
+
[event: string]: (...args: any) => void;
|
|
27
|
+
}
|
|
28
|
+
export type Unsubscribe = () => void;
|
|
29
|
+
export interface Emitter<Events extends EventsMap = DefaultEvents> {
|
|
30
|
+
/**
|
|
31
|
+
* Calls each of the listeners registered for a given event.
|
|
32
|
+
*
|
|
33
|
+
* ```js
|
|
34
|
+
* ee.emit('tick', tickType, tickDuration)
|
|
35
|
+
* ```
|
|
36
|
+
* @param event The event name.
|
|
37
|
+
* @param args The arguments for listeners.
|
|
38
|
+
*/
|
|
39
|
+
emit<K extends keyof Events>(this: this, event: K, ...args: Parameters<Events[K]>): void;
|
|
40
|
+
/**
|
|
41
|
+
* Event names in keys and arrays with listeners in values.
|
|
42
|
+
*
|
|
43
|
+
* ```js
|
|
44
|
+
* emitter1.events = emitter2.events
|
|
45
|
+
* emitter2.events = { }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
events: Partial<{
|
|
49
|
+
[E in keyof Events]: Events[E][];
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Add a listener for a given event.
|
|
53
|
+
*
|
|
54
|
+
* ```js
|
|
55
|
+
* const unbind = ee.on('tick', (tickType, tickDuration) => {
|
|
56
|
+
* count += 1
|
|
57
|
+
* })
|
|
58
|
+
*
|
|
59
|
+
* disable () {
|
|
60
|
+
* unbind()
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
* @param event The event name.
|
|
64
|
+
* @param cb The listener function.
|
|
65
|
+
* @returns Unbind listener from event.
|
|
66
|
+
*/
|
|
67
|
+
on<K extends keyof Events>(this: this, event: K, cb: Events[K]): Unsubscribe;
|
|
68
|
+
}
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Inlined from https://github.com/ai/nanoevents/blob/main/index.js
|
|
2
|
+
/**
|
|
3
|
+
* Create event emitter.
|
|
4
|
+
*
|
|
5
|
+
* ```js
|
|
6
|
+
* import { createNanoEvents } from 'nanoevents'
|
|
7
|
+
*
|
|
8
|
+
* class Ticker {
|
|
9
|
+
* constructor() {
|
|
10
|
+
* this.emitter = createNanoEvents()
|
|
11
|
+
* }
|
|
12
|
+
* on(...args) {
|
|
13
|
+
* return this.emitter.on(...args)
|
|
14
|
+
* }
|
|
15
|
+
* tick() {
|
|
16
|
+
* this.emitter.emit('tick')
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
* @returns Event emitter.
|
|
21
|
+
*/
|
|
22
|
+
export function createNanoEvents() {
|
|
23
|
+
return {
|
|
24
|
+
emit(event, ...args) {
|
|
25
|
+
for (let i = 0, callbacks = this.events[event] || [], length = callbacks.length; i < length; i++) {
|
|
26
|
+
callbacks[i](...args);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
events: {},
|
|
30
|
+
on(event, cb) {
|
|
31
|
+
(this.events[event] ||= []).push(cb);
|
|
32
|
+
return () => {
|
|
33
|
+
this.events[event] = this.events[event]?.filter((i) => cb !== i);
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -1,8 +1,33 @@
|
|
|
1
|
-
import { ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
|
|
1
|
+
import { AuthenticationStrategy, ServicePluginContract, ServicePluginDefinition } from '@wix/sdk-types';
|
|
2
|
+
import { Emitter } from './nanoevents.js';
|
|
2
3
|
export declare const isServicePluginModule: (val: any) => val is ServicePluginDefinition<ServicePluginContract>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export type UnknownServicePluginResponse = unknown;
|
|
5
|
+
type ServicePluginRequestMetadata = {
|
|
6
|
+
instanceId: string;
|
|
7
|
+
appExtensionType: string;
|
|
8
|
+
};
|
|
9
|
+
type ServicePluginRequest = {
|
|
10
|
+
metadata: ServicePluginRequestMetadata;
|
|
11
|
+
request: unknown;
|
|
12
|
+
};
|
|
13
|
+
export type ServicePluginsClient = Emitter<{
|
|
14
|
+
registered: (servicePluginDefinition: ServicePluginDefinition<ServicePluginContract>) => void;
|
|
15
|
+
}> & {
|
|
16
|
+
getRegisteredServicePlugins(): Map<string, {
|
|
17
|
+
servicePluginDefinition: ServicePluginDefinition<any>;
|
|
18
|
+
implementation: ServicePluginContract;
|
|
19
|
+
}[]>;
|
|
20
|
+
process(request: {
|
|
21
|
+
url: string;
|
|
22
|
+
body: string;
|
|
23
|
+
}): Promise<unknown>;
|
|
24
|
+
processRequest(request: Request): Promise<Response>;
|
|
25
|
+
parseJWT(jwt: string): Promise<ServicePluginRequest>;
|
|
26
|
+
parseRequest(request: Request): Promise<ServicePluginRequest>;
|
|
27
|
+
executeHandler(servicePluginRequest: ServicePluginRequest, url: string): Promise<UnknownServicePluginResponse>;
|
|
28
|
+
};
|
|
29
|
+
export declare function servicePluginsModules(authStrategy: AuthenticationStrategy<any>): {
|
|
30
|
+
initModule<T extends ServicePluginDefinition<any>>(servicePluginDefinition: T): (implementation: T["__contract"]) => void;
|
|
31
|
+
client: ServicePluginsClient;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -1,6 +1,74 @@
|
|
|
1
|
+
import { createNanoEvents } from './nanoevents.js';
|
|
1
2
|
export const isServicePluginModule = (val) => val.__type === 'service-plugin-definition';
|
|
2
|
-
export function
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
export function servicePluginsModules(authStrategy) {
|
|
4
|
+
const servicePluginsImplementations = new Map();
|
|
5
|
+
const servicePluginsEmitter = createNanoEvents();
|
|
6
|
+
const client = {
|
|
7
|
+
...servicePluginsEmitter,
|
|
8
|
+
getRegisteredServicePlugins: () => servicePluginsImplementations,
|
|
9
|
+
async parseJWT(jwt) {
|
|
10
|
+
if (!authStrategy.decodeJWT) {
|
|
11
|
+
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
12
|
+
}
|
|
13
|
+
const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
|
|
14
|
+
if (!valid) {
|
|
15
|
+
throw new Error('JWT is not valid');
|
|
16
|
+
}
|
|
17
|
+
if (typeof decoded.data !== 'object' ||
|
|
18
|
+
decoded.data === null ||
|
|
19
|
+
!('metadata' in decoded.data) ||
|
|
20
|
+
typeof decoded.data.metadata !== 'object' ||
|
|
21
|
+
decoded.data.metadata === null ||
|
|
22
|
+
!('appExtensionType' in decoded.data.metadata) ||
|
|
23
|
+
typeof decoded.data.metadata.appExtensionType !== 'string') {
|
|
24
|
+
throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
|
|
25
|
+
}
|
|
26
|
+
return decoded.data;
|
|
27
|
+
},
|
|
28
|
+
async process(request) {
|
|
29
|
+
const servicePluginRequest = await this.parseJWT(request.body);
|
|
30
|
+
return this.executeHandler(servicePluginRequest, request.url);
|
|
31
|
+
},
|
|
32
|
+
async parseRequest(request) {
|
|
33
|
+
const body = await request.text();
|
|
34
|
+
return this.parseJWT(body);
|
|
35
|
+
},
|
|
36
|
+
async processRequest(request) {
|
|
37
|
+
const url = request.url;
|
|
38
|
+
const body = await request.text();
|
|
39
|
+
const implMethodResult = await this.process({ url, body });
|
|
40
|
+
return Response.json(implMethodResult);
|
|
41
|
+
},
|
|
42
|
+
async executeHandler(servicePluginRequest, url) {
|
|
43
|
+
const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
|
|
44
|
+
const implementations = servicePluginsImplementations.get(componentType) ?? [];
|
|
45
|
+
if (implementations.length === 0) {
|
|
46
|
+
throw new Error(`No service plugin implementations found for component type ${componentType}`);
|
|
47
|
+
}
|
|
48
|
+
else if (implementations.length > 1) {
|
|
49
|
+
throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
|
|
50
|
+
}
|
|
51
|
+
const { implementation: impl, servicePluginDefinition } = implementations[0];
|
|
52
|
+
const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
|
|
53
|
+
if (!method) {
|
|
54
|
+
throw new Error('Unexpect request: request url did not match any method: ' + url);
|
|
55
|
+
}
|
|
56
|
+
const implMethod = impl[method.name];
|
|
57
|
+
if (!implMethod) {
|
|
58
|
+
throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
initModule(servicePluginDefinition) {
|
|
65
|
+
return (implementation) => {
|
|
66
|
+
const implementations = servicePluginsImplementations.get(servicePluginDefinition.componentType.toLowerCase()) ?? [];
|
|
67
|
+
implementations.push({ servicePluginDefinition, implementation });
|
|
68
|
+
servicePluginsImplementations.set(servicePluginDefinition.componentType.toLowerCase(), implementations);
|
|
69
|
+
servicePluginsEmitter.emit('registered', servicePluginDefinition);
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
client,
|
|
5
73
|
};
|
|
6
74
|
}
|
package/build/wixClient.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors,
|
|
1
|
+
import { AuthenticationStrategy, BoundAuthenticationStrategy, BuildDescriptors, Descriptors, Host, HostModule, RESTFunctionDescriptor } from '@wix/sdk-types';
|
|
2
2
|
import { EmptyObject } from 'type-fest/source/empty-object.js';
|
|
3
3
|
import type { GraphQLFormattedError } from 'graphql';
|
|
4
|
+
import { EventHandlersClient } from './event-handlers-modules.js';
|
|
5
|
+
import { ServicePluginsClient } from './service-plugin-modules.js';
|
|
4
6
|
export type ContextType = 'global' | 'module';
|
|
5
7
|
type Headers = Record<string, string>;
|
|
6
8
|
/**
|
|
@@ -42,55 +44,9 @@ export type WixClient<H extends Host<any> | undefined = undefined, Z extends Aut
|
|
|
42
44
|
data: Result;
|
|
43
45
|
errors?: GraphQLFormattedError[];
|
|
44
46
|
}>;
|
|
45
|
-
webhooks:
|
|
46
|
-
|
|
47
|
-
process<ExpectedEvents extends EventDefinition<any>[] = []>(jwt: string, opts?: {
|
|
48
|
-
expectedEvents: ExpectedEvents;
|
|
49
|
-
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
50
|
-
processRequest<ExpectedEvents extends EventDefinition<any>[] = []>(request: Request, opts?: {
|
|
51
|
-
expectedEvents: ExpectedEvents;
|
|
52
|
-
}): Promise<ProcessedEvent<ExpectedEvents>>;
|
|
53
|
-
parseJWT(jwt: string): Promise<ProcessedEvent>;
|
|
54
|
-
parseRequest(request: Request): Promise<ProcessedEvent>;
|
|
55
|
-
executeHandlers(event: ProcessedEvent): Promise<void>;
|
|
56
|
-
apps: {
|
|
57
|
-
AppInstalled: EventDefinition<{
|
|
58
|
-
appId: string;
|
|
59
|
-
originInstanceId: string;
|
|
60
|
-
}, 'AppInstalled'>;
|
|
61
|
-
AppRemoved: EventDefinition<{
|
|
62
|
-
appId: string;
|
|
63
|
-
}, 'AppRemoved'>;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
servicePlugins: {
|
|
67
|
-
getRegisteredServicePlugins(): Map<string, {
|
|
68
|
-
servicePluginDefinition: ServicePluginDefinition<any>;
|
|
69
|
-
implementation: ServicePluginContract;
|
|
70
|
-
}[]>;
|
|
71
|
-
process(request: {
|
|
72
|
-
url: string;
|
|
73
|
-
body: string;
|
|
74
|
-
}): Promise<unknown>;
|
|
75
|
-
processRequest(request: Request): Promise<Response>;
|
|
76
|
-
parseJWT(jwt: string): Promise<unknown>;
|
|
77
|
-
parseRequest(request: Request): Promise<unknown>;
|
|
78
|
-
executeHandler(servicePluginRequest: ProcessedEvent): Promise<void>;
|
|
79
|
-
};
|
|
47
|
+
webhooks: EventHandlersClient;
|
|
48
|
+
servicePlugins: ServicePluginsClient;
|
|
80
49
|
} & BuildDescriptors<T, H>;
|
|
81
|
-
type ResolvePossibleEvents<T extends EventDefinition<any>[]> = {
|
|
82
|
-
[K in keyof T]: T[K] extends EventDefinition<any> ? {
|
|
83
|
-
eventType: T[K]['type'];
|
|
84
|
-
payload: T[K]['__payload'];
|
|
85
|
-
} : never;
|
|
86
|
-
} extends (infer U)[] ? U : never;
|
|
87
|
-
export type ProcessedEvent<T extends EventDefinition<any>[] = []> = {
|
|
88
|
-
instanceId: string;
|
|
89
|
-
identity?: EventIdentity;
|
|
90
|
-
} & (T['length'] extends 0 ? {
|
|
91
|
-
eventType: string;
|
|
92
|
-
payload: unknown;
|
|
93
|
-
} : ResolvePossibleEvents<T>);
|
|
94
50
|
export declare function createClient<H extends Host<any> | undefined = undefined, Z extends AuthenticationStrategy<H> = AuthenticationStrategy<H>, T extends Descriptors = EmptyObject>(config: {
|
|
95
51
|
modules?: H extends Host<any> ? AssertHostMatches<T, H> : T;
|
|
96
52
|
auth?: Z;
|
package/build/wixClient.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { wixContext } from '@wix/sdk-context';
|
|
2
|
-
import {
|
|
2
|
+
import { SERVICE_PLUGIN_ERROR_TYPE, } from '@wix/sdk-types';
|
|
3
3
|
import { ambassadorModuleOptions, isAmbassadorModule, toHTTPModule, } from './ambassador-modules.js';
|
|
4
4
|
import { API_URL, PUBLIC_METADATA_KEY } from './common.js';
|
|
5
5
|
import { FetchErrorResponse } from './fetch-error.js';
|
|
6
6
|
import { getDefaultContentHeader, isObject } from './helpers.js';
|
|
7
7
|
import { buildHostModule, isHostModule } from './host-modules.js';
|
|
8
8
|
import { buildRESTDescriptor } from './rest-modules.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { eventHandlersModules, isEventHandlerModule, } from './event-handlers-modules.js';
|
|
10
|
+
import { isServicePluginModule, servicePluginsModules, } from './service-plugin-modules.js';
|
|
11
11
|
export function createClient(config) {
|
|
12
12
|
const _headers = config.headers || { Authorization: '' };
|
|
13
|
-
const eventHandlers = new Map();
|
|
14
|
-
const servicePluginsImplementations = new Map();
|
|
15
13
|
const authStrategy = config.auth ||
|
|
16
14
|
{
|
|
17
15
|
getAuthHeaders: (_) => Promise.resolve({ headers: {} }),
|
|
18
16
|
};
|
|
19
17
|
const boundGetAuthHeaders = authStrategy.getAuthHeaders.bind(undefined, config.host);
|
|
20
18
|
authStrategy.getAuthHeaders = boundGetAuthHeaders;
|
|
19
|
+
const { client: servicePluginsClient, initModule: initServicePluginModule } = servicePluginsModules(authStrategy);
|
|
20
|
+
const { client: eventHandlersClient, initModule: initEventHandlerModule } = eventHandlersModules(authStrategy);
|
|
21
21
|
const boundFetch = async (url, options) => {
|
|
22
22
|
const authHeaders = await boundGetAuthHeaders();
|
|
23
23
|
const defaultContentTypeHeader = getDefaultContentHeader(options);
|
|
@@ -36,18 +36,10 @@ export function createClient(config) {
|
|
|
36
36
|
// excessively deep and possibly infinite.`
|
|
37
37
|
const use = (modules, metadata) => {
|
|
38
38
|
if (isEventHandlerModule(modules)) {
|
|
39
|
-
return
|
|
40
|
-
const handlers = eventHandlers.get(eventDefinition.type) ?? [];
|
|
41
|
-
handlers.push({ eventDefinition, handler });
|
|
42
|
-
eventHandlers.set(eventDefinition.type, handlers);
|
|
43
|
-
});
|
|
39
|
+
return initEventHandlerModule(modules);
|
|
44
40
|
}
|
|
45
41
|
else if (isServicePluginModule(modules)) {
|
|
46
|
-
return
|
|
47
|
-
const implementations = servicePluginsImplementations.get(servicePluginDefinition.componentType.toLowerCase()) ?? [];
|
|
48
|
-
implementations.push({ servicePluginDefinition, implementation });
|
|
49
|
-
servicePluginsImplementations.set(servicePluginDefinition.componentType.toLowerCase(), implementations);
|
|
50
|
-
});
|
|
42
|
+
return initServicePluginModule(modules);
|
|
51
43
|
}
|
|
52
44
|
else if (isHostModule(modules) && config.host) {
|
|
53
45
|
return buildHostModule(modules, config.host);
|
|
@@ -161,137 +153,7 @@ export function createClient(config) {
|
|
|
161
153
|
const { data, errors } = await res.json();
|
|
162
154
|
return { data: data ?? {}, errors };
|
|
163
155
|
},
|
|
164
|
-
webhooks:
|
|
165
|
-
|
|
166
|
-
async process(jwt, opts = {
|
|
167
|
-
expectedEvents: [],
|
|
168
|
-
}) {
|
|
169
|
-
const { eventType, identity, instanceId, payload } = await this.parseJWT(jwt);
|
|
170
|
-
const allExpectedEvents = [
|
|
171
|
-
...opts.expectedEvents,
|
|
172
|
-
...Array.from(eventHandlers.keys()).map((type) => ({ type })),
|
|
173
|
-
];
|
|
174
|
-
if (allExpectedEvents.length > 0 &&
|
|
175
|
-
!allExpectedEvents.some(({ type }) => type === eventType)) {
|
|
176
|
-
throw new Error(`Unexpected event type: ${eventType}. Expected one of: ${allExpectedEvents
|
|
177
|
-
.map((x) => x.type)
|
|
178
|
-
.join(', ')}`);
|
|
179
|
-
}
|
|
180
|
-
const handlers = eventHandlers.get(eventType) ?? [];
|
|
181
|
-
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, payload, {
|
|
182
|
-
instanceId,
|
|
183
|
-
identity,
|
|
184
|
-
})));
|
|
185
|
-
return {
|
|
186
|
-
instanceId,
|
|
187
|
-
eventType,
|
|
188
|
-
payload,
|
|
189
|
-
identity,
|
|
190
|
-
};
|
|
191
|
-
},
|
|
192
|
-
async processRequest(request, opts) {
|
|
193
|
-
const body = await request.text();
|
|
194
|
-
return this.process(body, opts);
|
|
195
|
-
},
|
|
196
|
-
async parseJWT(jwt) {
|
|
197
|
-
if (!authStrategy.decodeJWT) {
|
|
198
|
-
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
199
|
-
}
|
|
200
|
-
const { decoded, valid } = await authStrategy.decodeJWT(jwt);
|
|
201
|
-
if (!valid) {
|
|
202
|
-
throw new Error('JWT is not valid');
|
|
203
|
-
}
|
|
204
|
-
if (typeof decoded.data !== 'string') {
|
|
205
|
-
throw new Error(`Unexpected type of JWT data: expected string, got ${typeof decoded.data}`);
|
|
206
|
-
}
|
|
207
|
-
const parsedDecoded = JSON.parse(decoded.data);
|
|
208
|
-
const eventType = parsedDecoded.eventType;
|
|
209
|
-
const instanceId = parsedDecoded.instanceId;
|
|
210
|
-
const identity = parsedDecoded.identity
|
|
211
|
-
? JSON.parse(parsedDecoded.identity)
|
|
212
|
-
: undefined;
|
|
213
|
-
const payload = JSON.parse(parsedDecoded.data);
|
|
214
|
-
return {
|
|
215
|
-
instanceId,
|
|
216
|
-
eventType,
|
|
217
|
-
payload,
|
|
218
|
-
identity,
|
|
219
|
-
};
|
|
220
|
-
},
|
|
221
|
-
async parseRequest(request) {
|
|
222
|
-
const jwt = await request.text();
|
|
223
|
-
return this.parseJWT(jwt);
|
|
224
|
-
},
|
|
225
|
-
async executeHandlers(event) {
|
|
226
|
-
const allExpectedEvents = Array.from(eventHandlers.keys()).map((type) => ({ type }));
|
|
227
|
-
if (allExpectedEvents.length > 0 &&
|
|
228
|
-
!allExpectedEvents.some(({ type }) => type === event.eventType)) {
|
|
229
|
-
throw new Error(`Unexpected event type: ${event.eventType}. Expected one of: ${allExpectedEvents
|
|
230
|
-
.map((x) => x.type)
|
|
231
|
-
.join(', ')}`);
|
|
232
|
-
}
|
|
233
|
-
const handlers = eventHandlers.get(event.eventType) ?? [];
|
|
234
|
-
await Promise.all(handlers.map(({ eventDefinition, handler }) => runHandler(eventDefinition, handler, event.payload, {
|
|
235
|
-
instanceId: event.instanceId,
|
|
236
|
-
identity: event.identity,
|
|
237
|
-
})));
|
|
238
|
-
},
|
|
239
|
-
apps: {
|
|
240
|
-
AppInstalled: EventDefinition('AppInstalled')(),
|
|
241
|
-
AppRemoved: EventDefinition('AppRemoved')(),
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
servicePlugins: {
|
|
245
|
-
getRegisteredServicePlugins: () => servicePluginsImplementations,
|
|
246
|
-
async process(request) {
|
|
247
|
-
const servicePluginRequest = await this.parseJWT(request.body);
|
|
248
|
-
return this.executeHandler(servicePluginRequest, request.url);
|
|
249
|
-
},
|
|
250
|
-
async processRequest(request) {
|
|
251
|
-
const url = request.url;
|
|
252
|
-
const body = await request.text();
|
|
253
|
-
const implMethodResult = await this.process({ url, body });
|
|
254
|
-
return Response.json(implMethodResult);
|
|
255
|
-
},
|
|
256
|
-
async parseJWT(jwt) {
|
|
257
|
-
if (!authStrategy.decodeJWT) {
|
|
258
|
-
throw new Error('decodeJWT is not supported by the authentication strategy');
|
|
259
|
-
}
|
|
260
|
-
const { decoded, valid } = await authStrategy.decodeJWT(jwt, true);
|
|
261
|
-
if (!valid) {
|
|
262
|
-
throw new Error('JWT is not valid');
|
|
263
|
-
}
|
|
264
|
-
if (typeof decoded.data !== 'object' ||
|
|
265
|
-
decoded.data === null ||
|
|
266
|
-
!('metadata' in decoded.data) ||
|
|
267
|
-
typeof decoded.data.metadata !== 'object' ||
|
|
268
|
-
decoded.data.metadata === null ||
|
|
269
|
-
!('appExtensionType' in decoded.data.metadata) ||
|
|
270
|
-
typeof decoded.data.metadata.appExtensionType !== 'string') {
|
|
271
|
-
throw new Error('Unexpected JWT data: expected object with metadata.appExtensionType string');
|
|
272
|
-
}
|
|
273
|
-
return decoded.data;
|
|
274
|
-
},
|
|
275
|
-
async executeHandler(servicePluginRequest, url) {
|
|
276
|
-
const componentType = servicePluginRequest.metadata.appExtensionType.toLowerCase();
|
|
277
|
-
const implementations = servicePluginsImplementations.get(componentType) ?? [];
|
|
278
|
-
if (implementations.length === 0) {
|
|
279
|
-
throw new Error(`No service plugin implementations found for component type ${componentType}`);
|
|
280
|
-
}
|
|
281
|
-
else if (implementations.length > 1) {
|
|
282
|
-
throw new Error(`Multiple service plugin implementations found for component type ${componentType}. This is currently not supported`);
|
|
283
|
-
}
|
|
284
|
-
const { implementation: impl, servicePluginDefinition } = implementations[0];
|
|
285
|
-
const method = servicePluginDefinition.methods.find((m) => url.endsWith(m.primaryHttpMappingPath));
|
|
286
|
-
if (!method) {
|
|
287
|
-
throw new Error('Unexpect request: request url did not match any method: ' + url);
|
|
288
|
-
}
|
|
289
|
-
const implMethod = impl[method.name];
|
|
290
|
-
if (!implMethod) {
|
|
291
|
-
throw new Error(`Got request for service plugin method ${method.name} but no implementation was provided. Available methods: ${Object.keys(impl).join(', ')}`);
|
|
292
|
-
}
|
|
293
|
-
return method.transformations.toREST(await implMethod(method.transformations.fromREST(servicePluginRequest)));
|
|
294
|
-
},
|
|
295
|
-
},
|
|
156
|
+
webhooks: eventHandlersClient,
|
|
157
|
+
servicePlugins: servicePluginsClient,
|
|
296
158
|
};
|
|
297
159
|
}
|
package/cjs/build/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function elevate<T extends RESTFunctionDescriptor
|
|
1
|
+
import { RESTFunctionDescriptor } from '@wix/sdk-types';
|
|
2
|
+
export declare function elevate<T extends RESTFunctionDescriptor>(restModule: T): T;
|
|
3
3
|
export declare const fetchWithAuth: typeof fetch & ((restModuleOpts: import("@wix/sdk-types").HttpClient) => typeof fetch);
|
|
4
4
|
export { graphql } from './graphql.js';
|
|
5
5
|
export { setGlobalWixContext } from './wix-context.js';
|