@channel.io/app-sdk-server 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.
Files changed (137) hide show
  1. package/dist/__tests__/decorators.test.d.ts +2 -0
  2. package/dist/__tests__/decorators.test.d.ts.map +1 -0
  3. package/dist/__tests__/decorators.test.js +259 -0
  4. package/dist/__tests__/decorators.test.js.map +1 -0
  5. package/dist/__tests__/testing-utils.test.d.ts +2 -0
  6. package/dist/__tests__/testing-utils.test.d.ts.map +1 -0
  7. package/dist/__tests__/testing-utils.test.js +118 -0
  8. package/dist/__tests__/testing-utils.test.js.map +1 -0
  9. package/dist/appstore/client.d.ts +70 -0
  10. package/dist/appstore/client.d.ts.map +1 -0
  11. package/dist/appstore/client.js +141 -0
  12. package/dist/appstore/client.js.map +1 -0
  13. package/dist/appstore/index.d.ts +3 -0
  14. package/dist/appstore/index.d.ts.map +1 -0
  15. package/dist/appstore/index.js +3 -0
  16. package/dist/appstore/index.js.map +1 -0
  17. package/dist/appstore/types.d.ts +87 -0
  18. package/dist/appstore/types.d.ts.map +1 -0
  19. package/dist/appstore/types.js +5 -0
  20. package/dist/appstore/types.js.map +1 -0
  21. package/dist/decorators/extension.decorator.d.ts +33 -0
  22. package/dist/decorators/extension.decorator.d.ts.map +1 -0
  23. package/dist/decorators/extension.decorator.js +36 -0
  24. package/dist/decorators/extension.decorator.js.map +1 -0
  25. package/dist/decorators/function.decorator.d.ts +34 -0
  26. package/dist/decorators/function.decorator.d.ts.map +1 -0
  27. package/dist/decorators/function.decorator.js +45 -0
  28. package/dist/decorators/function.decorator.js.map +1 -0
  29. package/dist/decorators/index.d.ts +5 -0
  30. package/dist/decorators/index.d.ts.map +1 -0
  31. package/dist/decorators/index.js +9 -0
  32. package/dist/decorators/index.js.map +1 -0
  33. package/dist/decorators/param.decorator.d.ts +49 -0
  34. package/dist/decorators/param.decorator.d.ts.map +1 -0
  35. package/dist/decorators/param.decorator.js +62 -0
  36. package/dist/decorators/param.decorator.js.map +1 -0
  37. package/dist/decorators/schema.decorator.d.ts +48 -0
  38. package/dist/decorators/schema.decorator.d.ts.map +1 -0
  39. package/dist/decorators/schema.decorator.js +59 -0
  40. package/dist/decorators/schema.decorator.js.map +1 -0
  41. package/dist/discovery/extension-discovery.service.d.ts +45 -0
  42. package/dist/discovery/extension-discovery.service.d.ts.map +1 -0
  43. package/dist/discovery/extension-discovery.service.js +192 -0
  44. package/dist/discovery/extension-discovery.service.js.map +1 -0
  45. package/dist/discovery/index.d.ts +3 -0
  46. package/dist/discovery/index.d.ts.map +1 -0
  47. package/dist/discovery/index.js +2 -0
  48. package/dist/discovery/index.js.map +1 -0
  49. package/dist/discovery/metadata.interface.d.ts +42 -0
  50. package/dist/discovery/metadata.interface.d.ts.map +1 -0
  51. package/dist/discovery/metadata.interface.js +2 -0
  52. package/dist/discovery/metadata.interface.js.map +1 -0
  53. package/dist/guards/index.d.ts +3 -0
  54. package/dist/guards/index.d.ts.map +1 -0
  55. package/dist/guards/index.js +3 -0
  56. package/dist/guards/index.js.map +1 -0
  57. package/dist/guards/signature.guard.d.ts +65 -0
  58. package/dist/guards/signature.guard.d.ts.map +1 -0
  59. package/dist/guards/signature.guard.js +156 -0
  60. package/dist/guards/signature.guard.js.map +1 -0
  61. package/dist/guards/signature.middleware.d.ts +76 -0
  62. package/dist/guards/signature.middleware.d.ts.map +1 -0
  63. package/dist/guards/signature.middleware.js +110 -0
  64. package/dist/guards/signature.middleware.js.map +1 -0
  65. package/dist/index.d.ts +11 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +21 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/native/client.d.ts +105 -0
  70. package/dist/native/client.d.ts.map +1 -0
  71. package/dist/native/client.js +210 -0
  72. package/dist/native/client.js.map +1 -0
  73. package/dist/native/index.d.ts +3 -0
  74. package/dist/native/index.d.ts.map +1 -0
  75. package/dist/native/index.js +3 -0
  76. package/dist/native/index.js.map +1 -0
  77. package/dist/native/types.d.ts +198 -0
  78. package/dist/native/types.d.ts.map +1 -0
  79. package/dist/native/types.js +8 -0
  80. package/dist/native/types.js.map +1 -0
  81. package/dist/nestjs/channel-app.controller.d.ts +22 -0
  82. package/dist/nestjs/channel-app.controller.d.ts.map +1 -0
  83. package/dist/nestjs/channel-app.controller.js +87 -0
  84. package/dist/nestjs/channel-app.controller.js.map +1 -0
  85. package/dist/nestjs/channel-app.module.d.ts +47 -0
  86. package/dist/nestjs/channel-app.module.d.ts.map +1 -0
  87. package/dist/nestjs/channel-app.module.js +93 -0
  88. package/dist/nestjs/channel-app.module.js.map +1 -0
  89. package/dist/nestjs/channel-app.service.d.ts +44 -0
  90. package/dist/nestjs/channel-app.service.d.ts.map +1 -0
  91. package/dist/nestjs/channel-app.service.js +190 -0
  92. package/dist/nestjs/channel-app.service.js.map +1 -0
  93. package/dist/nestjs/index.d.ts +5 -0
  94. package/dist/nestjs/index.d.ts.map +1 -0
  95. package/dist/nestjs/index.js +5 -0
  96. package/dist/nestjs/index.js.map +1 -0
  97. package/dist/nestjs/types.d.ts +70 -0
  98. package/dist/nestjs/types.d.ts.map +1 -0
  99. package/dist/nestjs/types.js +5 -0
  100. package/dist/nestjs/types.js.map +1 -0
  101. package/dist/simple/channel-app.d.ts +80 -0
  102. package/dist/simple/channel-app.d.ts.map +1 -0
  103. package/dist/simple/channel-app.js +253 -0
  104. package/dist/simple/channel-app.js.map +1 -0
  105. package/dist/simple/index.d.ts +2 -0
  106. package/dist/simple/index.d.ts.map +1 -0
  107. package/dist/simple/index.js +2 -0
  108. package/dist/simple/index.js.map +1 -0
  109. package/dist/testing/index.d.ts +9 -0
  110. package/dist/testing/index.d.ts.map +1 -0
  111. package/dist/testing/index.js +9 -0
  112. package/dist/testing/index.js.map +1 -0
  113. package/dist/testing/mock-context.d.ts +32 -0
  114. package/dist/testing/mock-context.d.ts.map +1 -0
  115. package/dist/testing/mock-context.js +33 -0
  116. package/dist/testing/mock-context.js.map +1 -0
  117. package/dist/testing/test-extension.d.ts +60 -0
  118. package/dist/testing/test-extension.d.ts.map +1 -0
  119. package/dist/testing/test-extension.js +113 -0
  120. package/dist/testing/test-extension.js.map +1 -0
  121. package/dist/token/cache.d.ts +31 -0
  122. package/dist/token/cache.d.ts.map +1 -0
  123. package/dist/token/cache.js +69 -0
  124. package/dist/token/cache.js.map +1 -0
  125. package/dist/token/index.d.ts +4 -0
  126. package/dist/token/index.d.ts.map +1 -0
  127. package/dist/token/index.js +4 -0
  128. package/dist/token/index.js.map +1 -0
  129. package/dist/token/manager.d.ts +111 -0
  130. package/dist/token/manager.d.ts.map +1 -0
  131. package/dist/token/manager.js +246 -0
  132. package/dist/token/manager.js.map +1 -0
  133. package/dist/token/types.d.ts +85 -0
  134. package/dist/token/types.d.ts.map +1 -0
  135. package/dist/token/types.js +5 -0
  136. package/dist/token/types.js.map +1 -0
  137. package/package.json +69 -0
