@objectstack/service-feed 4.0.4 → 4.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.
package/dist/index.js CHANGED
@@ -224,7 +224,6 @@ var InMemoryFeedAdapter = class {
224
224
  // src/objects/feed-item.object.ts
225
225
  import { ObjectSchema, Field } from "@objectstack/spec/data";
226
226
  var FeedItem = ObjectSchema.create({
227
- namespace: "sys",
228
227
  name: "feed_item",
229
228
  label: "Feed Item",
230
229
  pluralLabel: "Feed Items",
@@ -303,8 +302,8 @@ var FeedItem = ObjectSchema.create({
303
302
  label: "Reactions",
304
303
  description: "Array of emoji reaction objects (JSON)"
305
304
  }),
306
- parent_id: Field.text({
307
- label: "Parent Feed Item ID",
305
+ parent_id: Field.lookup("feed_item", {
306
+ label: "Parent Feed Item",
308
307
  description: "For threaded replies"
309
308
  }),
310
309
  reply_count: Field.number({
@@ -357,7 +356,6 @@ var FeedItem = ObjectSchema.create({
357
356
  // src/objects/feed-reaction.object.ts
358
357
  import { ObjectSchema as ObjectSchema2, Field as Field2 } from "@objectstack/spec/data";
359
358
  var FeedReaction = ObjectSchema2.create({
360
- namespace: "sys",
361
359
  name: "feed_reaction",
362
360
  label: "Feed Reaction",
363
361
  pluralLabel: "Feed Reactions",
@@ -371,8 +369,8 @@ var FeedReaction = ObjectSchema2.create({
371
369
  required: true,
372
370
  readonly: true
373
371
  }),
374
- feed_item_id: Field2.text({
375
- label: "Feed Item ID",
372
+ feed_item_id: Field2.lookup("feed_item", {
373
+ label: "Feed Item",
376
374
  required: true
377
375
  }),
378
376
  emoji: Field2.text({
@@ -380,8 +378,8 @@ var FeedReaction = ObjectSchema2.create({
380
378
  required: true,
381
379
  description: 'Emoji character or shortcode (e.g., "\u{1F44D}", ":thumbsup:")'
382
380
  }),
383
- user_id: Field2.text({
384
- label: "User ID",
381
+ user_id: Field2.lookup("sys_user", {
382
+ label: "User",
385
383
  required: true
386
384
  }),
387
385
  created_at: Field2.datetime({
@@ -408,7 +406,6 @@ var FeedReaction = ObjectSchema2.create({
408
406
  // src/objects/record-subscription.object.ts
409
407
  import { ObjectSchema as ObjectSchema3, Field as Field3 } from "@objectstack/spec/data";
410
408
  var RecordSubscription = ObjectSchema3.create({
411
- namespace: "sys",
412
409
  name: "record_subscription",
413
410
  label: "Record Subscription",
414
411
  pluralLabel: "Record Subscriptions",
@@ -430,8 +427,8 @@ var RecordSubscription = ObjectSchema3.create({
430
427
  label: "Record ID",
431
428
  required: true
432
429
  }),
433
- user_id: Field3.text({
434
- label: "User ID",
430
+ user_id: Field3.lookup("sys_user", {
431
+ label: "User",
435
432
  required: true
436
433
  }),
437
434
  events: Field3.textarea({
@@ -484,6 +481,7 @@ var FeedServicePlugin = class {
484
481
  name: "Feed Service",
485
482
  version: "1.0.0",
486
483
  type: "plugin",
484
+ scope: "project",
487
485
  objects: [FeedItem, FeedReaction, RecordSubscription]
488
486
  });
489
487
  ctx.logger.info("FeedServicePlugin: registered in-memory feed adapter");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/in-memory-feed-adapter.ts","../src/objects/feed-item.object.ts","../src/objects/feed-reaction.object.ts","../src/objects/record-subscription.object.ts","../src/feed-service-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n IFeedService,\n CreateFeedItemInput,\n UpdateFeedItemInput,\n ListFeedOptions,\n FeedListResult,\n SubscribeInput,\n} from '@objectstack/spec/contracts';\nimport type { FeedItem, Reaction } from '@objectstack/spec/data';\nimport type { RecordSubscription } from '@objectstack/spec/data';\n\n/**\n * Configuration options for InMemoryFeedAdapter.\n */\nexport interface InMemoryFeedAdapterOptions {\n /** Maximum number of feed items to store (0 = unlimited) */\n maxItems?: number;\n}\n\n/**\n * In-memory Feed/Chatter adapter implementing IFeedService.\n *\n * Uses Map-backed stores for feed items, reactions, and subscriptions.\n * Supports feed CRUD, emoji reactions, threaded replies, and record subscriptions.\n *\n * Suitable for single-process environments, development, and testing.\n * For production deployments, use a database-backed adapter.\n *\n * @example\n * ```ts\n * const feed = new InMemoryFeedAdapter();\n *\n * const item = await feed.createFeedItem({\n * object: 'account',\n * recordId: 'rec_123',\n * type: 'comment',\n * actor: { type: 'user', id: 'user_1', name: 'Alice' },\n * body: 'Great progress!',\n * });\n *\n * const list = await feed.listFeed({ object: 'account', recordId: 'rec_123' });\n * ```\n */\nexport class InMemoryFeedAdapter implements IFeedService {\n private readonly items = new Map<string, FeedItem>();\n private counter = 0;\n private readonly subscriptions = new Map<string, RecordSubscription>();\n private readonly maxItems: number;\n\n constructor(options: InMemoryFeedAdapterOptions = {}) {\n this.maxItems = options.maxItems ?? 0;\n }\n\n async listFeed(options: ListFeedOptions): Promise<FeedListResult> {\n let items = Array.from(this.items.values()).filter(\n (item) => item.object === options.object && item.recordId === options.recordId,\n );\n\n // Apply filter\n if (options.filter && options.filter !== 'all') {\n items = items.filter((item) => {\n switch (options.filter) {\n case 'comments_only':\n return item.type === 'comment';\n case 'changes_only':\n return item.type === 'field_change';\n case 'tasks_only':\n return item.type === 'task';\n default:\n return true;\n }\n });\n }\n\n // Sort reverse chronological (stable: break ties by ID descending)\n items.sort((a, b) => {\n const timeDiff = new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n if (timeDiff !== 0) return timeDiff;\n return b.id < a.id ? -1 : b.id > a.id ? 1 : 0;\n });\n\n const total = items.length;\n const limit = options.limit ?? 20;\n\n // Cursor-based pagination\n let startIndex = 0;\n if (options.cursor) {\n const cursorIndex = items.findIndex((item) => item.id === options.cursor);\n if (cursorIndex >= 0) {\n startIndex = cursorIndex + 1;\n }\n }\n\n const page = items.slice(startIndex, startIndex + limit);\n const hasMore = startIndex + limit < total;\n\n return {\n items: page,\n total,\n nextCursor: hasMore && page.length > 0 ? page[page.length - 1].id : undefined,\n hasMore,\n };\n }\n\n async createFeedItem(input: CreateFeedItemInput): Promise<FeedItem> {\n if (this.maxItems > 0 && this.items.size >= this.maxItems) {\n throw new Error(\n `Maximum feed item limit reached (${this.maxItems}). ` +\n 'Delete existing items before adding new ones.',\n );\n }\n\n const id = `feed_${++this.counter}`;\n const now = new Date().toISOString();\n\n // Increment parent reply count if threading\n if (input.parentId) {\n const parent = this.items.get(input.parentId);\n if (!parent) {\n throw new Error(`Parent feed item not found: ${input.parentId}`);\n }\n const updatedParent: FeedItem = {\n ...parent,\n replyCount: (parent.replyCount ?? 0) + 1,\n updatedAt: now,\n };\n this.items.set(parent.id, updatedParent);\n }\n\n const item: FeedItem = {\n id,\n type: input.type as FeedItem['type'],\n object: input.object,\n recordId: input.recordId,\n actor: {\n type: input.actor.type,\n id: input.actor.id,\n ...(input.actor.name ? { name: input.actor.name } : {}),\n ...(input.actor.avatarUrl ? { avatarUrl: input.actor.avatarUrl } : {}),\n },\n ...(input.body !== undefined ? { body: input.body } : {}),\n ...(input.mentions ? { mentions: input.mentions } : {}),\n ...(input.changes ? { changes: input.changes } : {}),\n ...(input.parentId ? { parentId: input.parentId } : {}),\n visibility: input.visibility ?? 'public',\n replyCount: 0,\n isEdited: false,\n pinned: false,\n starred: false,\n createdAt: now,\n };\n\n this.items.set(id, item);\n return item;\n }\n\n async updateFeedItem(feedId: string, input: UpdateFeedItemInput): Promise<FeedItem> {\n const existing = this.items.get(feedId);\n if (!existing) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n const now = new Date().toISOString();\n const updated: FeedItem = {\n ...existing,\n ...(input.body !== undefined ? { body: input.body } : {}),\n ...(input.mentions !== undefined ? { mentions: input.mentions } : {}),\n ...(input.visibility !== undefined ? { visibility: input.visibility } : {}),\n updatedAt: now,\n editedAt: now,\n isEdited: true,\n };\n\n this.items.set(feedId, updated);\n return updated;\n }\n\n async deleteFeedItem(feedId: string): Promise<void> {\n const item = this.items.get(feedId);\n if (!item) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n // Decrement parent reply count if threaded\n if (item.parentId) {\n const parent = this.items.get(item.parentId);\n if (parent) {\n const updatedParent: FeedItem = {\n ...parent,\n replyCount: Math.max(0, (parent.replyCount ?? 0) - 1),\n };\n this.items.set(parent.id, updatedParent);\n }\n }\n\n this.items.delete(feedId);\n }\n\n async getFeedItem(feedId: string): Promise<FeedItem | null> {\n return this.items.get(feedId) ?? null;\n }\n\n async addReaction(feedId: string, emoji: string, userId: string): Promise<Reaction[]> {\n const item = this.items.get(feedId);\n if (!item) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n const reactions = [...(item.reactions ?? [])];\n const existing = reactions.find((r) => r.emoji === emoji);\n\n if (existing) {\n if (existing.userIds.includes(userId)) {\n throw new Error(`Reaction already exists: ${emoji} by ${userId}`);\n }\n existing.userIds = [...existing.userIds, userId];\n existing.count = existing.userIds.length;\n } else {\n reactions.push({ emoji, userIds: [userId], count: 1 });\n }\n\n const updated: FeedItem = { ...item, reactions };\n this.items.set(feedId, updated);\n return reactions;\n }\n\n async removeReaction(feedId: string, emoji: string, userId: string): Promise<Reaction[]> {\n const item = this.items.get(feedId);\n if (!item) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n let reactions = [...(item.reactions ?? [])];\n const existing = reactions.find((r) => r.emoji === emoji);\n\n if (!existing || !existing.userIds.includes(userId)) {\n throw new Error(`Reaction not found: ${emoji} by ${userId}`);\n }\n\n existing.userIds = existing.userIds.filter((id) => id !== userId);\n existing.count = existing.userIds.length;\n\n // Remove reaction entry if no users left\n reactions = reactions.filter((r) => r.count > 0);\n\n const updated: FeedItem = { ...item, reactions };\n this.items.set(feedId, updated);\n return reactions;\n }\n\n async subscribe(input: SubscribeInput): Promise<RecordSubscription> {\n const key = this.subscriptionKey(input.object, input.recordId, input.userId);\n const existing = this.findSubscription(input.object, input.recordId, input.userId);\n\n if (existing) {\n // Update existing subscription\n const updated: RecordSubscription = {\n ...existing,\n events: input.events ?? existing.events,\n channels: input.channels ?? existing.channels,\n active: true,\n };\n this.subscriptions.set(key, updated);\n return updated;\n }\n\n const now = new Date().toISOString();\n const subscription: RecordSubscription = {\n object: input.object,\n recordId: input.recordId,\n userId: input.userId,\n events: input.events ?? ['all'],\n channels: input.channels ?? ['in_app'],\n active: true,\n createdAt: now,\n };\n\n this.subscriptions.set(key, subscription);\n return subscription;\n }\n\n async unsubscribe(object: string, recordId: string, userId: string): Promise<boolean> {\n const key = this.subscriptionKey(object, recordId, userId);\n return this.subscriptions.delete(key);\n }\n\n async getSubscription(\n object: string,\n recordId: string,\n userId: string,\n ): Promise<RecordSubscription | null> {\n return this.findSubscription(object, recordId, userId);\n }\n\n /**\n * Get the total number of feed items stored.\n */\n getItemCount(): number {\n return this.items.size;\n }\n\n /**\n * Get the total number of subscriptions stored.\n */\n getSubscriptionCount(): number {\n return this.subscriptions.size;\n }\n\n private subscriptionKey(object: string, recordId: string, userId: string): string {\n return `${object}:${recordId}:${userId}`;\n }\n\n private findSubscription(\n object: string,\n recordId: string,\n userId: string,\n ): RecordSubscription | null {\n const key = this.subscriptionKey(object, recordId, userId);\n return this.subscriptions.get(key) ?? null;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Feed Item Object\n *\n * System object for storing feed/chatter items including comments,\n * field changes, tasks, events, and system activities.\n *\n * Belongs to `service-feed` package per \"protocol + service ownership\" pattern.\n */\nexport const FeedItem = ObjectSchema.create({\n namespace: 'sys',\n name: 'feed_item',\n label: 'Feed Item',\n pluralLabel: 'Feed Items',\n icon: 'message-square',\n description: 'Unified activity timeline entries (comments, field changes, tasks, events)',\n titleFormat: '{type}: {body}',\n compactLayout: ['type', 'object', 'record_id', 'created_at'],\n\n fields: {\n id: Field.text({\n label: 'Feed Item ID',\n required: true,\n readonly: true,\n }),\n\n type: Field.select({\n label: 'Type',\n required: true,\n options: [\n { label: 'Comment', value: 'comment' },\n { label: 'Field Change', value: 'field_change' },\n { label: 'Task', value: 'task' },\n { label: 'Event', value: 'event' },\n { label: 'Email', value: 'email' },\n { label: 'Call', value: 'call' },\n { label: 'Note', value: 'note' },\n { label: 'File', value: 'file' },\n { label: 'Record Create', value: 'record_create' },\n { label: 'Record Delete', value: 'record_delete' },\n { label: 'Approval', value: 'approval' },\n { label: 'Sharing', value: 'sharing' },\n { label: 'System', value: 'system' },\n ],\n }),\n\n object: Field.text({\n label: 'Object Name',\n required: true,\n searchable: true,\n }),\n\n record_id: Field.text({\n label: 'Record ID',\n required: true,\n searchable: true,\n }),\n\n actor_type: Field.select({\n label: 'Actor Type',\n required: true,\n options: [\n { label: 'User', value: 'user' },\n { label: 'System', value: 'system' },\n { label: 'Service', value: 'service' },\n { label: 'Automation', value: 'automation' },\n ],\n }),\n\n actor_id: Field.text({\n label: 'Actor ID',\n required: true,\n }),\n\n actor_name: Field.text({\n label: 'Actor Name',\n }),\n\n actor_avatar_url: Field.url({\n label: 'Actor Avatar URL',\n }),\n\n body: Field.textarea({\n label: 'Body',\n description: 'Rich text body (Markdown supported)',\n }),\n\n mentions: Field.textarea({\n label: 'Mentions',\n description: 'Array of @mention objects (JSON)',\n }),\n\n changes: Field.textarea({\n label: 'Field Changes',\n description: 'Array of field change entries (JSON)',\n }),\n\n reactions: Field.textarea({\n label: 'Reactions',\n description: 'Array of emoji reaction objects (JSON)',\n }),\n\n parent_id: Field.text({\n label: 'Parent Feed Item ID',\n description: 'For threaded replies',\n }),\n\n reply_count: Field.number({\n label: 'Reply Count',\n defaultValue: 0,\n }),\n\n visibility: Field.select({\n label: 'Visibility',\n defaultValue: 'public',\n options: [\n { label: 'Public', value: 'public' },\n { label: 'Internal', value: 'internal' },\n { label: 'Private', value: 'private' },\n ],\n }),\n\n is_edited: Field.boolean({\n label: 'Is Edited',\n defaultValue: false,\n }),\n\n edited_at: Field.datetime({\n label: 'Edited At',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['object', 'record_id'], unique: false },\n { fields: ['actor_id'], unique: false },\n { fields: ['parent_id'], unique: false },\n { fields: ['created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Feed Reaction Object\n *\n * System object for storing individual emoji reactions on feed items.\n * Each row represents one user's reaction on one feed item.\n *\n * Belongs to `service-feed` package per \"protocol + service ownership\" pattern.\n */\nexport const FeedReaction = ObjectSchema.create({\n namespace: 'sys',\n name: 'feed_reaction',\n label: 'Feed Reaction',\n pluralLabel: 'Feed Reactions',\n icon: 'smile',\n description: 'Emoji reactions on feed items',\n titleFormat: '{emoji} by {user_id}',\n compactLayout: ['feed_item_id', 'emoji', 'user_id'],\n\n fields: {\n id: Field.text({\n label: 'Reaction ID',\n required: true,\n readonly: true,\n }),\n\n feed_item_id: Field.text({\n label: 'Feed Item ID',\n required: true,\n }),\n\n emoji: Field.text({\n label: 'Emoji',\n required: true,\n description: 'Emoji character or shortcode (e.g., \"👍\", \":thumbsup:\")',\n }),\n\n user_id: Field.text({\n label: 'User ID',\n required: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['feed_item_id', 'emoji', 'user_id'], unique: true },\n { fields: ['feed_item_id'], unique: false },\n { fields: ['user_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Record Subscription Object\n *\n * System object for storing record-level notification subscriptions.\n * Enables Airtable-style bell icon for record change notifications.\n *\n * Belongs to `service-feed` package per \"protocol + service ownership\" pattern.\n */\nexport const RecordSubscription = ObjectSchema.create({\n namespace: 'sys',\n name: 'record_subscription',\n label: 'Record Subscription',\n pluralLabel: 'Record Subscriptions',\n icon: 'bell',\n description: 'Record-level notification subscriptions for feed events',\n titleFormat: '{object}/{record_id} — {user_id}',\n compactLayout: ['object', 'record_id', 'user_id', 'active'],\n\n fields: {\n id: Field.text({\n label: 'Subscription ID',\n required: true,\n readonly: true,\n }),\n\n object: Field.text({\n label: 'Object Name',\n required: true,\n }),\n\n record_id: Field.text({\n label: 'Record ID',\n required: true,\n }),\n\n user_id: Field.text({\n label: 'User ID',\n required: true,\n }),\n\n events: Field.textarea({\n label: 'Subscribed Events',\n description: 'Array of event types: comment, mention, field_change, task, approval, all (JSON)',\n }),\n\n channels: Field.textarea({\n label: 'Notification Channels',\n description: 'Array of channels: in_app, email, push, slack (JSON)',\n }),\n\n active: Field.boolean({\n label: 'Active',\n defaultValue: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['object', 'record_id', 'user_id'], unique: true },\n { fields: ['user_id'], unique: false },\n { fields: ['object', 'record_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { InMemoryFeedAdapter } from './in-memory-feed-adapter.js';\nimport type { InMemoryFeedAdapterOptions } from './in-memory-feed-adapter.js';\nimport { FeedItem, FeedReaction, RecordSubscription } from './objects/index.js';\n\n/**\n * Configuration options for the FeedServicePlugin.\n */\nexport interface FeedServicePluginOptions {\n /** Feed adapter type (default: 'memory') */\n adapter?: 'memory';\n /** Options for the in-memory adapter */\n memory?: InMemoryFeedAdapterOptions;\n}\n\n/**\n * FeedServicePlugin — Production IFeedService implementation.\n *\n * Registers a Feed/Chatter service with the kernel during the init phase.\n * Currently supports in-memory storage for single-process environments.\n *\n * @example\n * ```ts\n * import { ObjectKernel } from '@objectstack/core';\n * import { FeedServicePlugin } from '@objectstack/service-feed';\n *\n * const kernel = new ObjectKernel();\n * kernel.use(new FeedServicePlugin());\n * await kernel.bootstrap();\n *\n * const feed = kernel.getService('feed');\n * const item = await feed.createFeedItem({\n * object: 'account',\n * recordId: 'rec_123',\n * type: 'comment',\n * actor: { type: 'user', id: 'user_1', name: 'Alice' },\n * body: 'Great progress!',\n * });\n * ```\n */\nexport class FeedServicePlugin implements Plugin {\n name = 'com.objectstack.service.feed';\n version = '1.0.0';\n type = 'standard';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private readonly options: FeedServicePluginOptions;\n\n constructor(options: FeedServicePluginOptions = {}) {\n this.options = { adapter: 'memory', ...options };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n const feed = new InMemoryFeedAdapter(this.options.memory);\n ctx.registerService('feed', feed);\n\n // Register feed system objects via the manifest service.\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service.feed',\n name: 'Feed Service',\n version: '1.0.0',\n type: 'plugin',\n objects: [FeedItem, FeedReaction, RecordSubscription],\n });\n\n ctx.logger.info('FeedServicePlugin: registered in-memory feed adapter');\n }\n}\n"],"mappings":"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","names":["ObjectSchema","Field","ObjectSchema","Field"]}
1
+ {"version":3,"sources":["../src/in-memory-feed-adapter.ts","../src/objects/feed-item.object.ts","../src/objects/feed-reaction.object.ts","../src/objects/record-subscription.object.ts","../src/feed-service-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n IFeedService,\n CreateFeedItemInput,\n UpdateFeedItemInput,\n ListFeedOptions,\n FeedListResult,\n SubscribeInput,\n} from '@objectstack/spec/contracts';\nimport type { FeedItem, Reaction } from '@objectstack/spec/data';\nimport type { RecordSubscription } from '@objectstack/spec/data';\n\n/**\n * Configuration options for InMemoryFeedAdapter.\n */\nexport interface InMemoryFeedAdapterOptions {\n /** Maximum number of feed items to store (0 = unlimited) */\n maxItems?: number;\n}\n\n/**\n * In-memory Feed/Chatter adapter implementing IFeedService.\n *\n * Uses Map-backed stores for feed items, reactions, and subscriptions.\n * Supports feed CRUD, emoji reactions, threaded replies, and record subscriptions.\n *\n * Suitable for single-process environments, development, and testing.\n * For production deployments, use a database-backed adapter.\n *\n * @example\n * ```ts\n * const feed = new InMemoryFeedAdapter();\n *\n * const item = await feed.createFeedItem({\n * object: 'account',\n * recordId: 'rec_123',\n * type: 'comment',\n * actor: { type: 'user', id: 'user_1', name: 'Alice' },\n * body: 'Great progress!',\n * });\n *\n * const list = await feed.listFeed({ object: 'account', recordId: 'rec_123' });\n * ```\n */\nexport class InMemoryFeedAdapter implements IFeedService {\n private readonly items = new Map<string, FeedItem>();\n private counter = 0;\n private readonly subscriptions = new Map<string, RecordSubscription>();\n private readonly maxItems: number;\n\n constructor(options: InMemoryFeedAdapterOptions = {}) {\n this.maxItems = options.maxItems ?? 0;\n }\n\n async listFeed(options: ListFeedOptions): Promise<FeedListResult> {\n let items = Array.from(this.items.values()).filter(\n (item) => item.object === options.object && item.recordId === options.recordId,\n );\n\n // Apply filter\n if (options.filter && options.filter !== 'all') {\n items = items.filter((item) => {\n switch (options.filter) {\n case 'comments_only':\n return item.type === 'comment';\n case 'changes_only':\n return item.type === 'field_change';\n case 'tasks_only':\n return item.type === 'task';\n default:\n return true;\n }\n });\n }\n\n // Sort reverse chronological (stable: break ties by ID descending)\n items.sort((a, b) => {\n const timeDiff = new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n if (timeDiff !== 0) return timeDiff;\n return b.id < a.id ? -1 : b.id > a.id ? 1 : 0;\n });\n\n const total = items.length;\n const limit = options.limit ?? 20;\n\n // Cursor-based pagination\n let startIndex = 0;\n if (options.cursor) {\n const cursorIndex = items.findIndex((item) => item.id === options.cursor);\n if (cursorIndex >= 0) {\n startIndex = cursorIndex + 1;\n }\n }\n\n const page = items.slice(startIndex, startIndex + limit);\n const hasMore = startIndex + limit < total;\n\n return {\n items: page,\n total,\n nextCursor: hasMore && page.length > 0 ? page[page.length - 1].id : undefined,\n hasMore,\n };\n }\n\n async createFeedItem(input: CreateFeedItemInput): Promise<FeedItem> {\n if (this.maxItems > 0 && this.items.size >= this.maxItems) {\n throw new Error(\n `Maximum feed item limit reached (${this.maxItems}). ` +\n 'Delete existing items before adding new ones.',\n );\n }\n\n const id = `feed_${++this.counter}`;\n const now = new Date().toISOString();\n\n // Increment parent reply count if threading\n if (input.parentId) {\n const parent = this.items.get(input.parentId);\n if (!parent) {\n throw new Error(`Parent feed item not found: ${input.parentId}`);\n }\n const updatedParent: FeedItem = {\n ...parent,\n replyCount: (parent.replyCount ?? 0) + 1,\n updatedAt: now,\n };\n this.items.set(parent.id, updatedParent);\n }\n\n const item: FeedItem = {\n id,\n type: input.type as FeedItem['type'],\n object: input.object,\n recordId: input.recordId,\n actor: {\n type: input.actor.type,\n id: input.actor.id,\n ...(input.actor.name ? { name: input.actor.name } : {}),\n ...(input.actor.avatarUrl ? { avatarUrl: input.actor.avatarUrl } : {}),\n },\n ...(input.body !== undefined ? { body: input.body } : {}),\n ...(input.mentions ? { mentions: input.mentions } : {}),\n ...(input.changes ? { changes: input.changes } : {}),\n ...(input.parentId ? { parentId: input.parentId } : {}),\n visibility: input.visibility ?? 'public',\n replyCount: 0,\n isEdited: false,\n pinned: false,\n starred: false,\n createdAt: now,\n };\n\n this.items.set(id, item);\n return item;\n }\n\n async updateFeedItem(feedId: string, input: UpdateFeedItemInput): Promise<FeedItem> {\n const existing = this.items.get(feedId);\n if (!existing) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n const now = new Date().toISOString();\n const updated: FeedItem = {\n ...existing,\n ...(input.body !== undefined ? { body: input.body } : {}),\n ...(input.mentions !== undefined ? { mentions: input.mentions } : {}),\n ...(input.visibility !== undefined ? { visibility: input.visibility } : {}),\n updatedAt: now,\n editedAt: now,\n isEdited: true,\n };\n\n this.items.set(feedId, updated);\n return updated;\n }\n\n async deleteFeedItem(feedId: string): Promise<void> {\n const item = this.items.get(feedId);\n if (!item) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n // Decrement parent reply count if threaded\n if (item.parentId) {\n const parent = this.items.get(item.parentId);\n if (parent) {\n const updatedParent: FeedItem = {\n ...parent,\n replyCount: Math.max(0, (parent.replyCount ?? 0) - 1),\n };\n this.items.set(parent.id, updatedParent);\n }\n }\n\n this.items.delete(feedId);\n }\n\n async getFeedItem(feedId: string): Promise<FeedItem | null> {\n return this.items.get(feedId) ?? null;\n }\n\n async addReaction(feedId: string, emoji: string, userId: string): Promise<Reaction[]> {\n const item = this.items.get(feedId);\n if (!item) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n const reactions = [...(item.reactions ?? [])];\n const existing = reactions.find((r) => r.emoji === emoji);\n\n if (existing) {\n if (existing.userIds.includes(userId)) {\n throw new Error(`Reaction already exists: ${emoji} by ${userId}`);\n }\n existing.userIds = [...existing.userIds, userId];\n existing.count = existing.userIds.length;\n } else {\n reactions.push({ emoji, userIds: [userId], count: 1 });\n }\n\n const updated: FeedItem = { ...item, reactions };\n this.items.set(feedId, updated);\n return reactions;\n }\n\n async removeReaction(feedId: string, emoji: string, userId: string): Promise<Reaction[]> {\n const item = this.items.get(feedId);\n if (!item) {\n throw new Error(`Feed item not found: ${feedId}`);\n }\n\n let reactions = [...(item.reactions ?? [])];\n const existing = reactions.find((r) => r.emoji === emoji);\n\n if (!existing || !existing.userIds.includes(userId)) {\n throw new Error(`Reaction not found: ${emoji} by ${userId}`);\n }\n\n existing.userIds = existing.userIds.filter((id) => id !== userId);\n existing.count = existing.userIds.length;\n\n // Remove reaction entry if no users left\n reactions = reactions.filter((r) => r.count > 0);\n\n const updated: FeedItem = { ...item, reactions };\n this.items.set(feedId, updated);\n return reactions;\n }\n\n async subscribe(input: SubscribeInput): Promise<RecordSubscription> {\n const key = this.subscriptionKey(input.object, input.recordId, input.userId);\n const existing = this.findSubscription(input.object, input.recordId, input.userId);\n\n if (existing) {\n // Update existing subscription\n const updated: RecordSubscription = {\n ...existing,\n events: input.events ?? existing.events,\n channels: input.channels ?? existing.channels,\n active: true,\n };\n this.subscriptions.set(key, updated);\n return updated;\n }\n\n const now = new Date().toISOString();\n const subscription: RecordSubscription = {\n object: input.object,\n recordId: input.recordId,\n userId: input.userId,\n events: input.events ?? ['all'],\n channels: input.channels ?? ['in_app'],\n active: true,\n createdAt: now,\n };\n\n this.subscriptions.set(key, subscription);\n return subscription;\n }\n\n async unsubscribe(object: string, recordId: string, userId: string): Promise<boolean> {\n const key = this.subscriptionKey(object, recordId, userId);\n return this.subscriptions.delete(key);\n }\n\n async getSubscription(\n object: string,\n recordId: string,\n userId: string,\n ): Promise<RecordSubscription | null> {\n return this.findSubscription(object, recordId, userId);\n }\n\n /**\n * Get the total number of feed items stored.\n */\n getItemCount(): number {\n return this.items.size;\n }\n\n /**\n * Get the total number of subscriptions stored.\n */\n getSubscriptionCount(): number {\n return this.subscriptions.size;\n }\n\n private subscriptionKey(object: string, recordId: string, userId: string): string {\n return `${object}:${recordId}:${userId}`;\n }\n\n private findSubscription(\n object: string,\n recordId: string,\n userId: string,\n ): RecordSubscription | null {\n const key = this.subscriptionKey(object, recordId, userId);\n return this.subscriptions.get(key) ?? null;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Feed Item Object\n *\n * System object for storing feed/chatter items including comments,\n * field changes, tasks, events, and system activities.\n *\n * Belongs to `service-feed` package per \"protocol + service ownership\" pattern.\n */\nexport const FeedItem = ObjectSchema.create({\n name: 'feed_item',\n label: 'Feed Item',\n pluralLabel: 'Feed Items',\n icon: 'message-square',\n description: 'Unified activity timeline entries (comments, field changes, tasks, events)',\n titleFormat: '{type}: {body}',\n compactLayout: ['type', 'object', 'record_id', 'created_at'],\n\n fields: {\n id: Field.text({\n label: 'Feed Item ID',\n required: true,\n readonly: true,\n }),\n\n type: Field.select({\n label: 'Type',\n required: true,\n options: [\n { label: 'Comment', value: 'comment' },\n { label: 'Field Change', value: 'field_change' },\n { label: 'Task', value: 'task' },\n { label: 'Event', value: 'event' },\n { label: 'Email', value: 'email' },\n { label: 'Call', value: 'call' },\n { label: 'Note', value: 'note' },\n { label: 'File', value: 'file' },\n { label: 'Record Create', value: 'record_create' },\n { label: 'Record Delete', value: 'record_delete' },\n { label: 'Approval', value: 'approval' },\n { label: 'Sharing', value: 'sharing' },\n { label: 'System', value: 'system' },\n ],\n }),\n\n object: Field.text({\n label: 'Object Name',\n required: true,\n searchable: true,\n }),\n\n record_id: Field.text({\n label: 'Record ID',\n required: true,\n searchable: true,\n }),\n\n actor_type: Field.select({\n label: 'Actor Type',\n required: true,\n options: [\n { label: 'User', value: 'user' },\n { label: 'System', value: 'system' },\n { label: 'Service', value: 'service' },\n { label: 'Automation', value: 'automation' },\n ],\n }),\n\n actor_id: Field.text({\n label: 'Actor ID',\n required: true,\n }),\n\n actor_name: Field.text({\n label: 'Actor Name',\n }),\n\n actor_avatar_url: Field.url({\n label: 'Actor Avatar URL',\n }),\n\n body: Field.textarea({\n label: 'Body',\n description: 'Rich text body (Markdown supported)',\n }),\n\n mentions: Field.textarea({\n label: 'Mentions',\n description: 'Array of @mention objects (JSON)',\n }),\n\n changes: Field.textarea({\n label: 'Field Changes',\n description: 'Array of field change entries (JSON)',\n }),\n\n reactions: Field.textarea({\n label: 'Reactions',\n description: 'Array of emoji reaction objects (JSON)',\n }),\n\n parent_id: Field.lookup('feed_item', {\n label: 'Parent Feed Item',\n description: 'For threaded replies',\n }),\n\n reply_count: Field.number({\n label: 'Reply Count',\n defaultValue: 0,\n }),\n\n visibility: Field.select({\n label: 'Visibility',\n defaultValue: 'public',\n options: [\n { label: 'Public', value: 'public' },\n { label: 'Internal', value: 'internal' },\n { label: 'Private', value: 'private' },\n ],\n }),\n\n is_edited: Field.boolean({\n label: 'Is Edited',\n defaultValue: false,\n }),\n\n edited_at: Field.datetime({\n label: 'Edited At',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['object', 'record_id'], unique: false },\n { fields: ['actor_id'], unique: false },\n { fields: ['parent_id'], unique: false },\n { fields: ['created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Feed Reaction Object\n *\n * System object for storing individual emoji reactions on feed items.\n * Each row represents one user's reaction on one feed item.\n *\n * Belongs to `service-feed` package per \"protocol + service ownership\" pattern.\n */\nexport const FeedReaction = ObjectSchema.create({\n name: 'feed_reaction',\n label: 'Feed Reaction',\n pluralLabel: 'Feed Reactions',\n icon: 'smile',\n description: 'Emoji reactions on feed items',\n titleFormat: '{emoji} by {user_id}',\n compactLayout: ['feed_item_id', 'emoji', 'user_id'],\n\n fields: {\n id: Field.text({\n label: 'Reaction ID',\n required: true,\n readonly: true,\n }),\n\n feed_item_id: Field.lookup('feed_item', {\n label: 'Feed Item',\n required: true,\n }),\n\n emoji: Field.text({\n label: 'Emoji',\n required: true,\n description: 'Emoji character or shortcode (e.g., \"👍\", \":thumbsup:\")',\n }),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n required: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['feed_item_id', 'emoji', 'user_id'], unique: true },\n { fields: ['feed_item_id'], unique: false },\n { fields: ['user_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Record Subscription Object\n *\n * System object for storing record-level notification subscriptions.\n * Enables Airtable-style bell icon for record change notifications.\n *\n * Belongs to `service-feed` package per \"protocol + service ownership\" pattern.\n */\nexport const RecordSubscription = ObjectSchema.create({\n name: 'record_subscription',\n label: 'Record Subscription',\n pluralLabel: 'Record Subscriptions',\n icon: 'bell',\n description: 'Record-level notification subscriptions for feed events',\n titleFormat: '{object}/{record_id} — {user_id}',\n compactLayout: ['object', 'record_id', 'user_id', 'active'],\n\n fields: {\n id: Field.text({\n label: 'Subscription ID',\n required: true,\n readonly: true,\n }),\n\n object: Field.text({\n label: 'Object Name',\n required: true,\n }),\n\n record_id: Field.text({\n label: 'Record ID',\n required: true,\n }),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n required: true,\n }),\n\n events: Field.textarea({\n label: 'Subscribed Events',\n description: 'Array of event types: comment, mention, field_change, task, approval, all (JSON)',\n }),\n\n channels: Field.textarea({\n label: 'Notification Channels',\n description: 'Array of channels: in_app, email, push, slack (JSON)',\n }),\n\n active: Field.boolean({\n label: 'Active',\n defaultValue: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['object', 'record_id', 'user_id'], unique: true },\n { fields: ['user_id'], unique: false },\n { fields: ['object', 'record_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { InMemoryFeedAdapter } from './in-memory-feed-adapter.js';\nimport type { InMemoryFeedAdapterOptions } from './in-memory-feed-adapter.js';\nimport { FeedItem, FeedReaction, RecordSubscription } from './objects/index.js';\n\n/**\n * Configuration options for the FeedServicePlugin.\n */\nexport interface FeedServicePluginOptions {\n /** Feed adapter type (default: 'memory') */\n adapter?: 'memory';\n /** Options for the in-memory adapter */\n memory?: InMemoryFeedAdapterOptions;\n}\n\n/**\n * FeedServicePlugin — Production IFeedService implementation.\n *\n * Registers a Feed/Chatter service with the kernel during the init phase.\n * Currently supports in-memory storage for single-process environments.\n *\n * @example\n * ```ts\n * import { ObjectKernel } from '@objectstack/core';\n * import { FeedServicePlugin } from '@objectstack/service-feed';\n *\n * const kernel = new ObjectKernel();\n * kernel.use(new FeedServicePlugin());\n * await kernel.bootstrap();\n *\n * const feed = kernel.getService('feed');\n * const item = await feed.createFeedItem({\n * object: 'account',\n * recordId: 'rec_123',\n * type: 'comment',\n * actor: { type: 'user', id: 'user_1', name: 'Alice' },\n * body: 'Great progress!',\n * });\n * ```\n */\nexport class FeedServicePlugin implements Plugin {\n name = 'com.objectstack.service.feed';\n version = '1.0.0';\n type = 'standard';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private readonly options: FeedServicePluginOptions;\n\n constructor(options: FeedServicePluginOptions = {}) {\n this.options = { adapter: 'memory', ...options };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n const feed = new InMemoryFeedAdapter(this.options.memory);\n ctx.registerService('feed', feed);\n\n // Register feed system objects via the manifest service.\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service.feed',\n name: 'Feed Service',\n version: '1.0.0',\n type: 'plugin',\n scope: 'project',\n objects: [FeedItem, FeedReaction, RecordSubscription],\n });\n\n ctx.logger.info('FeedServicePlugin: registered in-memory feed adapter');\n }\n}\n"],"mappings":"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","names":["ObjectSchema","Field","ObjectSchema","Field"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/service-feed",
3
- "version": "4.0.4",
3
+ "version": "4.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Feed/Chatter Service for ObjectStack — implements IFeedService with in-memory adapter for comments, reactions, field changes, and record subscriptions",
6
6
  "type": "module",
@@ -14,13 +14,38 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@objectstack/core": "4.0.4",
18
- "@objectstack/spec": "4.0.4"
17
+ "@objectstack/core": "4.1.0",
18
+ "@objectstack/spec": "4.1.0"
19
19
  },
20
20
  "devDependencies": {
21
- "@types/node": "^25.6.0",
22
- "typescript": "^6.0.2",
23
- "vitest": "^4.1.4"
21
+ "@types/node": "^25.9.1",
22
+ "typescript": "^6.0.3",
23
+ "vitest": "^4.1.7"
24
+ },
25
+ "keywords": [
26
+ "objectstack",
27
+ "service",
28
+ "feed",
29
+ "activity",
30
+ "chatter"
31
+ ],
32
+ "author": "ObjectStack",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/objectstack-ai/framework.git",
36
+ "directory": "packages/services/service-feed"
37
+ },
38
+ "homepage": "https://objectstack.ai/docs",
39
+ "bugs": "https://github.com/objectstack-ai/framework/issues",
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md"
46
+ ],
47
+ "engines": {
48
+ "node": ">=18.0.0"
24
49
  },
25
50
  "scripts": {
26
51
  "build": "tsup --config ../../../tsup.config.ts",
@@ -1,22 +0,0 @@
1
-
2
- > @objectstack/service-feed@4.0.4 build /home/runner/work/framework/framework/packages/services/service-feed
3
- > tsup --config ../../../tsup.config.ts
4
-
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.1
8
- CLI Using tsup config: /home/runner/work/framework/framework/tsup.config.ts
9
- CLI Target: es2020
10
- CLI Cleaning output folder
11
- ESM Build start
12
- CJS Build start
13
- ESM dist/index.js 14.76 KB
14
- ESM dist/index.js.map 31.12 KB
15
- ESM ⚡️ Build success in 148ms
16
- CJS dist/index.cjs 16.27 KB
17
- CJS dist/index.cjs.map 31.65 KB
18
- CJS ⚡️ Build success in 131ms
19
- DTS Build start
20
- DTS ⚡️ Build success in 20999ms
21
- DTS dist/index.d.ts 281.09 KB
22
- DTS dist/index.d.cts 281.09 KB
package/CHANGELOG.md DELETED
@@ -1,168 +0,0 @@
1
- # @objectstack/service-feed
2
-
3
- ## 4.0.4
4
-
5
- ### Patch Changes
6
-
7
- - Updated dependencies [326b66b]
8
- - @objectstack/spec@4.0.4
9
- - @objectstack/core@4.0.4
10
-
11
- ## 4.0.3
12
-
13
- ### Patch Changes
14
-
15
- - @objectstack/spec@4.0.3
16
- - @objectstack/core@4.0.3
17
-
18
- ## 4.0.2
19
-
20
- ### Patch Changes
21
-
22
- - Updated dependencies [5f659e9]
23
- - @objectstack/spec@4.0.2
24
- - @objectstack/core@4.0.2
25
-
26
- ## 4.0.0
27
-
28
- ### Patch Changes
29
-
30
- - Updated dependencies [f08ffc3]
31
- - Updated dependencies [e0b0a78]
32
- - @objectstack/spec@4.0.0
33
- - @objectstack/core@4.0.0
34
-
35
- ## 3.3.1
36
-
37
- ### Patch Changes
38
-
39
- - @objectstack/spec@3.3.1
40
- - @objectstack/core@3.3.1
41
-
42
- ## 3.3.0
43
-
44
- ### Patch Changes
45
-
46
- - @objectstack/spec@3.3.0
47
- - @objectstack/core@3.3.0
48
-
49
- ## 3.2.9
50
-
51
- ### Patch Changes
52
-
53
- - @objectstack/spec@3.2.9
54
- - @objectstack/core@3.2.9
55
-
56
- ## 3.2.8
57
-
58
- ### Patch Changes
59
-
60
- - @objectstack/spec@3.2.8
61
- - @objectstack/core@3.2.8
62
-
63
- ## 3.2.7
64
-
65
- ### Patch Changes
66
-
67
- - @objectstack/spec@3.2.7
68
- - @objectstack/core@3.2.7
69
-
70
- ## 3.2.6
71
-
72
- ### Patch Changes
73
-
74
- - @objectstack/spec@3.2.6
75
- - @objectstack/core@3.2.6
76
-
77
- ## 3.2.5
78
-
79
- ### Patch Changes
80
-
81
- - @objectstack/spec@3.2.5
82
- - @objectstack/core@3.2.5
83
-
84
- ## 3.2.4
85
-
86
- ### Patch Changes
87
-
88
- - @objectstack/spec@3.2.4
89
- - @objectstack/core@3.2.4
90
-
91
- ## 3.2.3
92
-
93
- ### Patch Changes
94
-
95
- - @objectstack/spec@3.2.3
96
- - @objectstack/core@3.2.3
97
-
98
- ## 3.2.2
99
-
100
- ### Patch Changes
101
-
102
- - Updated dependencies [46defbb]
103
- - @objectstack/spec@3.2.2
104
- - @objectstack/core@3.2.2
105
-
106
- ## 3.2.1
107
-
108
- ### Patch Changes
109
-
110
- - Updated dependencies [850b546]
111
- - @objectstack/spec@3.2.1
112
- - @objectstack/core@3.2.1
113
-
114
- ## 3.2.0
115
-
116
- ### Patch Changes
117
-
118
- - Updated dependencies [5901c29]
119
- - @objectstack/spec@3.2.0
120
- - @objectstack/core@3.2.0
121
-
122
- ## 3.1.1
123
-
124
- ### Patch Changes
125
-
126
- - Updated dependencies [953d667]
127
- - @objectstack/spec@3.1.1
128
- - @objectstack/core@3.1.1
129
-
130
- ## 3.1.0
131
-
132
- ### Patch Changes
133
-
134
- - Updated dependencies [0088830]
135
- - @objectstack/spec@3.1.0
136
- - @objectstack/core@3.1.0
137
-
138
- ## 3.0.11
139
-
140
- ### Patch Changes
141
-
142
- - Updated dependencies [92d9d99]
143
- - @objectstack/spec@3.0.11
144
- - @objectstack/core@3.0.11
145
-
146
- ## 3.0.10
147
-
148
- ### Patch Changes
149
-
150
- - Updated dependencies [d1e5d31]
151
- - @objectstack/spec@3.0.10
152
- - @objectstack/core@3.0.10
153
-
154
- ## 3.0.9
155
-
156
- ### Patch Changes
157
-
158
- - Updated dependencies [15e0df6]
159
- - @objectstack/spec@3.0.9
160
- - @objectstack/core@3.0.9
161
-
162
- ## 3.0.8
163
-
164
- ### Patch Changes
165
-
166
- - Updated dependencies [5a968a2]
167
- - @objectstack/spec@3.0.8
168
- - @objectstack/core@3.0.8
@@ -1,70 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type { Plugin, PluginContext } from '@objectstack/core';
4
- import { InMemoryFeedAdapter } from './in-memory-feed-adapter.js';
5
- import type { InMemoryFeedAdapterOptions } from './in-memory-feed-adapter.js';
6
- import { FeedItem, FeedReaction, RecordSubscription } from './objects/index.js';
7
-
8
- /**
9
- * Configuration options for the FeedServicePlugin.
10
- */
11
- export interface FeedServicePluginOptions {
12
- /** Feed adapter type (default: 'memory') */
13
- adapter?: 'memory';
14
- /** Options for the in-memory adapter */
15
- memory?: InMemoryFeedAdapterOptions;
16
- }
17
-
18
- /**
19
- * FeedServicePlugin — Production IFeedService implementation.
20
- *
21
- * Registers a Feed/Chatter service with the kernel during the init phase.
22
- * Currently supports in-memory storage for single-process environments.
23
- *
24
- * @example
25
- * ```ts
26
- * import { ObjectKernel } from '@objectstack/core';
27
- * import { FeedServicePlugin } from '@objectstack/service-feed';
28
- *
29
- * const kernel = new ObjectKernel();
30
- * kernel.use(new FeedServicePlugin());
31
- * await kernel.bootstrap();
32
- *
33
- * const feed = kernel.getService('feed');
34
- * const item = await feed.createFeedItem({
35
- * object: 'account',
36
- * recordId: 'rec_123',
37
- * type: 'comment',
38
- * actor: { type: 'user', id: 'user_1', name: 'Alice' },
39
- * body: 'Great progress!',
40
- * });
41
- * ```
42
- */
43
- export class FeedServicePlugin implements Plugin {
44
- name = 'com.objectstack.service.feed';
45
- version = '1.0.0';
46
- type = 'standard';
47
- dependencies = ['com.objectstack.engine.objectql'];
48
-
49
- private readonly options: FeedServicePluginOptions;
50
-
51
- constructor(options: FeedServicePluginOptions = {}) {
52
- this.options = { adapter: 'memory', ...options };
53
- }
54
-
55
- async init(ctx: PluginContext): Promise<void> {
56
- const feed = new InMemoryFeedAdapter(this.options.memory);
57
- ctx.registerService('feed', feed);
58
-
59
- // Register feed system objects via the manifest service.
60
- ctx.getService<{ register(m: any): void }>('manifest').register({
61
- id: 'com.objectstack.service.feed',
62
- name: 'Feed Service',
63
- version: '1.0.0',
64
- type: 'plugin',
65
- objects: [FeedItem, FeedReaction, RecordSubscription],
66
- });
67
-
68
- ctx.logger.info('FeedServicePlugin: registered in-memory feed adapter');
69
- }
70
- }