@blocklet/sdk 1.16.41-beta-20250325-154552-2bf78c26 → 1.16.41-beta-20250329-232306-53c45e3b

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/lib/config.js CHANGED
@@ -293,9 +293,9 @@ const getBlockletJs = (pageGroup = '', pathPrefix = '', source = blockletJs) =>
293
293
  if (pageGroup) {
294
294
  copy = copy.replace('pageGroup: "",', `pageGroup: "${pageGroup}",`);
295
295
  }
296
- if (pathPrefix) {
297
- const componentDid = process.env.BLOCKLET_COMPONENT_DID;
298
- const { mountPoint } = componentStore.find((x) => x.did === componentDid);
296
+ const componentDid = process.env.BLOCKLET_COMPONENT_DID;
297
+ if (pathPrefix && componentDid) {
298
+ const { mountPoint } = componentStore.find((x) => x.did === componentDid) || {};
299
299
  copy = copy
300
300
  .replace(`prefix: "${normalize(mountPoint)}",`, `prefix: "${normalize(pathPrefix)}",`)
301
301
  .replace('prefix: "/",', `prefix: "${normalize(pathPrefix)}",`);
@@ -7,7 +7,10 @@ type PageData = {
7
7
  };
8
8
  type FallbackOptions = {
9
9
  root?: string | undefined;
10
- getPageData?: (req: Request) => Promise<PageData>;
10
+ getPageData?: (req: Request) => PageData | Promise<PageData>;
11
+ timeout?: number;
12
+ maxLength?: number;
13
+ cacheTtl?: number;
11
14
  };
12
15
  declare const fallback: (file: string, options?: FallbackOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
13
16
  export = fallback;
@@ -2,74 +2,160 @@
2
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
- const fs_1 = require("fs");
5
+ const fs_1 = __importDefault(require("fs"));
6
6
  const path_1 = require("path");
7
7
  const ufo_1 = require("ufo");
8
8
  const escape_1 = __importDefault(require("lodash/escape"));
9
+ const crypto_1 = __importDefault(require("crypto"));
9
10
  const constant_1 = require("@blocklet/constant");
10
11
  const config_1 = require("../config");
12
+ // Cache configurations
13
+ const DEFAULT_CACHE_TTL = 1 * 60 * 1000; // 1 minute
14
+ const cache = new Map();
15
+ // Pre-compile regex patterns for better performance
16
+ const TITLE_TAG_REGEX = /<title>(.+)<\/title>/;
17
+ const HEAD_END_TAG = '</head>';
18
+ const buildOpenGraph = (pageData, appUrl) => {
19
+ const parts = [
20
+ `<meta property="og:title" content="${pageData.title}" data-react-helmet="true" />`,
21
+ `<meta property="og:description" content="${pageData.description}" data-react-helmet="true" />`,
22
+ '<meta property="og:type" content="website" data-react-helmet="true" />',
23
+ `<meta property="og:url" content="${appUrl}" data-react-helmet="true" />`,
24
+ `<meta property="og:image" content="${pageData.ogImage}" data-react-helmet="true" />`,
25
+ '<meta name="twitter:card" content="summary_large_image" data-react-helmet="true" />',
26
+ ];
27
+ return parts.join('\n');
28
+ };
29
+ const validatePageData = (data, maxLength) => {
30
+ if (data.title && data.title.length > maxLength) {
31
+ throw new Error('Title too long');
32
+ }
33
+ if (data.description && data.description.length > maxLength) {
34
+ throw new Error('Description too long');
35
+ }
36
+ };
37
+ const generateETag = (content) => {
38
+ const hash = crypto_1.default.createHash('sha1');
39
+ hash.update(content);
40
+ return `W/"${hash.digest('base64')}"`;
41
+ };
42
+ const getCacheKey = (filePath, pageGroup, pathPrefix) => {
43
+ return `${filePath}:${pageGroup}:${pathPrefix}`;
44
+ };
45
+ const tryWithTimeout = (asyncFn, timeout) => {
46
+ if (typeof asyncFn !== 'function') {
47
+ throw new Error('Must provide a valid asyncFn function');
48
+ }
49
+ // eslint-disable-next-line no-async-promise-executor
50
+ return new Promise(async (resolve, reject) => {
51
+ const timer = setTimeout(() => {
52
+ reject(new Error(`Operation timed out after ${timeout} ms`));
53
+ }, timeout);
54
+ try {
55
+ const result = await asyncFn();
56
+ resolve(result);
57
+ }
58
+ catch (err) {
59
+ reject(err);
60
+ }
61
+ finally {
62
+ clearTimeout(timer);
63
+ }
64
+ });
65
+ };
11
66
  const fallback = (file, options = {}) => {
12
67
  const filePath = options.root ? (0, path_1.join)(options.root, file) : file;
13
- if ((0, fs_1.existsSync)(filePath) === false) {
68
+ // Check file existence during initialization
69
+ if (!fs_1.default.existsSync(filePath)) {
14
70
  throw new Error(`Fallback file not found at: ${filePath}`);
15
71
  }
16
72
  return async (req, res, next) => {
17
- if ((req.method === 'GET' || req.method === 'HEAD') && req.accepts('html') && !constant_1.RESOURCE_PATTERN.test(req.path)) {
18
- res.type('html');
73
+ try {
74
+ // Skip non-HTML requests early
75
+ if (!(req.method === 'GET' || req.method === 'HEAD') || !req.accepts('html') || constant_1.RESOURCE_PATTERN.test(req.path)) {
76
+ next();
77
+ return;
78
+ }
19
79
  const pageGroup = req.headers['x-page-group'] || '';
20
80
  const pathPrefix = req.headers['x-path-prefix'] || '';
21
- const pageData = typeof options.getPageData === 'function' ? await options.getPageData(req) : {};
81
+ const cacheKey = getCacheKey(filePath, pageGroup, pathPrefix);
82
+ // Check cache first
83
+ const cached = cache.get(cacheKey);
84
+ const cacheTtl = options.cacheTtl || DEFAULT_CACHE_TTL;
85
+ if (cached && Date.now() - cached.timestamp < cacheTtl) {
86
+ if (cached.pageGroup === pageGroup && cached.pathPrefix === pathPrefix) {
87
+ res.setHeader('X-Cache', 'HIT');
88
+ res.setHeader('ETag', cached.etag);
89
+ res.type('html');
90
+ res.send(cached.html);
91
+ if (process.env.NODE_ENV === 'test') {
92
+ next(cached.html);
93
+ }
94
+ return;
95
+ }
96
+ }
97
+ // Get page data with timeout protection
98
+ const pageData = await tryWithTimeout(options.getPageData ? () => options.getPageData(req) : () => Promise.resolve({}), options.timeout || 5000);
99
+ validatePageData(pageData, options.maxLength || 1000);
22
100
  pageData.title = (0, escape_1.default)(pageData.title || config_1.env.appName);
23
101
  pageData.description = (0, escape_1.default)(pageData.description || config_1.env.appDescription);
24
102
  pageData.ogImage = pageData.ogImage || (0, ufo_1.joinURL)(config_1.env.appUrl || '/', '/.well-known/service/blocklet/og.png');
25
- let source = (0, fs_1.readFileSync)(filePath).toString();
26
- // inject seo title
103
+ let source = await fs_1.default.promises.readFile(filePath, 'utf8');
104
+ // Optimize string replacements
27
105
  if (pageData.title) {
28
- if (source.indexOf('<title>') === -1) {
29
- source = source.replace('</head>', `<title>${pageData.title}</title></head>`);
106
+ if (!source.includes('<title>')) {
107
+ source = source.replace(HEAD_END_TAG, `<title>${pageData.title}</title>${HEAD_END_TAG}`);
30
108
  }
31
109
  else {
32
- source = source.replace(/<title>(.+)<\/title>/, `<title>${pageData.title}</title>`);
110
+ source = source.replace(TITLE_TAG_REGEX, `<title>${pageData.title}</title>`);
33
111
  }
34
112
  }
35
- // inject seo description
36
- if (pageData.description) {
37
- if (source.indexOf('<meta name="description"') === -1) {
38
- source = source.replace('</head>', `<meta name="description" content="${pageData.description}" data-react-helmet="true" /></head>`);
39
- }
113
+ if (pageData.description && !source.includes('<meta name="description"')) {
114
+ source = source.replace(HEAD_END_TAG, `<meta name="description" content="${pageData.description}" data-react-helmet="true" />${HEAD_END_TAG}`);
40
115
  }
41
- // inject open graph
42
- if (source.indexOf('meta property="og:image"') === -1) {
43
- const og = `<meta property="og:title" content="${pageData.title}" data-react-helmet="true" />
44
- <meta property="og:description" content="${pageData.description}" data-react-helmet="true" />
45
- <meta property="og:type" content="website" data-react-helmet="true" />
46
- <meta property="og:url" content="${config_1.env.appUrl}" data-react-helmet="true" />
47
- <meta property="og:image" content="${pageData.ogImage}" data-react-helmet="true" />
48
- <meta name="twitter:card" content="summary_large_image" data-react-helmet="true" />`;
49
- source = source.replace('</head>', `${og}</head>`);
116
+ if (!source.includes('meta property="og:image"')) {
117
+ source = source.replace(HEAD_END_TAG, `${buildOpenGraph(pageData, config_1.env.appUrl || '/')}\n${HEAD_END_TAG}`);
50
118
  }
51
119
  if (pageData.embed) {
52
- source = source.replace('</head>', `<link rel="blocklet-open-embed" type="application/json" href="${pageData.embed}" /></head>`);
120
+ source = source.replace(HEAD_END_TAG, `<link rel="blocklet-open-embed" type="application/json" href="${pageData.embed}" />${HEAD_END_TAG}`);
53
121
  }
54
- // inline blocklet.js
55
122
  const blockletJs = (0, config_1.getBlockletJs)(pageGroup, pathPrefix);
56
123
  if (blockletJs) {
57
124
  source = source
58
125
  .replace('<script src="__blocklet__.js"></script>', `<script>${blockletJs}</script>`)
59
126
  .replace('<script src="__meta__.js"></script>', `<script>${blockletJs}</script>`);
60
127
  }
61
- // disable cache for generated html
62
- res.setHeader('Surrogate-Control', 'no-store');
63
- res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
64
- res.setHeader('Expires', '0');
128
+ // Cache the processed response
129
+ const etag = generateETag(source);
130
+ cache.set(cacheKey, {
131
+ html: source,
132
+ timestamp: Date.now(),
133
+ etag,
134
+ pageGroup: pageGroup,
135
+ pathPrefix: pathPrefix,
136
+ });
137
+ // Set response headers
138
+ if (options.cacheTtl) {
139
+ res.setHeader('Cache-Control', `public, max-age=${options.cacheTtl}`);
140
+ }
141
+ else {
142
+ res.setHeader('Surrogate-Control', 'no-store');
143
+ res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
144
+ res.setHeader('Expires', '0');
145
+ }
146
+ res.setHeader('X-Cache', 'MISS');
147
+ res.setHeader('ETag', etag);
148
+ res.type('html');
65
149
  res.send(source);
66
- // istanbul-ignore-next
67
150
  if (process.env.NODE_ENV === 'test') {
68
151
  next(source);
69
152
  }
70
153
  }
71
- else {
72
- next();
154
+ catch (err) {
155
+ if (process.env.NODE_ENV === 'test') {
156
+ console.error('error', err);
157
+ }
158
+ next(err);
73
159
  }
74
160
  };
75
161
  };
@@ -24,12 +24,20 @@ declare const _default: {
24
24
  };
25
25
  fallback: (file: string, options?: {
26
26
  root?: string | undefined;
27
- getPageData?: (req: import("express").Request) => Promise<{
27
+ getPageData?: (req: import("express").Request) => {
28
+ title?: string;
29
+ description?: string;
30
+ ogImage?: string;
31
+ embed?: string;
32
+ } | Promise<{
28
33
  title?: string;
29
34
  description?: string;
30
35
  ogImage?: string;
31
36
  embed?: string;
32
37
  }>;
38
+ timeout?: number;
39
+ maxLength?: number;
40
+ cacheTtl?: number;
33
41
  }) => (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => Promise<void>;
34
42
  sitemap: (generatorFn: (fn: (item: {
35
43
  url: string;
@@ -3,6 +3,11 @@ type PartialDeep<T> = {
3
3
  [K in keyof T]?: T[K] extends object ? PartialDeep<T[K]> : T[K];
4
4
  };
5
5
  type OmitTeamDid<T> = PartialDeep<Omit<T, 'teamDid'>>;
6
+ type RequestHeaders = {
7
+ headers: {
8
+ cookie: string;
9
+ };
10
+ };
6
11
  declare class AuthService {
7
12
  constructor(httpEndpoint?: string);
8
13
  }
@@ -62,6 +67,7 @@ interface AuthService {
62
67
  getComponent(did: string): Promise<Client.ComponentState>;
63
68
  getTrustedDomains(): Promise<string[]>;
64
69
  getVault(): Promise<string>;
65
- updateUserAddress(args: OmitTeamDid<Client.RequestUpdateUserAddressInput>): Promise<Client.ResponseUser>;
70
+ updateUserAddress(args: OmitTeamDid<Client.RequestUpdateUserAddressInput>, options: RequestHeaders): Promise<Client.ResponseUser>;
71
+ updateUserInfo(userInfo: ABTNodeClient.UserInfoInput, options: RequestHeaders): Promise<Client.ResponseUser>;
66
72
  }
67
73
  export = AuthService;
@@ -71,6 +71,7 @@ class AuthService {
71
71
  'updateUserExtra',
72
72
  // updateUserInfo
73
73
  'updateUserAddress',
74
+ 'updateUserInfo',
74
75
  // tagging
75
76
  'getTags',
76
77
  'createTag',
@@ -201,6 +202,40 @@ class AuthService {
201
202
  const { blocklet } = await this.getBlocklet();
202
203
  return (0, security_1.verifyVault)(blocklet.vaults, wallet.address);
203
204
  };
205
+ this.updateUserInfo = async (userInfo, options) => {
206
+ const fn = client.updateUserInfo;
207
+ if (!options?.headers?.cookie) {
208
+ throw new Error('Missing required authentication cookie in request headers');
209
+ }
210
+ if (!userInfo?.did) {
211
+ throw new Error('Missing required user DID in address update args');
212
+ }
213
+ try {
214
+ // @ts-ignore
215
+ const res = await fn({ input: { user: userInfo, teamDid } }, options);
216
+ return res;
217
+ }
218
+ catch (err) {
219
+ throw new Error(err.response ? err.response.data : err.message);
220
+ }
221
+ };
222
+ this.updateUserAddress = async (args, options) => {
223
+ const fn = client.updateUserAddress;
224
+ if (!options?.headers?.cookie) {
225
+ throw new Error('Missing required authentication cookie in request headers');
226
+ }
227
+ if (!args?.did) {
228
+ throw new Error('Missing required user DID in address update args');
229
+ }
230
+ try {
231
+ // @ts-ignore
232
+ const res = await fn({ input: { ...args, teamDid } }, options);
233
+ return res;
234
+ }
235
+ catch (err) {
236
+ throw new Error(err.response ? err.response.data : err.message);
237
+ }
238
+ };
204
239
  // eslint-disable-next-line no-constructor-return
205
240
  return new Proxy(this, {
206
241
  get(target, propKey) {
@@ -1,3 +1,10 @@
1
+ export interface TActivityTarget {
2
+ desc?: any;
3
+ id: string;
4
+ image?: any;
5
+ name?: any;
6
+ type: 'discussion' | 'blog' | 'doc' | 'bookmark' | 'comment' | 'user';
7
+ }
1
8
  export type TChannelEvent = string;
2
9
  export interface TDataAsset {
3
10
  chainHost: string;
@@ -61,6 +68,7 @@ export interface TMessage {
61
68
  }
62
69
  export interface TNotification {
63
70
  actions?: TNotificationAction[];
71
+ activity?: TNotificationActivity;
64
72
  appInfo?: object;
65
73
  attachments?: TNotificationAttachment[];
66
74
  blocks?: TNotificationAttachment[];
@@ -84,6 +92,12 @@ export interface TNotificationAction {
84
92
  name: string;
85
93
  title?: string;
86
94
  }
95
+ export interface TNotificationActivity {
96
+ actor: unknown;
97
+ meta?: any;
98
+ target: TActivityTarget;
99
+ type: 'comment' | 'like' | 'follow' | 'tips' | 'mention' | 'assign';
100
+ }
87
101
  export interface TNotificationAttachment {
88
102
  data?: any;
89
103
  fields?: any;
@@ -6,6 +6,22 @@ declare const TYPES: {
6
6
  HI: string;
7
7
  PASSTHROUGH: string;
8
8
  };
9
+ declare const ACTIVITY_TYPES: {
10
+ COMMENT: string;
11
+ LIKE: string;
12
+ FOLLOW: string;
13
+ TIPS: string;
14
+ MENTION: string;
15
+ ASSIGN: string;
16
+ };
17
+ declare const ACTIVITY_TARGET_TYPES: {
18
+ DISCUSSION: string;
19
+ BLOG: string;
20
+ DOC: string;
21
+ BOOKMARK: string;
22
+ COMMENT: string;
23
+ USER: string;
24
+ };
9
25
  declare const assetSchema: JOI.ObjectSchema<any>;
10
26
  declare const vcSchema: JOI.ObjectSchema<any>;
11
27
  declare const tokenSchema: JOI.ObjectSchema<any>;
@@ -19,6 +35,8 @@ declare const attachmentSchema: JOI.ObjectSchema<any>;
19
35
  declare const notificationTypeSchema: JOI.ObjectSchema<any>;
20
36
  declare const connectTypeSchema: JOI.ObjectSchema<any>;
21
37
  declare const feedTypeSchema: JOI.ObjectSchema<any>;
38
+ declare const activityTargetSchema: JOI.ObjectSchema<any>;
39
+ declare const notificationActivitySchema: JOI.ObjectSchema<any>;
22
40
  declare const notificationSchema: JOI.ObjectSchema<any>;
23
41
  declare const messageSchema: JOI.ObjectSchema<any>;
24
42
  declare const inputNotificationSchema: JOI.ArraySchema<any[]>;
@@ -30,6 +48,7 @@ export declare const validateMessage: any;
30
48
  export declare const validateChannelEvent: any;
31
49
  export declare const validateOption: any;
32
50
  export declare const validateEmail: any;
51
+ export declare const validateActivity: any;
33
52
  export { tokenSchema };
34
53
  export { actionSchema };
35
54
  export { assetSchema };
@@ -46,6 +65,9 @@ export { optionSchema };
46
65
  export { channelEventSchema };
47
66
  export { TYPES as NOTIFICATION_TYPES };
48
67
  export { inputNotificationSchema, notificationTypeSchema, connectTypeSchema, feedTypeSchema };
68
+ export { ACTIVITY_TYPES, ACTIVITY_TARGET_TYPES };
69
+ export { notificationActivitySchema };
70
+ export { activityTargetSchema };
49
71
  declare const _default: {
50
72
  validateReceiver: any;
51
73
  validateNotification: any;
@@ -73,5 +95,24 @@ declare const _default: {
73
95
  HI: string;
74
96
  PASSTHROUGH: string;
75
97
  };
98
+ ACTIVITY_TYPES: {
99
+ COMMENT: string;
100
+ LIKE: string;
101
+ FOLLOW: string;
102
+ TIPS: string;
103
+ MENTION: string;
104
+ ASSIGN: string;
105
+ };
106
+ ACTIVITY_TARGET_TYPES: {
107
+ DISCUSSION: string;
108
+ BLOG: string;
109
+ DOC: string;
110
+ BOOKMARK: string;
111
+ COMMENT: string;
112
+ USER: string;
113
+ };
114
+ validateActivity: any;
115
+ notificationActivitySchema: JOI.ObjectSchema<any>;
116
+ activityTargetSchema: JOI.ObjectSchema<any>;
76
117
  };
77
118
  export default _default;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.feedTypeSchema = exports.connectTypeSchema = exports.notificationTypeSchema = exports.inputNotificationSchema = exports.NOTIFICATION_TYPES = exports.channelEventSchema = exports.optionSchema = exports.messageSchema = exports.notificationSchema = exports.attachmentSchema = exports.dappSchema = exports.imageSchema = exports.linkSchema = exports.textSchema = exports.transactionSchema = exports.vcSchema = exports.assetSchema = exports.actionSchema = exports.tokenSchema = exports.validateEmail = exports.validateOption = exports.validateChannelEvent = exports.validateMessage = exports.validateNotification = exports.validateReceiver = void 0;
6
+ exports.activityTargetSchema = exports.notificationActivitySchema = exports.ACTIVITY_TARGET_TYPES = exports.ACTIVITY_TYPES = exports.feedTypeSchema = exports.connectTypeSchema = exports.notificationTypeSchema = exports.inputNotificationSchema = exports.NOTIFICATION_TYPES = exports.channelEventSchema = exports.optionSchema = exports.messageSchema = exports.notificationSchema = exports.attachmentSchema = exports.dappSchema = exports.imageSchema = exports.linkSchema = exports.textSchema = exports.transactionSchema = exports.vcSchema = exports.assetSchema = exports.actionSchema = exports.tokenSchema = exports.validateActivity = exports.validateEmail = exports.validateOption = exports.validateChannelEvent = exports.validateMessage = exports.validateNotification = exports.validateReceiver = void 0;
7
7
  const joi_1 = __importDefault(require("joi"));
8
8
  const extension_1 = require("@blocklet/meta/lib/extension");
9
9
  const Joi = joi_1.default.extend(extension_1.didExtension);
@@ -33,6 +33,24 @@ const ATTACHMENT_TYPES = {
33
33
  LINK: 'link',
34
34
  SECTION: 'section',
35
35
  };
36
+ const ACTIVITY_TYPES = {
37
+ COMMENT: 'comment',
38
+ LIKE: 'like',
39
+ FOLLOW: 'follow',
40
+ TIPS: 'tips',
41
+ MENTION: 'mention',
42
+ ASSIGN: 'assign',
43
+ };
44
+ exports.ACTIVITY_TYPES = ACTIVITY_TYPES;
45
+ const ACTIVITY_TARGET_TYPES = {
46
+ DISCUSSION: 'discussion',
47
+ BLOG: 'blog',
48
+ DOC: 'doc',
49
+ BOOKMARK: 'bookmark',
50
+ COMMENT: 'comment',
51
+ USER: 'user',
52
+ };
53
+ exports.ACTIVITY_TARGET_TYPES = ACTIVITY_TARGET_TYPES;
36
54
  const assetSchema = Joi.object({
37
55
  did: Joi.DID().trim().required(),
38
56
  chainHost: Joi.string().uri().required(),
@@ -162,6 +180,52 @@ const feedTypeSchema = Joi.object({
162
180
  .required()
163
181
  .meta({ className: 'TNotificationFeed' });
164
182
  exports.feedTypeSchema = feedTypeSchema;
183
+ const activityTargetSchema = Joi.object({
184
+ type: Joi.string()
185
+ .valid(...Object.values(ACTIVITY_TARGET_TYPES))
186
+ .required(),
187
+ id: Joi.string().required(),
188
+ name: Joi.when('type', {
189
+ is: ACTIVITY_TARGET_TYPES.USER,
190
+ then: Joi.forbidden(),
191
+ otherwise: Joi.string().allow('').optional(),
192
+ }),
193
+ desc: Joi.when('type', {
194
+ is: ACTIVITY_TARGET_TYPES.USER,
195
+ then: Joi.forbidden(),
196
+ otherwise: Joi.string().allow('').optional(),
197
+ }),
198
+ image: Joi.when('type', {
199
+ is: ACTIVITY_TARGET_TYPES.USER,
200
+ then: Joi.forbidden(),
201
+ otherwise: Joi.string().allow('').optional(),
202
+ }),
203
+ }).meta({ className: 'TActivityTarget' });
204
+ exports.activityTargetSchema = activityTargetSchema;
205
+ const notificationActivitySchema = Joi.object({
206
+ type: Joi.string()
207
+ .valid(...Object.values(ACTIVITY_TYPES))
208
+ .required(),
209
+ actor: Joi.DID().trim().required(),
210
+ target: activityTargetSchema.required(),
211
+ meta: Joi.when('type', {
212
+ is: ACTIVITY_TYPES.TIPS,
213
+ then: Joi.object({
214
+ amount: Joi.number().required(),
215
+ symbol: Joi.string().required(),
216
+ chainId: Joi.string().required(),
217
+ }).required(),
218
+ otherwise: Joi.when('type', {
219
+ is: ACTIVITY_TYPES.COMMENT,
220
+ then: Joi.object({
221
+ id: Joi.string().required(),
222
+ content: Joi.string().required(),
223
+ }).required(),
224
+ otherwise: Joi.object().optional(),
225
+ }),
226
+ }),
227
+ }).meta({ className: 'TNotificationActivity' });
228
+ exports.notificationActivitySchema = notificationActivitySchema;
165
229
  const notificationSchema = Joi.object({
166
230
  type: Joi.string().valid(...Object.values(TYPES)),
167
231
  id: Joi.string().optional(),
@@ -182,6 +246,8 @@ const notificationSchema = Joi.object({
182
246
  actions: Joi.array().items(actionSchema).default([]),
183
247
  appInfo: Joi.object().optional(),
184
248
  poweredBy: Joi.object().optional(),
249
+ // notification activity v1.16.41
250
+ activity: notificationActivitySchema.optional(),
185
251
  })
186
252
  .required()
187
253
  .meta({ className: 'TNotification' });
@@ -225,6 +291,7 @@ exports.validateMessage = messageSchema.validateAsync.bind(messageSchema);
225
291
  exports.validateChannelEvent = channelEventSchema.validateAsync.bind(channelEventSchema);
226
292
  exports.validateOption = optionSchema.validateAsync.bind(optionSchema);
227
293
  exports.validateEmail = schemaEmail.validateAsync.bind(schemaEmail);
294
+ exports.validateActivity = notificationActivitySchema.validateAsync.bind(notificationActivitySchema);
228
295
  exports.default = {
229
296
  validateReceiver: exports.validateReceiver,
230
297
  validateNotification: exports.validateNotification,
@@ -246,4 +313,9 @@ exports.default = {
246
313
  optionSchema,
247
314
  channelEventSchema,
248
315
  NOTIFICATION_TYPES: TYPES,
316
+ ACTIVITY_TYPES,
317
+ ACTIVITY_TARGET_TYPES,
318
+ validateActivity: exports.validateActivity,
319
+ notificationActivitySchema,
320
+ activityTargetSchema,
249
321
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.41-beta-20250325-154552-2bf78c26",
6
+ "version": "1.16.41-beta-20250329-232306-53c45e3b",
7
7
  "description": "graphql client to read/write data on abt node",
8
8
  "main": "lib/index.js",
9
9
  "typings": "lib/index.d.ts",
@@ -27,16 +27,16 @@
27
27
  "author": "linchen1987 <linchen.1987@foxmail.com> (http://github.com/linchen1987)",
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@abtnode/client": "1.16.41-beta-20250325-154552-2bf78c26",
31
- "@abtnode/constant": "1.16.41-beta-20250325-154552-2bf78c26",
32
- "@abtnode/util": "1.16.41-beta-20250325-154552-2bf78c26",
30
+ "@abtnode/client": "1.16.41-beta-20250329-232306-53c45e3b",
31
+ "@abtnode/constant": "1.16.41-beta-20250329-232306-53c45e3b",
32
+ "@abtnode/util": "1.16.41-beta-20250329-232306-53c45e3b",
33
33
  "@arcblock/did": "1.19.15",
34
34
  "@arcblock/did-auth": "1.19.15",
35
35
  "@arcblock/jwt": "1.19.15",
36
36
  "@arcblock/ws": "1.19.15",
37
- "@blocklet/constant": "1.16.41-beta-20250325-154552-2bf78c26",
38
- "@blocklet/env": "1.16.41-beta-20250325-154552-2bf78c26",
39
- "@blocklet/meta": "1.16.41-beta-20250325-154552-2bf78c26",
37
+ "@blocklet/constant": "1.16.41-beta-20250329-232306-53c45e3b",
38
+ "@blocklet/env": "1.16.41-beta-20250329-232306-53c45e3b",
39
+ "@blocklet/meta": "1.16.41-beta-20250329-232306-53c45e3b",
40
40
  "@did-connect/authenticator": "^2.2.7",
41
41
  "@did-connect/handler": "^2.2.7",
42
42
  "@nedb/core": "^2.1.5",
@@ -82,5 +82,5 @@
82
82
  "ts-node": "^10.9.1",
83
83
  "typescript": "^5.6.3"
84
84
  },
85
- "gitHead": "5342bdb7acbcba223a94817f686331c1beeb49c0"
85
+ "gitHead": "498c1ee3e88a4db6bd62f62a75d2a8e48f7db85f"
86
86
  }