@@ -0,0 +1,246 @@
1
+ import { InMemoryTokenCache } from "./cache.js";
2
+ /**
3
+ * Default refresh buffer: 5 minutes before expiry
4
+ */
5
+ const DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
6
+ /**
7
+ * Default Channel.io API base URL
8
+ */
9
+ const DEFAULT_API_BASE_URL = "https://api.channel.io";
10
+ /**
11
+ * Token manager for Channel.io App SDK
12
+ *
13
+ * Handles token issuance, caching, and automatic refresh for:
14
+ * - Manager tokens (for desk/agent operations)
15
+ * - User tokens (for user-facing operations)
16
+ * - Channel tokens (for channel-level operations)
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { TokenManager } from '@channel.io/app-sdk-server';
21
+ *
22
+ * const tokenManager = new TokenManager({
23
+ * appId: process.env.APP_ID,
24
+ * appSecret: process.env.APP_SECRET,
25
+ * });
26
+ *
27
+ * // Get a manager token (with automatic caching and refresh)
28
+ * const token = await tokenManager.getManagerToken({
29
+ * channelId: 'channel-123',
30
+ * managerId: 'manager-456',
31
+ * });
32
+ *
33
+ * // Use the token for API calls
34
+ * await fetch('https://api.channel.io/...', {
35
+ * headers: {
36
+ * 'Authorization': `Bearer ${token.accessToken}`,
37
+ * },
38
+ * });
39
+ * ```
40
+ */
41
+ export class TokenManager {
42
+ config;
43
+ cache;
44
+ debug;
45
+ constructor(config) {
46
+ this.config = {
47
+ ...config,
48
+ apiBaseUrl: config.apiBaseUrl ?? DEFAULT_API_BASE_URL,
49
+ refreshBufferMs: config.refreshBufferMs ?? DEFAULT_REFRESH_BUFFER_MS,
50
+ };
51
+ this.cache = config.cacheStorage ?? new InMemoryTokenCache();
52
+ this.debug = config.debug ?? false;
53
+ }
54
+ /**
55
+ * Get a manager token with automatic caching and refresh
56
+ */
57
+ async getManagerToken(request) {
58
+ const cacheKey = this.buildCacheKey("manager", request.channelId, request.managerId);
59
+ return this.getOrRefreshToken(cacheKey, () => this.issueManagerToken(request));
60
+ }
61
+ /**
62
+ * Get a user token with automatic caching and refresh
63
+ */
64
+ async getUserToken(request) {
65
+ const cacheKey = this.buildCacheKey("user", request.channelId, request.userId);
66
+ return this.getOrRefreshToken(cacheKey, () => this.issueUserToken(request));
67
+ }
68
+ /**
69
+ * Get a channel token with automatic caching and refresh
70
+ */
71
+ async getChannelToken(request) {
72
+ const cacheKey = this.buildCacheKey("channel", request.channelId);
73
+ return this.getOrRefreshToken(cacheKey, () => this.issueChannelToken(request));
74
+ }
75
+ /**
76
+ * Manually refresh a token (bypass cache)
77
+ */
78
+ async refreshToken(refreshToken) {
79
+ const response = await this.apiRequest("/app/v1/token/refresh", {
80
+ method: "POST",
81
+ body: JSON.stringify({ refreshToken }),
82
+ });
83
+ return this.normalizeTokenResponse(response);
84
+ }
85
+ /**
86
+ * Invalidate a cached token
87
+ */
88
+ async invalidateToken(type, channelId, entityId) {
89
+ const cacheKey = this.buildCacheKey(type, channelId, entityId);
90
+ await this.cache.delete(cacheKey);
91
+ }
92
+ /**
93
+ * Clear all cached tokens
94
+ */
95
+ async clearCache() {
96
+ await this.cache.clear();
97
+ }
98
+ /**
99
+ * Get or refresh a token with automatic caching
100
+ */
101
+ async getOrRefreshToken(cacheKey, issueToken) {
102
+ // Try to get from cache
103
+ const cached = await this.cache.get(cacheKey);
104
+ if (cached) {
105
+ // Check if token needs refresh (within buffer period)
106
+ const now = Date.now();
107
+ const expiresAt = cached.token.expiresAt;
108
+ const needsRefresh = now >= expiresAt - this.config.refreshBufferMs;
109
+ if (!needsRefresh) {
110
+ this.log(`Cache hit for ${cacheKey}`);
111
+ return cached.token;
112
+ }
113
+ // Try to refresh using refresh token
114
+ this.log(`Token expiring soon, refreshing for ${cacheKey}`);
115
+ try {
116
+ const refreshed = await this.refreshToken(cached.token.refreshToken);
117
+ await this.cacheToken(cacheKey, refreshed);
118
+ return refreshed;
119
+ }
120
+ catch (error) {
121
+ this.log(`Refresh failed, re-issuing token for ${cacheKey}`, error);
122
+ // Fall through to issue new token
123
+ }
124
+ }
125
+ // Issue new token
126
+ this.log(`Issuing new token for ${cacheKey}`);
127
+ const token = await issueToken();
128
+ await this.cacheToken(cacheKey, token);
129
+ return token;
130
+ }
131
+ /**
132
+ * Issue a manager token
133
+ */
134
+ async issueManagerToken(request) {
135
+ const response = await this.apiRequest(`/app/v1/channels/${request.channelId}/managers/${request.managerId}/token`, { method: "POST" });
136
+ return this.normalizeTokenResponse(response);
137
+ }
138
+ /**
139
+ * Issue a user token
140
+ */
141
+ async issueUserToken(request) {
142
+ const response = await this.apiRequest(`/app/v1/channels/${request.channelId}/users/${request.userId}/token`, { method: "POST" });
143
+ return this.normalizeTokenResponse(response);
144
+ }
145
+ /**
146
+ * Issue a channel token
147
+ */
148
+ async issueChannelToken(request) {
149
+ const response = await this.apiRequest(`/app/v1/channels/${request.channelId}/token`, { method: "POST" });
150
+ return this.normalizeTokenResponse(response);
151
+ }
152
+ /**
153
+ * Cache a token
154
+ */
155
+ async cacheToken(key, token) {
156
+ const cached = {
157
+ token,
158
+ cachedAt: Date.now(),
159
+ key,
160
+ };
161
+ // TTL is until token expires
162
+ const ttlMs = token.expiresAt - Date.now();
163
+ await this.cache.set(key, cached, ttlMs > 0 ? ttlMs : undefined);
164
+ }
165
+ /**
166
+ * Build a cache key
167
+ */
168
+ buildCacheKey(type, channelId, entityId) {
169
+ const parts = [this.config.appId, type, channelId];
170
+ if (entityId)
171
+ parts.push(entityId);
172
+ return parts.join(":");
173
+ }
174
+ /**
175
+ * Make an API request to Channel.io
176
+ */
177
+ async apiRequest(path, options = {}) {
178
+ const url = `${this.config.apiBaseUrl}${path}`;
179
+ const headers = {
180
+ "Content-Type": "application/json",
181
+ "X-App-Id": this.config.appId,
182
+ "X-App-Secret": this.config.appSecret,
183
+ ...options.headers,
184
+ };
185
+ const response = await fetch(url, {
186
+ ...options,
187
+ headers,
188
+ });
189
+ if (!response.ok) {
190
+ const errorBody = await response.text();
191
+ throw new TokenManagerError(`API request failed: ${String(response.status)} ${response.statusText}`, response.status, errorBody);
192
+ }
193
+ return response.json();
194
+ }
195
+ /**
196
+ * Normalize token response (handle different API response formats)
197
+ */
198
+ normalizeTokenResponse(response) {
199
+ const expiresIn = response.expiresIn ?? response.expires_in ?? 3600;
200
+ const refreshTokenExpiresIn = response.refreshTokenExpiresIn ?? response.refresh_token_expires_in ?? 604800;
201
+ return {
202
+ accessToken: response.accessToken ?? response.access_token ?? "",
203
+ refreshToken: response.refreshToken ?? response.refresh_token ?? "",
204
+ expiresIn,
205
+ expiresAt: response.expiresAt ?? Date.now() + expiresIn * 1000,
206
+ refreshTokenExpiresAt: response.refreshTokenExpiresAt ?? Date.now() + refreshTokenExpiresIn * 1000,
207
+ tokenType: response.tokenType ?? response.token_type ?? "Bearer",
208
+ scopes: response.scopes ?? (response.scope ? response.scope.split(" ") : []),
209
+ };
210
+ }
211
+ /**
212
+ * Debug logging
213
+ */
214
+ log(message, error) {
215
+ if (this.debug) {
216
+ if (error) {
217
+ console.debug(`[TokenManager] ${message}`, error);
218
+ }
219
+ else {
220
+ console.debug(`[TokenManager] ${message}`);
221
+ }
222
+ }
223
+ }
224
+ /**
225
+ * Cleanup resources (call when shutting down)
226
+ */
227
+ destroy() {
228
+ if (this.cache instanceof InMemoryTokenCache) {
229
+ this.cache.destroy();
230
+ }
231
+ }
232
+ }
233
+ /**
234
+ * Token manager error
235
+ */
236
+ export class TokenManagerError extends Error {
237
+ statusCode;
238
+ responseBody;
239
+ constructor(message, statusCode, responseBody) {
240
+ super(message);
241
+ this.statusCode = statusCode;
242
+ this.responseBody = responseBody;
243
+ this.name = "TokenManagerError";
244
+ }
245
+ }
246
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/token/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Token types and interfaces for Channel.io App SDK
3
+ */
4
+ /**
5
+ * Token response from Channel.io token issuance
6
+ */
7
+ export interface TokenResponse {
8
+ /** Access token for API calls */
9
+ accessToken: string;
10
+ /** Refresh token for token renewal */
11
+ refreshToken: string;
12
+ /** Token expiration time in seconds */
13
+ expiresIn: number;
14
+ /** Token expiration timestamp (Unix milliseconds) */
15
+ expiresAt: number;
16
+ /** Refresh token expiration timestamp (Unix milliseconds) */
17
+ refreshTokenExpiresAt: number;
18
+ /** Token type (usually "Bearer") */
19
+ tokenType: string;
20
+ /** Granted scopes */
21
+ scopes: string[];
22
+ }
23
+ /**
24
+ * Cached token entry with metadata
25
+ */
26
+ export interface CachedToken {
27
+ /** The token response */
28
+ token: TokenResponse;
29
+ /** When this cache entry was created */
30
+ cachedAt: number;
31
+ /** Cache key identifier */
32
+ key: string;
33
+ }
34
+ /**
35
+ * Token cache storage interface
36
+ * Implement this to use custom storage (Redis, database, etc.)
37
+ */
38
+ export interface TokenCacheStorage {
39
+ /** Get a cached token by key */
40
+ get(key: string): Promise<CachedToken | null>;
41
+ /** Set a cached token */
42
+ set(key: string, token: CachedToken, ttlMs?: number): Promise<void>;
43
+ /** Delete a cached token */
44
+ delete(key: string): Promise<void>;
45
+ /** Clear all cached tokens */
46
+ clear(): Promise<void>;
47
+ }
48
+ /**
49
+ * Token manager configuration
50
+ */
51
+ export interface TokenManagerConfig {
52
+ /** App ID */
53
+ appId: string;
54
+ /** App secret */
55
+ appSecret: string;
56
+ /** Channel.io API base URL (default: https://api.channel.io) */
57
+ apiBaseUrl?: string;
58
+ /** Custom cache storage (default: in-memory) */
59
+ cacheStorage?: TokenCacheStorage;
60
+ /** Buffer time before expiry to trigger refresh (default: 5 minutes) */
61
+ refreshBufferMs?: number;
62
+ /** Enable debug logging */
63
+ debug?: boolean;
64
+ }
65
+ /**
66
+ * Token request for issuing manager token
67
+ */
68
+ export interface ManagerTokenRequest {
69
+ channelId: string;
70
+ managerId: string;
71
+ }
72
+ /**
73
+ * Token request for issuing user token
74
+ */
75
+ export interface UserTokenRequest {
76
+ channelId: string;
77
+ userId: string;
78
+ }
79
+ /**
80
+ * Token request for issuing channel token
81
+ */
82
+ export interface ChannelTokenRequest {
83
+ channelId: string;
84
+ }
85
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/token/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yBAAyB;IACzB,KAAK,EAAE,aAAa,CAAC;IACrB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,yBAAyB;IACzB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,4BAA4B;IAC5B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8BAA8B;IAC9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Token types and interfaces for Channel.io App SDK
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/token/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@channel.io/app-sdk-server",
3
+ "version": "0.1.0",
4
+ "description": "NestJS server SDK for Channel.io apps",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./nestjs": {
14
+ "types": "./dist/nestjs/index.d.ts",
15
+ "import": "./dist/nestjs/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "zod": "^3.24.1",
23
+ "zod-to-json-schema": "^3.24.1",
24
+ "@channel.io/app-sdk-core": "0.1.0"
25
+ },
26
+ "peerDependencies": {
27
+ "@nestjs/common": ">=10.0.0",
28
+ "@nestjs/core": ">=10.0.0",
29
+ "reflect-metadata": ">=0.1.0"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "@nestjs/common": {
33
+ "optional": false
34
+ },
35
+ "@nestjs/core": {
36
+ "optional": false
37
+ }
38
+ },
39
+ "devDependencies": {
40
+ "@nestjs/common": "^10.4.15",
41
+ "@nestjs/core": "^10.4.15",
42
+ "@nestjs/platform-express": "^10.4.15",
43
+ "@nestjs/testing": "^10.4.15",
44
+ "@types/express": "^5.0.6",
45
+ "reflect-metadata": "^0.2.2",
46
+ "rxjs": "^7.8.1",
47
+ "typescript": "^5.7.2",
48
+ "vitest": "^2.1.8"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/channel-io/app-sdk.git",
53
+ "directory": "packages/server"
54
+ },
55
+ "license": "MIT",
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "scripts": {
60
+ "build": "tsc",
61
+ "dev": "tsc --watch",
62
+ "lint": "eslint src/",
63
+ "lint:fix": "eslint src/ --fix",
64
+ "typecheck": "tsc --noEmit",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest",
67
+ "clean": "rm -rf dist"
68
+ }
69
+ }