@wix/realtime 0.1.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.
@@ -0,0 +1 @@
1
+ export * as site from './site/index.js';
package/build/index.js ADDED
@@ -0,0 +1 @@
1
+ export * as site from './site/index.js';
@@ -0,0 +1,5 @@
1
+ import { PermissionsRouter } from './permissions-router.js';
2
+ import type { Publisher } from './types.js';
3
+ declare const permissionsRouter: PermissionsRouter;
4
+ declare const publish: Publisher;
5
+ export { permissionsRouter, publish };
@@ -0,0 +1,10 @@
1
+ import { createRESTModule } from '@wix/sdk-runtime/rest-modules';
2
+ import { createPublisher } from './publisher.js';
3
+ import { PermissionsRouter } from './permissions-router.js';
4
+ const permissionsRouter = new PermissionsRouter();
5
+ const publish = createRESTModule((httpClient) => createPublisher({
6
+ httpClient,
7
+ apiUrl: process.env.DUPLEXER_API_URL ||
8
+ 'https://manage.wix.com/_api/wix-duplexer-api',
9
+ }), true);
10
+ export { permissionsRouter, publish };
@@ -0,0 +1,9 @@
1
+ import type { Channel, PermissionHandler, Subscriber } from './types.js';
2
+ export declare class PermissionsRouter {
3
+ private readonly routes;
4
+ private defaultHandler;
5
+ constructor();
6
+ add(channel: Channel, permissionHandler: PermissionHandler): void;
7
+ default(permissionHandler: PermissionHandler): void;
8
+ check(channel: Channel, subscriber: Subscriber): Promise<import("./types.js").Permissions>;
9
+ }
@@ -0,0 +1,36 @@
1
+ export class PermissionsRouter {
2
+ routes;
3
+ defaultHandler;
4
+ constructor() {
5
+ this.routes = new Map();
6
+ this.defaultHandler = () => Promise.resolve({
7
+ read: true,
8
+ write: false,
9
+ });
10
+ }
11
+ add(channel, permissionHandler) {
12
+ if (!this.routes.has(channel.name)) {
13
+ this.routes.set(channel.name, new Map());
14
+ }
15
+ const resourceId = typeof channel.resourceId === 'string' ? channel.resourceId : '';
16
+ this.routes.get(channel.name)?.set(resourceId, permissionHandler);
17
+ }
18
+ default(permissionHandler) {
19
+ this.defaultHandler = permissionHandler;
20
+ }
21
+ check(channel, subscriber) {
22
+ if (this.routes.has(channel.name)) {
23
+ const channelNameRoutes = this.routes.get(channel.name);
24
+ if (typeof channel.resourceId === 'string' &&
25
+ channelNameRoutes?.has(channel.resourceId)) {
26
+ const handler = channelNameRoutes.get(channel.resourceId);
27
+ return handler(channel, subscriber);
28
+ }
29
+ if (channelNameRoutes?.has('')) {
30
+ const handler = channelNameRoutes.get('');
31
+ return handler(channel, subscriber);
32
+ }
33
+ }
34
+ return this.defaultHandler(channel, subscriber);
35
+ }
36
+ }
@@ -0,0 +1,6 @@
1
+ import type { HttpClient } from '@wix/sdk-types';
2
+ import type { Publisher } from './types.js';
3
+ export declare function createPublisher({ apiUrl, httpClient, }: {
4
+ apiUrl: string;
5
+ httpClient: HttpClient;
6
+ }): Publisher;
@@ -0,0 +1,51 @@
1
+ import { getCurrentRequest } from './request.js';
2
+ import { transformError } from '@wix/sdk-runtime/transform-error';
3
+ export function createPublisher({ apiUrl, httpClient, }) {
4
+ return async function (channel, payload, { users: recipients, includePublisher } = {}) {
5
+ const isAddRevisionToChannelNameInRealtimeBackendEnabled = await shouldAddRevisionToChannelNameInRealtimeBackend();
6
+ const { userId, visitorId, viewMode, siteRevision } = getCurrentRequest();
7
+ const publisher = includePublisher
8
+ ? { uid: userId || visitorId }
9
+ : undefined;
10
+ let channels;
11
+ if (viewMode?.toLowerCase() !== 'site') {
12
+ channels = [`@preview-${channel.name}`];
13
+ }
14
+ else if (isAddRevisionToChannelNameInRealtimeBackendEnabled) {
15
+ channels = [`${siteRevision}-${channel.name}`];
16
+ }
17
+ else {
18
+ channels = [channel.name];
19
+ }
20
+ try {
21
+ await httpClient.fetchWithAuth(`${apiUrl}/v3/publish`, {
22
+ method: 'POST',
23
+ headers: {
24
+ 'Content-Type': 'application/json',
25
+ },
26
+ body: JSON.stringify({
27
+ channels,
28
+ resourceId: channel.resourceId,
29
+ event: 'message',
30
+ payload: { payload },
31
+ publisher,
32
+ recipients,
33
+ }),
34
+ });
35
+ }
36
+ catch (err) {
37
+ const transformedError = transformError(err);
38
+ throw transformedError;
39
+ }
40
+ };
41
+ }
42
+ const shouldAddRevisionToChannelNameInRealtimeBackend = async () => {
43
+ // const currentRequest = getCurrentRequest();
44
+ // const petriClient = getPetriClient({ url: currentRequest.petriUrl });
45
+ // const result = await petriClient.conductExperiment(
46
+ // 'specs.core-services.AddRevisionToChannelNameInRealtime',
47
+ // 'false',
48
+ // );
49
+ // return result.toString() === 'true';
50
+ return false;
51
+ };
@@ -0,0 +1,8 @@
1
+ import { ViewMode } from './types.js';
2
+ export declare function getCurrentRequest(): {
3
+ serverIdentity?: string;
4
+ userId?: string;
5
+ visitorId?: string;
6
+ viewMode?: ViewMode;
7
+ siteRevision?: string;
8
+ };
@@ -0,0 +1,18 @@
1
+ export function getCurrentRequest() {
2
+ const maybeRequest = extractRequestFromContext();
3
+ const headers = maybeRequest?.headers ?? {};
4
+ return {
5
+ serverIdentity: headers['x-wix-server-identity'],
6
+ userId: headers['x-wix-user-id'],
7
+ visitorId: headers['x-wix-aid'],
8
+ viewMode: headers['x-wix-view-mode'],
9
+ siteRevision: headers['x-wix-site-revision'],
10
+ };
11
+ }
12
+ function extractRequestFromContext() {
13
+ if (global.__requestContext?.getStore()) {
14
+ return global.__requestContext?.getStore()?.request;
15
+ }
16
+ // @ts-expect-error domain is a custom property
17
+ return process.domain?.webMethodInfo?.request;
18
+ }
@@ -0,0 +1,36 @@
1
+ import type { Request as ExpressRequest } from 'express';
2
+ import type { AsyncLocalStorage } from 'node:async_hooks';
3
+ export type Request = ExpressRequest;
4
+ declare global {
5
+ var __requestContext: AsyncLocalStorage<{
6
+ request: Request;
7
+ }> | undefined;
8
+ }
9
+ export declare enum ViewMode {
10
+ Preview = "Preview",
11
+ Public = "Site"
12
+ }
13
+ export interface Channel {
14
+ name: string;
15
+ resourceId?: string;
16
+ }
17
+ export interface PublishOptions {
18
+ includePublisher?: boolean;
19
+ users?: string[];
20
+ }
21
+ export type Publisher = (channel: Channel, payload: unknown, options?: PublishOptions) => Promise<unknown>;
22
+ export declare const enum SubscriberType {
23
+ USER = "USER",
24
+ SITEMEMBER = "MEMBER",
25
+ VISITOR = "VISITOR"
26
+ }
27
+ export interface Subscriber {
28
+ id: string;
29
+ type: SubscriberType;
30
+ }
31
+ export interface Permissions {
32
+ read: boolean;
33
+ write: boolean;
34
+ }
35
+ export type PermissionHandler = (channel: Channel, subscriber: Subscriber) => Promise<Permissions>;
36
+ export type Routes = Map<string, Map<string, PermissionHandler>>;
@@ -0,0 +1,5 @@
1
+ export var ViewMode;
2
+ (function (ViewMode) {
3
+ ViewMode["Preview"] = "Preview";
4
+ ViewMode["Public"] = "Site";
5
+ })(ViewMode || (ViewMode = {}));
@@ -0,0 +1 @@
1
+ export * as site from './site/index.js';
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.site = void 0;
37
+ exports.site = __importStar(require("./site/index.js"));
@@ -0,0 +1,5 @@
1
+ import { PermissionsRouter } from './permissions-router.js';
2
+ import type { Publisher } from './types.js';
3
+ declare const permissionsRouter: PermissionsRouter;
4
+ declare const publish: Publisher;
5
+ export { permissionsRouter, publish };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.publish = exports.permissionsRouter = void 0;
4
+ const rest_modules_1 = require("@wix/sdk-runtime/rest-modules");
5
+ const publisher_js_1 = require("./publisher.js");
6
+ const permissions_router_js_1 = require("./permissions-router.js");
7
+ const permissionsRouter = new permissions_router_js_1.PermissionsRouter();
8
+ exports.permissionsRouter = permissionsRouter;
9
+ const publish = (0, rest_modules_1.createRESTModule)((httpClient) => (0, publisher_js_1.createPublisher)({
10
+ httpClient,
11
+ apiUrl: process.env.DUPLEXER_API_URL ||
12
+ 'https://manage.wix.com/_api/wix-duplexer-api',
13
+ }), true);
14
+ exports.publish = publish;
@@ -0,0 +1,9 @@
1
+ import type { Channel, PermissionHandler, Subscriber } from './types.js';
2
+ export declare class PermissionsRouter {
3
+ private readonly routes;
4
+ private defaultHandler;
5
+ constructor();
6
+ add(channel: Channel, permissionHandler: PermissionHandler): void;
7
+ default(permissionHandler: PermissionHandler): void;
8
+ check(channel: Channel, subscriber: Subscriber): Promise<import("./types.js").Permissions>;
9
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PermissionsRouter = void 0;
4
+ class PermissionsRouter {
5
+ routes;
6
+ defaultHandler;
7
+ constructor() {
8
+ this.routes = new Map();
9
+ this.defaultHandler = () => Promise.resolve({
10
+ read: true,
11
+ write: false,
12
+ });
13
+ }
14
+ add(channel, permissionHandler) {
15
+ if (!this.routes.has(channel.name)) {
16
+ this.routes.set(channel.name, new Map());
17
+ }
18
+ const resourceId = typeof channel.resourceId === 'string' ? channel.resourceId : '';
19
+ this.routes.get(channel.name)?.set(resourceId, permissionHandler);
20
+ }
21
+ default(permissionHandler) {
22
+ this.defaultHandler = permissionHandler;
23
+ }
24
+ check(channel, subscriber) {
25
+ if (this.routes.has(channel.name)) {
26
+ const channelNameRoutes = this.routes.get(channel.name);
27
+ if (typeof channel.resourceId === 'string' &&
28
+ channelNameRoutes?.has(channel.resourceId)) {
29
+ const handler = channelNameRoutes.get(channel.resourceId);
30
+ return handler(channel, subscriber);
31
+ }
32
+ if (channelNameRoutes?.has('')) {
33
+ const handler = channelNameRoutes.get('');
34
+ return handler(channel, subscriber);
35
+ }
36
+ }
37
+ return this.defaultHandler(channel, subscriber);
38
+ }
39
+ }
40
+ exports.PermissionsRouter = PermissionsRouter;
@@ -0,0 +1,6 @@
1
+ import type { HttpClient } from '@wix/sdk-types';
2
+ import type { Publisher } from './types.js';
3
+ export declare function createPublisher({ apiUrl, httpClient, }: {
4
+ apiUrl: string;
5
+ httpClient: HttpClient;
6
+ }): Publisher;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPublisher = createPublisher;
4
+ const request_js_1 = require("./request.js");
5
+ const transform_error_1 = require("@wix/sdk-runtime/transform-error");
6
+ function createPublisher({ apiUrl, httpClient, }) {
7
+ return async function (channel, payload, { users: recipients, includePublisher } = {}) {
8
+ const isAddRevisionToChannelNameInRealtimeBackendEnabled = await shouldAddRevisionToChannelNameInRealtimeBackend();
9
+ const { userId, visitorId, viewMode, siteRevision } = (0, request_js_1.getCurrentRequest)();
10
+ const publisher = includePublisher
11
+ ? { uid: userId || visitorId }
12
+ : undefined;
13
+ let channels;
14
+ if (viewMode?.toLowerCase() !== 'site') {
15
+ channels = [`@preview-${channel.name}`];
16
+ }
17
+ else if (isAddRevisionToChannelNameInRealtimeBackendEnabled) {
18
+ channels = [`${siteRevision}-${channel.name}`];
19
+ }
20
+ else {
21
+ channels = [channel.name];
22
+ }
23
+ try {
24
+ await httpClient.fetchWithAuth(`${apiUrl}/v3/publish`, {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ },
29
+ body: JSON.stringify({
30
+ channels,
31
+ resourceId: channel.resourceId,
32
+ event: 'message',
33
+ payload: { payload },
34
+ publisher,
35
+ recipients,
36
+ }),
37
+ });
38
+ }
39
+ catch (err) {
40
+ const transformedError = (0, transform_error_1.transformError)(err);
41
+ throw transformedError;
42
+ }
43
+ };
44
+ }
45
+ const shouldAddRevisionToChannelNameInRealtimeBackend = async () => {
46
+ // const currentRequest = getCurrentRequest();
47
+ // const petriClient = getPetriClient({ url: currentRequest.petriUrl });
48
+ // const result = await petriClient.conductExperiment(
49
+ // 'specs.core-services.AddRevisionToChannelNameInRealtime',
50
+ // 'false',
51
+ // );
52
+ // return result.toString() === 'true';
53
+ return false;
54
+ };
@@ -0,0 +1,8 @@
1
+ import { ViewMode } from './types.js';
2
+ export declare function getCurrentRequest(): {
3
+ serverIdentity?: string;
4
+ userId?: string;
5
+ visitorId?: string;
6
+ viewMode?: ViewMode;
7
+ siteRevision?: string;
8
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCurrentRequest = getCurrentRequest;
4
+ function getCurrentRequest() {
5
+ const maybeRequest = extractRequestFromContext();
6
+ const headers = maybeRequest?.headers ?? {};
7
+ return {
8
+ serverIdentity: headers['x-wix-server-identity'],
9
+ userId: headers['x-wix-user-id'],
10
+ visitorId: headers['x-wix-aid'],
11
+ viewMode: headers['x-wix-view-mode'],
12
+ siteRevision: headers['x-wix-site-revision'],
13
+ };
14
+ }
15
+ function extractRequestFromContext() {
16
+ if (global.__requestContext?.getStore()) {
17
+ return global.__requestContext?.getStore()?.request;
18
+ }
19
+ // @ts-expect-error domain is a custom property
20
+ return process.domain?.webMethodInfo?.request;
21
+ }
@@ -0,0 +1,36 @@
1
+ import type { Request as ExpressRequest } from 'express';
2
+ import type { AsyncLocalStorage } from 'node:async_hooks';
3
+ export type Request = ExpressRequest;
4
+ declare global {
5
+ var __requestContext: AsyncLocalStorage<{
6
+ request: Request;
7
+ }> | undefined;
8
+ }
9
+ export declare enum ViewMode {
10
+ Preview = "Preview",
11
+ Public = "Site"
12
+ }
13
+ export interface Channel {
14
+ name: string;
15
+ resourceId?: string;
16
+ }
17
+ export interface PublishOptions {
18
+ includePublisher?: boolean;
19
+ users?: string[];
20
+ }
21
+ export type Publisher = (channel: Channel, payload: unknown, options?: PublishOptions) => Promise<unknown>;
22
+ export declare const enum SubscriberType {
23
+ USER = "USER",
24
+ SITEMEMBER = "MEMBER",
25
+ VISITOR = "VISITOR"
26
+ }
27
+ export interface Subscriber {
28
+ id: string;
29
+ type: SubscriberType;
30
+ }
31
+ export interface Permissions {
32
+ read: boolean;
33
+ write: boolean;
34
+ }
35
+ export type PermissionHandler = (channel: Channel, subscriber: Subscriber) => Promise<Permissions>;
36
+ export type Routes = Map<string, Map<string, PermissionHandler>>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ViewMode = void 0;
4
+ var ViewMode;
5
+ (function (ViewMode) {
6
+ ViewMode["Preview"] = "Preview";
7
+ ViewMode["Public"] = "Site";
8
+ })(ViewMode || (exports.ViewMode = ViewMode = {}));
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1 @@
1
+ {"root":["../src/index.ts","../src/site/index.ts","../src/site/permissions-router.ts","../src/site/publisher.ts","../src/site/request.ts","../src/site/types.ts"],"version":"5.7.3"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@wix/realtime",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "main": "cjs/build/index.js",
6
+ "module": "build/index.mjs",
7
+ "type": "module",
8
+ "files": [
9
+ "build",
10
+ "cjs"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc -b tsconfig.json tsconfig.cjs.json && yarn docs",
14
+ "docs": "docs-ts-model --entryPoint src/index.ts --outDir ./docs --modelName docs-ts-model.json",
15
+ "test": "tsx --test test/*.spec.ts",
16
+ "lint": "eslint",
17
+ "lint:fix": "eslint --max-warnings=0 . --fix",
18
+ "typecheck": "tsc --noEmit"
19
+ },
20
+ "dependencies": {
21
+ "@wix/sdk-runtime": "^0.3.35"
22
+ },
23
+ "optionalDependencies": {
24
+ "@wix/docs-ts-model": "^1.30.0"
25
+ },
26
+ "devDependencies": {
27
+ "@eslint/js": "^9.4.0",
28
+ "@types/chance": "^1",
29
+ "@types/express": "^5.0.0",
30
+ "@types/node": "^20.14.2",
31
+ "@wix/sdk": "^1.10.0",
32
+ "@wix/sdk-types": "^1.8.0",
33
+ "chance": "^1.1.11",
34
+ "eslint": "9.x",
35
+ "eslint-plugin-prettier": "^5.1.3",
36
+ "fetch-mock": "^9.11.0",
37
+ "globals": "^15.4.0",
38
+ "node-fetch": "^3.3.2",
39
+ "prettier": "^3.3.1",
40
+ "tsx": "^4.15.1",
41
+ "typescript": "^5.7.3",
42
+ "typescript-eslint": "^8.24.1"
43
+ },
44
+ "publishConfig": {
45
+ "registry": "https://registry.npmjs.org/",
46
+ "access": "public"
47
+ },
48
+ "wix": {
49
+ "artifact": {
50
+ "groupId": "com.wixpress.sdk",
51
+ "artifactId": "realtime"
52
+ },
53
+ "validations": {
54
+ "source": [
55
+ "lint"
56
+ ],
57
+ "postDependenciesBuild": [
58
+ "typecheck"
59
+ ]
60
+ }
61
+ },
62
+ "falconPackageHash": "fe736bc3e3d36aa9b5e1637e2251fd15e16f94739adf2bc816ca55e9"
63
+ }