@connect-plus-online/ogabai-integrations 0.1.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.
@@ -0,0 +1,98 @@
1
+ type Money = {
2
+ amount: number;
3
+ currency: string;
4
+ };
5
+ type UserRole = "admin" | "agent" | "customer";
6
+ type User = {
7
+ id: string;
8
+ name: string;
9
+ email?: string;
10
+ role: UserRole;
11
+ balance?: Money;
12
+ };
13
+ /** GraphQL-related */
14
+ type GraphQLVariables = Record<string, any> | undefined;
15
+ type GraphQLRequest = {
16
+ query: string;
17
+ variables?: GraphQLVariables;
18
+ operationName?: string;
19
+ };
20
+ type GraphQLError = {
21
+ message: string;
22
+ locations?: {
23
+ line: number;
24
+ column: number;
25
+ }[];
26
+ path?: string[];
27
+ extensions?: Record<string, any>;
28
+ };
29
+ type GraphQLResponse<T = any> = {
30
+ data?: T;
31
+ errors?: GraphQLError[];
32
+ };
33
+
34
+ type AuthTokenProvider = () => Promise<string | null> | string | null;
35
+ type HeadersFactory = () => Promise<Record<string, string>> | Record<string, string>;
36
+ declare const toAsyncTokenProvider: (p?: AuthTokenProvider) => (() => Promise<string | null>);
37
+ declare const toAsyncHeadersFactory: (f?: HeadersFactory) => (() => Promise<Record<string, string>>);
38
+
39
+ declare class SdkError extends Error {
40
+ code?: string;
41
+ info?: any;
42
+ constructor(message: string, code?: string, info?: any);
43
+ }
44
+ declare class NetworkError extends SdkError {
45
+ constructor(message?: string, info?: any);
46
+ }
47
+ declare class AuthenticationError extends SdkError {
48
+ constructor(message?: string, info?: any);
49
+ }
50
+
51
+ interface CacheRequestOptions {
52
+ skipCache?: boolean;
53
+ }
54
+
55
+ type RequestContext = {
56
+ request: GraphQLRequest;
57
+ url: string;
58
+ headers: Record<string, string>;
59
+ meta?: Record<string, any>;
60
+ cacheOptions?: CacheRequestOptions;
61
+ };
62
+ type ResponseContext<T = any> = {
63
+ response?: GraphQLResponse<T> | null;
64
+ error?: Error | null;
65
+ status?: number | null;
66
+ };
67
+ type Next = () => Promise<void>;
68
+ type Middleware = <T = any>(ctx: RequestContext, resCtx: ResponseContext<T>, next: Next) => Promise<void>;
69
+
70
+ type ClientOptions = {
71
+ url: string;
72
+ tokenProvider?: (() => Promise<string | null>) | (() => string | null);
73
+ headersFactory?: (() => Promise<Record<string, string>>) | (() => Record<string, string>);
74
+ fetchImpl?: typeof fetch;
75
+ timeoutMs?: number;
76
+ middlewares?: Middleware[];
77
+ };
78
+ declare class GraphQLClient {
79
+ private url;
80
+ private tokenProvider;
81
+ private headersFactory;
82
+ private middlewares;
83
+ constructor(opts: ClientOptions);
84
+ private authMiddleware;
85
+ request<T = any>(query: string, variables?: Record<string, any>, options?: Partial<Omit<RequestContext, "request" | "url">>): Promise<GraphQLResponse<T>>;
86
+ }
87
+
88
+ declare const createUserService: (client: GraphQLClient) => {
89
+ getUser(id: string): Promise<User | null>;
90
+ };
91
+
92
+ /**
93
+ * Very small mock client that conforms to GraphQLClient.request interface.
94
+ * Use in tests to return canned responses.
95
+ */
96
+ declare const createMockClient: (handler: (req: GraphQLRequest) => Promise<GraphQLResponse>) => GraphQLClient;
97
+
98
+ export { AuthTokenProvider, AuthenticationError, GraphQLClient, GraphQLError, GraphQLRequest, GraphQLResponse, GraphQLVariables, HeadersFactory, Money, NetworkError, SdkError, User, UserRole, createMockClient, createUserService, toAsyncHeadersFactory, toAsyncTokenProvider };
package/dist/index.js ADDED
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ AuthenticationError: () => AuthenticationError,
24
+ GraphQLClient: () => GraphQLClient,
25
+ NetworkError: () => NetworkError,
26
+ SdkError: () => SdkError,
27
+ createMockClient: () => createMockClient,
28
+ createUserService: () => createUserService,
29
+ toAsyncHeadersFactory: () => toAsyncHeadersFactory,
30
+ toAsyncTokenProvider: () => toAsyncTokenProvider
31
+ });
32
+ module.exports = __toCommonJS(src_exports);
33
+
34
+ // src/auth.ts
35
+ var toAsyncTokenProvider = (p) => {
36
+ if (!p)
37
+ return async () => null;
38
+ return async () => {
39
+ try {
40
+ const res = p();
41
+ return res instanceof Promise ? await res : res;
42
+ } catch {
43
+ return null;
44
+ }
45
+ };
46
+ };
47
+ var toAsyncHeadersFactory = (f) => {
48
+ if (!f)
49
+ return async () => ({});
50
+ return async () => {
51
+ try {
52
+ const res = f();
53
+ return (res instanceof Promise ? await res : res) ?? {};
54
+ } catch {
55
+ return {};
56
+ }
57
+ };
58
+ };
59
+
60
+ // src/errors.ts
61
+ var SdkError = class extends Error {
62
+ constructor(message, code, info) {
63
+ super(message);
64
+ this.name = "SdkError";
65
+ this.code = code;
66
+ this.info = info;
67
+ }
68
+ };
69
+ var NetworkError = class extends SdkError {
70
+ constructor(message = "Network error", info) {
71
+ super(message, "NETWORK_ERROR", info);
72
+ }
73
+ };
74
+ var AuthenticationError = class extends SdkError {
75
+ constructor(message = "Authentication failed", info) {
76
+ super(message, "AUTH_ERROR", info);
77
+ }
78
+ };
79
+
80
+ // src/middleware.ts
81
+ var compose = (middlewares) => async (ctx, resCtx) => {
82
+ let idx = -1;
83
+ const dispatch = async (i) => {
84
+ if (i <= idx)
85
+ throw new Error("next() called multiple times");
86
+ idx = i;
87
+ const fn = middlewares[i];
88
+ if (!fn)
89
+ return;
90
+ await fn(ctx, resCtx, () => dispatch(i + 1));
91
+ };
92
+ await dispatch(0);
93
+ };
94
+
95
+ // src/transport.ts
96
+ var createTransport = (opts) => {
97
+ const fetchImpl = opts?.fetchImpl ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0);
98
+ if (!fetchImpl) {
99
+ throw new Error(
100
+ "No fetch implementation available. Provide fetchImpl in TransportOptions or polyfill fetch."
101
+ );
102
+ }
103
+ return async (ctx, resCtx, next) => {
104
+ const body = JSON.stringify({ query: ctx.request.query, variables: ctx.request.variables });
105
+ try {
106
+ const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
107
+ const signal = controller?.signal;
108
+ let timer;
109
+ if (controller && opts?.timeoutMs)
110
+ timer = setTimeout(() => controller.abort(), opts.timeoutMs);
111
+ const r = await fetchImpl(ctx.url, {
112
+ method: "POST",
113
+ headers: ctx.headers,
114
+ body,
115
+ signal
116
+ });
117
+ if (timer)
118
+ clearTimeout(timer);
119
+ const text = await r.text();
120
+ let parsed;
121
+ try {
122
+ parsed = JSON.parse(text);
123
+ } catch {
124
+ resCtx.error = new Error("Invalid JSON response");
125
+ resCtx.status = r.status;
126
+ return;
127
+ }
128
+ resCtx.response = parsed;
129
+ resCtx.status = r.status;
130
+ } catch (err) {
131
+ if (err.name === "AbortError")
132
+ resCtx.error = new Error("Request timed out");
133
+ else
134
+ resCtx.error = err;
135
+ }
136
+ await next();
137
+ };
138
+ };
139
+
140
+ // src/client.ts
141
+ var GraphQLClient = class {
142
+ constructor(opts) {
143
+ this.url = opts.url;
144
+ this.tokenProvider = toAsyncTokenProvider(opts.tokenProvider);
145
+ this.headersFactory = toAsyncHeadersFactory(opts.headersFactory);
146
+ const base = [this.authMiddleware.bind(this)];
147
+ if (opts.middlewares)
148
+ base.push(...opts.middlewares);
149
+ base.push(createTransport({ fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs }));
150
+ this.middlewares = base;
151
+ }
152
+ async authMiddleware(ctx, resCtx, next) {
153
+ const token = await this.tokenProvider();
154
+ const dynamicHeaders = await this.headersFactory();
155
+ ctx.headers = {
156
+ "Content-Type": "application/json",
157
+ Accept: "application/json",
158
+ ...dynamicHeaders,
159
+ ...token ? { Authorization: `Bearer ${token}` } : {},
160
+ ...ctx.headers ?? {}
161
+ };
162
+ await next();
163
+ }
164
+ // core request
165
+ async request(query, variables, options) {
166
+ const ctx = {
167
+ request: { query, variables },
168
+ url: this.url,
169
+ headers: options?.headers ?? {},
170
+ cacheOptions: options?.cacheOptions
171
+ };
172
+ const resCtx = {};
173
+ const runner = compose(this.middlewares);
174
+ await runner(ctx, resCtx);
175
+ if (resCtx.error)
176
+ throw resCtx.error;
177
+ if (!resCtx.response)
178
+ throw new Error("No response from GraphQL transport");
179
+ if (resCtx.response.errors && resCtx.response.errors.length) {
180
+ const e = resCtx.response.errors[0];
181
+ const err = new Error(e.message);
182
+ err.extensions = e.extensions;
183
+ throw err;
184
+ }
185
+ return resCtx.response;
186
+ }
187
+ };
188
+
189
+ // src/services/user.service.ts
190
+ var GET_USER = `
191
+ query GetUser($id: ID!) {
192
+ user(id: $id) {
193
+ id
194
+ name
195
+ email
196
+ role
197
+ balance { amount currency }
198
+ }
199
+ }
200
+ `;
201
+ var createUserService = (client) => ({
202
+ async getUser(id) {
203
+ const res = await client.request(GET_USER, { id }, { cacheOptions: { skipCache: true } });
204
+ return res.data?.user ?? null;
205
+ }
206
+ });
207
+
208
+ // src/testing/mockClient.ts
209
+ var createMockClient = (handler) => {
210
+ return {
211
+ request: async (query, variables) => {
212
+ return await handler({ query, variables });
213
+ }
214
+ };
215
+ };
216
+ // Annotate the CommonJS export names for ESM import in node:
217
+ 0 && (module.exports = {
218
+ AuthenticationError,
219
+ GraphQLClient,
220
+ NetworkError,
221
+ SdkError,
222
+ createMockClient,
223
+ createUserService,
224
+ toAsyncHeadersFactory,
225
+ toAsyncTokenProvider
226
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,192 @@
1
+ // src/auth.ts
2
+ var toAsyncTokenProvider = (p) => {
3
+ if (!p)
4
+ return async () => null;
5
+ return async () => {
6
+ try {
7
+ const res = p();
8
+ return res instanceof Promise ? await res : res;
9
+ } catch {
10
+ return null;
11
+ }
12
+ };
13
+ };
14
+ var toAsyncHeadersFactory = (f) => {
15
+ if (!f)
16
+ return async () => ({});
17
+ return async () => {
18
+ try {
19
+ const res = f();
20
+ return (res instanceof Promise ? await res : res) ?? {};
21
+ } catch {
22
+ return {};
23
+ }
24
+ };
25
+ };
26
+
27
+ // src/errors.ts
28
+ var SdkError = class extends Error {
29
+ constructor(message, code, info) {
30
+ super(message);
31
+ this.name = "SdkError";
32
+ this.code = code;
33
+ this.info = info;
34
+ }
35
+ };
36
+ var NetworkError = class extends SdkError {
37
+ constructor(message = "Network error", info) {
38
+ super(message, "NETWORK_ERROR", info);
39
+ }
40
+ };
41
+ var AuthenticationError = class extends SdkError {
42
+ constructor(message = "Authentication failed", info) {
43
+ super(message, "AUTH_ERROR", info);
44
+ }
45
+ };
46
+
47
+ // src/middleware.ts
48
+ var compose = (middlewares) => async (ctx, resCtx) => {
49
+ let idx = -1;
50
+ const dispatch = async (i) => {
51
+ if (i <= idx)
52
+ throw new Error("next() called multiple times");
53
+ idx = i;
54
+ const fn = middlewares[i];
55
+ if (!fn)
56
+ return;
57
+ await fn(ctx, resCtx, () => dispatch(i + 1));
58
+ };
59
+ await dispatch(0);
60
+ };
61
+
62
+ // src/transport.ts
63
+ var createTransport = (opts) => {
64
+ const fetchImpl = opts?.fetchImpl ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0);
65
+ if (!fetchImpl) {
66
+ throw new Error(
67
+ "No fetch implementation available. Provide fetchImpl in TransportOptions or polyfill fetch."
68
+ );
69
+ }
70
+ return async (ctx, resCtx, next) => {
71
+ const body = JSON.stringify({ query: ctx.request.query, variables: ctx.request.variables });
72
+ try {
73
+ const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
74
+ const signal = controller?.signal;
75
+ let timer;
76
+ if (controller && opts?.timeoutMs)
77
+ timer = setTimeout(() => controller.abort(), opts.timeoutMs);
78
+ const r = await fetchImpl(ctx.url, {
79
+ method: "POST",
80
+ headers: ctx.headers,
81
+ body,
82
+ signal
83
+ });
84
+ if (timer)
85
+ clearTimeout(timer);
86
+ const text = await r.text();
87
+ let parsed;
88
+ try {
89
+ parsed = JSON.parse(text);
90
+ } catch {
91
+ resCtx.error = new Error("Invalid JSON response");
92
+ resCtx.status = r.status;
93
+ return;
94
+ }
95
+ resCtx.response = parsed;
96
+ resCtx.status = r.status;
97
+ } catch (err) {
98
+ if (err.name === "AbortError")
99
+ resCtx.error = new Error("Request timed out");
100
+ else
101
+ resCtx.error = err;
102
+ }
103
+ await next();
104
+ };
105
+ };
106
+
107
+ // src/client.ts
108
+ var GraphQLClient = class {
109
+ constructor(opts) {
110
+ this.url = opts.url;
111
+ this.tokenProvider = toAsyncTokenProvider(opts.tokenProvider);
112
+ this.headersFactory = toAsyncHeadersFactory(opts.headersFactory);
113
+ const base = [this.authMiddleware.bind(this)];
114
+ if (opts.middlewares)
115
+ base.push(...opts.middlewares);
116
+ base.push(createTransport({ fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs }));
117
+ this.middlewares = base;
118
+ }
119
+ async authMiddleware(ctx, resCtx, next) {
120
+ const token = await this.tokenProvider();
121
+ const dynamicHeaders = await this.headersFactory();
122
+ ctx.headers = {
123
+ "Content-Type": "application/json",
124
+ Accept: "application/json",
125
+ ...dynamicHeaders,
126
+ ...token ? { Authorization: `Bearer ${token}` } : {},
127
+ ...ctx.headers ?? {}
128
+ };
129
+ await next();
130
+ }
131
+ // core request
132
+ async request(query, variables, options) {
133
+ const ctx = {
134
+ request: { query, variables },
135
+ url: this.url,
136
+ headers: options?.headers ?? {},
137
+ cacheOptions: options?.cacheOptions
138
+ };
139
+ const resCtx = {};
140
+ const runner = compose(this.middlewares);
141
+ await runner(ctx, resCtx);
142
+ if (resCtx.error)
143
+ throw resCtx.error;
144
+ if (!resCtx.response)
145
+ throw new Error("No response from GraphQL transport");
146
+ if (resCtx.response.errors && resCtx.response.errors.length) {
147
+ const e = resCtx.response.errors[0];
148
+ const err = new Error(e.message);
149
+ err.extensions = e.extensions;
150
+ throw err;
151
+ }
152
+ return resCtx.response;
153
+ }
154
+ };
155
+
156
+ // src/services/user.service.ts
157
+ var GET_USER = `
158
+ query GetUser($id: ID!) {
159
+ user(id: $id) {
160
+ id
161
+ name
162
+ email
163
+ role
164
+ balance { amount currency }
165
+ }
166
+ }
167
+ `;
168
+ var createUserService = (client) => ({
169
+ async getUser(id) {
170
+ const res = await client.request(GET_USER, { id }, { cacheOptions: { skipCache: true } });
171
+ return res.data?.user ?? null;
172
+ }
173
+ });
174
+
175
+ // src/testing/mockClient.ts
176
+ var createMockClient = (handler) => {
177
+ return {
178
+ request: async (query, variables) => {
179
+ return await handler({ query, variables });
180
+ }
181
+ };
182
+ };
183
+ export {
184
+ AuthenticationError,
185
+ GraphQLClient,
186
+ NetworkError,
187
+ SdkError,
188
+ createMockClient,
189
+ createUserService,
190
+ toAsyncHeadersFactory,
191
+ toAsyncTokenProvider
192
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@connect-plus-online/ogabai-integrations",
3
+ "version": "0.1.01",
4
+ "description": "Ogabai integrations for Connect Plus Online",
5
+ "keywords": [
6
+ "graphql",
7
+ "sdk",
8
+ "typescript",
9
+ "connecthive",
10
+ "ogabai",
11
+ "ogabai-integrations",
12
+ "connect-plus",
13
+ "connect-plus-online"
14
+ ],
15
+ "author": "Agu Chijioke <chokey2nv@gmail.com>",
16
+ "license": "MIT",
17
+ "main": "dist/index.cjs.js",
18
+ "module": "dist/index.esm.js",
19
+ "types": "dist/index.d.ts",
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "scripts": {
27
+ "build": "tsup src/index.ts --dts --format cjs,esm --out-dir dist",
28
+ "prepublishOnly": "yarn build",
29
+ "test": "vitest",
30
+ "lint": "eslint src --ext .ts"
31
+ },
32
+ "dependencies": {},
33
+ "devDependencies": {
34
+ "tsup": "^6.0.0",
35
+ "typescript": "^5.0.0",
36
+ "vitest": "^0.34.0"
37
+ }
38
+ }