@eventusgo/sdk 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,82 @@
1
+ type EventusTheme = "light" | "dark";
2
+ type EventusUser = {
3
+ id: string;
4
+ name?: string;
5
+ displayName?: string;
6
+ avatarUrl?: string;
7
+ handle?: string;
8
+ };
9
+ type EventusContext = {
10
+ appId?: string;
11
+ locale: string;
12
+ theme: EventusTheme;
13
+ user?: EventusUser;
14
+ };
15
+ type EventusPermission = "user.profile.read" | "theme.read" | "storage.local";
16
+ type EventusManifest = {
17
+ name: string;
18
+ appId: string;
19
+ version: string;
20
+ permissions?: Array<EventusPermission | string>;
21
+ };
22
+ type EventusRuntimeSource = "native" | "mock";
23
+ type EventusEventMap = {
24
+ ready: {
25
+ context: EventusContext;
26
+ source: EventusRuntimeSource;
27
+ };
28
+ themeChange: {
29
+ theme: EventusTheme;
30
+ context: EventusContext;
31
+ source: EventusRuntimeSource;
32
+ };
33
+ };
34
+ type EventusEventName = keyof EventusEventMap;
35
+ type EventusEventHandler<K extends EventusEventName> = (payload: EventusEventMap[K]) => void;
36
+ type EventusClient = {
37
+ ready(): Promise<void>;
38
+ getContext(): Promise<EventusContext>;
39
+ getManifest(): EventusManifest | null;
40
+ request<T = unknown>(action: string, payload?: unknown): Promise<T>;
41
+ on<K extends EventusEventName>(event: K, handler: EventusEventHandler<K>): () => void;
42
+ };
43
+ type ConfigureMockEventusOptions = {
44
+ context?: Partial<EventusContext>;
45
+ manifest?: EventusManifest | null;
46
+ ready?: boolean;
47
+ reset?: boolean;
48
+ };
49
+ type NativeBridgeUser = Record<string, unknown>;
50
+ type NativeBridgeRecord = Record<string, unknown>;
51
+ type NativeEventusBridge = {
52
+ version?: string;
53
+ user?: NativeBridgeUser | null;
54
+ app?: NativeBridgeRecord;
55
+ device?: NativeBridgeRecord;
56
+ capabilities?: Record<string, boolean>;
57
+ request?<T = unknown>(action: string, payload?: unknown): Promise<T>;
58
+ } & Record<string, unknown>;
59
+ declare global {
60
+ interface Window {
61
+ Eventus?: NativeEventusBridge;
62
+ }
63
+ }
64
+ declare class EventusClientImpl implements EventusClient {
65
+ private emitter;
66
+ private lastReadySource;
67
+ private hasReadyRequest;
68
+ constructor();
69
+ ready(): Promise<void>;
70
+ getContext(): Promise<EventusContext>;
71
+ getManifest(): EventusManifest | null;
72
+ request<T = unknown>(action: string, payload?: unknown): Promise<T>;
73
+ on<K extends EventusEventName>(event: K, handler: EventusEventHandler<K>): () => void;
74
+ configureMock(options?: ConfigureMockEventusOptions): void;
75
+ private emitReady;
76
+ private handleBridgeReady;
77
+ private waitForNativeBridge;
78
+ }
79
+ declare const eventus: EventusClientImpl;
80
+ declare function configureMockEventus(options?: ConfigureMockEventusOptions): void;
81
+
82
+ export { type ConfigureMockEventusOptions, type EventusClient, type EventusContext, type EventusEventHandler, type EventusEventMap, type EventusEventName, type EventusManifest, type EventusPermission, type EventusRuntimeSource, type EventusTheme, type EventusUser, configureMockEventus, eventus };
package/dist/index.js ADDED
@@ -0,0 +1,235 @@
1
+ // src/index.ts
2
+ var EventEmitter = class {
3
+ listeners = /* @__PURE__ */ new Map();
4
+ on(event, handler) {
5
+ const nextListeners = this.listeners.get(event) ?? /* @__PURE__ */ new Set();
6
+ nextListeners.add(handler);
7
+ this.listeners.set(event, nextListeners);
8
+ return () => {
9
+ nextListeners.delete(handler);
10
+ if (nextListeners.size === 0) {
11
+ this.listeners.delete(event);
12
+ }
13
+ };
14
+ }
15
+ emit(event, payload) {
16
+ const handlers = this.listeners.get(event);
17
+ if (!handlers) {
18
+ return;
19
+ }
20
+ for (const handler of handlers) {
21
+ handler(payload);
22
+ }
23
+ }
24
+ };
25
+ function getBrowserLocale() {
26
+ if (typeof navigator !== "undefined" && navigator.language) {
27
+ return navigator.language;
28
+ }
29
+ return "en";
30
+ }
31
+ function createDefaultMockContext() {
32
+ const manifest = readInjectedManifest();
33
+ return {
34
+ locale: getBrowserLocale(),
35
+ theme: "light",
36
+ ...manifest?.appId ? { appId: manifest.appId } : {},
37
+ user: {
38
+ id: "dev-user",
39
+ name: "Eventus Developer"
40
+ }
41
+ };
42
+ }
43
+ function readInjectedManifest() {
44
+ const manifest = globalThis.__EVENTUS_MANIFEST__;
45
+ if (typeof manifest === "undefined") {
46
+ return null;
47
+ }
48
+ return manifest ?? null;
49
+ }
50
+ function readWindowBridge() {
51
+ if (typeof window === "undefined") {
52
+ return void 0;
53
+ }
54
+ return window.Eventus;
55
+ }
56
+ function readStringField(record, key) {
57
+ const value = record?.[key];
58
+ return typeof value === "string" && value.trim() ? value : void 0;
59
+ }
60
+ function mapNativeUser(user) {
61
+ if (!user || typeof user.id !== "string" || !user.id.trim()) {
62
+ return void 0;
63
+ }
64
+ const displayName = typeof user.displayName === "string" ? user.displayName : void 0;
65
+ const name = typeof user.name === "string" ? user.name : displayName;
66
+ const avatarUrl = typeof user.avatarUrl === "string" ? user.avatarUrl : void 0;
67
+ const handle = typeof user.handle === "string" ? user.handle : void 0;
68
+ return {
69
+ id: user.id,
70
+ ...name ? { name } : {},
71
+ ...displayName ? { displayName } : {},
72
+ ...avatarUrl ? { avatarUrl } : {},
73
+ ...handle ? { handle } : {}
74
+ };
75
+ }
76
+ function mapNativeContext(bridge) {
77
+ const appId = readStringField(bridge.app, "slug") ?? readStringField(bridge.app, "id");
78
+ const locale = readStringField(bridge.device, "locale") ?? getBrowserLocale();
79
+ const themeValue = readStringField(bridge.device, "themeMode");
80
+ const theme = themeValue === "dark" ? "dark" : "light";
81
+ const user = mapNativeUser(bridge.user);
82
+ return {
83
+ locale,
84
+ theme,
85
+ ...appId ? { appId } : {},
86
+ ...user ? { user } : {}
87
+ };
88
+ }
89
+ var mockState = {
90
+ context: createDefaultMockContext(),
91
+ manifestOverride: void 0,
92
+ ready: false
93
+ };
94
+ var EventusClientImpl = class {
95
+ emitter = new EventEmitter();
96
+ lastReadySource;
97
+ hasReadyRequest = false;
98
+ constructor() {
99
+ if (typeof window !== "undefined") {
100
+ window.addEventListener("eventus:ready", this.handleBridgeReady);
101
+ }
102
+ }
103
+ async ready() {
104
+ this.hasReadyRequest = true;
105
+ const bridge = await this.waitForNativeBridge();
106
+ if (bridge) {
107
+ this.emitReady(mapNativeContext(bridge), "native");
108
+ return;
109
+ }
110
+ mockState.ready = true;
111
+ this.emitReady(mockState.context, "mock");
112
+ }
113
+ async getContext() {
114
+ const bridge = readWindowBridge();
115
+ if (bridge) {
116
+ return mapNativeContext(bridge);
117
+ }
118
+ return mockState.context;
119
+ }
120
+ getManifest() {
121
+ const bridge = readWindowBridge();
122
+ if (bridge) {
123
+ return readInjectedManifest();
124
+ }
125
+ return mockState.manifestOverride === void 0 ? readInjectedManifest() : mockState.manifestOverride;
126
+ }
127
+ async request(action, payload) {
128
+ const bridge = readWindowBridge();
129
+ if (bridge) {
130
+ if (typeof bridge.request === "function") {
131
+ return bridge.request(action, payload);
132
+ }
133
+ const bridgeAction = bridge[action];
134
+ if (typeof bridgeAction === "function") {
135
+ return bridgeAction(payload);
136
+ }
137
+ }
138
+ const mockedResponse = {
139
+ mock: true,
140
+ action,
141
+ payload: payload ?? null,
142
+ message: "Eventus request used the browser mock fallback because no native bridge is connected."
143
+ };
144
+ return mockedResponse;
145
+ }
146
+ on(event, handler) {
147
+ return this.emitter.on(event, handler);
148
+ }
149
+ configureMock(options = {}) {
150
+ const previousTheme = mockState.context.theme;
151
+ if (options.reset) {
152
+ mockState.context = createDefaultMockContext();
153
+ mockState.manifestOverride = void 0;
154
+ mockState.ready = false;
155
+ this.lastReadySource = void 0;
156
+ this.hasReadyRequest = false;
157
+ }
158
+ if (options.context) {
159
+ const nextUser = options.context.user ? {
160
+ ...mockState.context.user ?? {},
161
+ ...options.context.user
162
+ } : mockState.context.user;
163
+ mockState.context = {
164
+ ...mockState.context,
165
+ ...options.context,
166
+ ...nextUser ? { user: nextUser } : {}
167
+ };
168
+ }
169
+ if ("manifest" in options) {
170
+ mockState.manifestOverride = options.manifest;
171
+ }
172
+ if (typeof options.ready === "boolean") {
173
+ mockState.ready = options.ready;
174
+ if (!options.ready) {
175
+ this.lastReadySource = void 0;
176
+ }
177
+ }
178
+ if (mockState.context.theme !== previousTheme) {
179
+ this.emitter.emit("themeChange", {
180
+ theme: mockState.context.theme,
181
+ context: mockState.context,
182
+ source: "mock"
183
+ });
184
+ }
185
+ }
186
+ emitReady(context, source) {
187
+ if (this.lastReadySource === source) {
188
+ return;
189
+ }
190
+ this.lastReadySource = source;
191
+ this.emitter.emit("ready", {
192
+ context,
193
+ source
194
+ });
195
+ }
196
+ handleBridgeReady = () => {
197
+ if (!this.hasReadyRequest && this.lastReadySource !== "mock") {
198
+ return;
199
+ }
200
+ const bridge = readWindowBridge();
201
+ if (!bridge) {
202
+ return;
203
+ }
204
+ this.emitReady(mapNativeContext(bridge), "native");
205
+ };
206
+ async waitForNativeBridge() {
207
+ const bridge = readWindowBridge();
208
+ if (bridge || typeof window === "undefined") {
209
+ return bridge;
210
+ }
211
+ return new Promise((resolve) => {
212
+ const timeout = window.setTimeout(() => {
213
+ cleanup();
214
+ resolve(readWindowBridge());
215
+ }, 120);
216
+ const onReady = () => {
217
+ cleanup();
218
+ resolve(readWindowBridge());
219
+ };
220
+ const cleanup = () => {
221
+ window.clearTimeout(timeout);
222
+ window.removeEventListener("eventus:ready", onReady);
223
+ };
224
+ window.addEventListener("eventus:ready", onReady, { once: true });
225
+ });
226
+ }
227
+ };
228
+ var eventus = new EventusClientImpl();
229
+ function configureMockEventus(options = {}) {
230
+ eventus.configureMock(options);
231
+ }
232
+ export {
233
+ configureMockEventus,
234
+ eventus
235
+ };
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@eventusgo/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Eventus mini-app SDK with a browser-friendly mock fallback.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup src/index.ts --format esm --dts --clean",
23
+ "check": "tsc -p tsconfig.json --noEmit",
24
+ "test": "vitest run"
25
+ }
26
+ }