@objectstack/service-feed 7.1.0 → 7.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -511,7 +511,7 @@ var FeedServicePlugin = class {
511
511
  name: "Feed Service",
512
512
  version: "1.0.0",
513
513
  type: "plugin",
514
- scope: "project",
514
+ scope: "system",
515
515
  objects: [FeedItem, FeedReaction, RecordSubscription]
516
516
  });
517
517
  ctx.logger.info("FeedServicePlugin: registered in-memory feed adapter");
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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\nexport { FeedServicePlugin } from './feed-service-plugin.js';\nexport type { FeedServicePluginOptions } from './feed-service-plugin.js';\nexport { InMemoryFeedAdapter } from './in-memory-feed-adapter.js';\nexport type { InMemoryFeedAdapterOptions } from './in-memory-feed-adapter.js';\n\n// Feed Service Objects (metadata definitions)\nexport { FeedItem, FeedReaction, RecordSubscription } from './objects/index.js';\n","// 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":["import_data","import_data"]}
1
+ {"version":3,"sources":["../src/index.ts","../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\nexport { FeedServicePlugin } from './feed-service-plugin.js';\nexport type { FeedServicePluginOptions } from './feed-service-plugin.js';\nexport { InMemoryFeedAdapter } from './in-memory-feed-adapter.js';\nexport type { InMemoryFeedAdapterOptions } from './in-memory-feed-adapter.js';\n\n// Feed Service Objects (metadata definitions)\nexport { FeedItem, FeedReaction, RecordSubscription } from './objects/index.js';\n","// 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: 'system',\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":["import_data","import_data"]}
package/dist/index.d.cts CHANGED
@@ -350,6 +350,13 @@ declare const FeedItem: Omit<{
350
350
  caseSensitive?: boolean | undefined;
351
351
  autonumberFormat?: string | undefined;
352
352
  }>;
353
+ _lock?: "full" | "none" | "no-overlay" | "no-delete" | undefined;
354
+ _lockReason?: string | undefined;
355
+ _lockSource?: "artifact" | "package" | "env-forced" | undefined;
356
+ _provenance?: "package" | "env-forced" | "org" | undefined;
357
+ _packageId?: string | undefined;
358
+ _packageVersion?: string | undefined;
359
+ _lockDocsUrl?: string | undefined;
353
360
  label?: string | undefined;
354
361
  pluralLabel?: string | undefined;
355
362
  description?: string | undefined;
@@ -495,7 +502,7 @@ declare const FeedItem: Omit<{
495
502
  wrap?: boolean | undefined;
496
503
  type?: string | undefined;
497
504
  pinned?: "left" | "right" | undefined;
498
- summary?: "count" | "min" | "max" | "sum" | "avg" | "none" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
505
+ summary?: "count" | "none" | "min" | "max" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
499
506
  link?: boolean | undefined;
500
507
  action?: string | undefined;
501
508
  }[];
@@ -544,7 +551,7 @@ declare const FeedItem: Omit<{
544
551
  bordered?: boolean | undefined;
545
552
  compactToolbar?: boolean | undefined;
546
553
  selection?: {
547
- type: "multiple" | "single" | "none";
554
+ type: "none" | "multiple" | "single";
548
555
  } | undefined;
549
556
  navigation?: {
550
557
  mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
@@ -739,7 +746,7 @@ declare const FeedItem: Omit<{
739
746
  apiMethods?: ("search" | "create" | "import" | "delete" | "list" | "get" | "update" | "upsert" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
740
747
  } | undefined;
741
748
  recordTypes?: string[] | undefined;
742
- sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
749
+ sharingModel?: "private" | "full" | "read" | "read_write" | undefined;
743
750
  publicSharing?: {
744
751
  enabled: boolean;
745
752
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -842,6 +849,11 @@ declare const FeedItem: Omit<{
842
849
  role?: string | undefined;
843
850
  } | undefined;
844
851
  }[] | undefined;
852
+ protection?: {
853
+ lock: "full" | "none" | "no-overlay" | "no-delete";
854
+ reason: string;
855
+ docsUrl?: string | undefined;
856
+ } | undefined;
845
857
  }, "fields"> & Pick<{
846
858
  readonly name: "feed_item";
847
859
  readonly label: "Feed Item";
@@ -4405,6 +4417,13 @@ declare const FeedReaction: Omit<{
4405
4417
  caseSensitive?: boolean | undefined;
4406
4418
  autonumberFormat?: string | undefined;
4407
4419
  }>;
4420
+ _lock?: "full" | "none" | "no-overlay" | "no-delete" | undefined;
4421
+ _lockReason?: string | undefined;
4422
+ _lockSource?: "artifact" | "package" | "env-forced" | undefined;
4423
+ _provenance?: "package" | "env-forced" | "org" | undefined;
4424
+ _packageId?: string | undefined;
4425
+ _packageVersion?: string | undefined;
4426
+ _lockDocsUrl?: string | undefined;
4408
4427
  label?: string | undefined;
4409
4428
  pluralLabel?: string | undefined;
4410
4429
  description?: string | undefined;
@@ -4550,7 +4569,7 @@ declare const FeedReaction: Omit<{
4550
4569
  wrap?: boolean | undefined;
4551
4570
  type?: string | undefined;
4552
4571
  pinned?: "left" | "right" | undefined;
4553
- summary?: "count" | "min" | "max" | "sum" | "avg" | "none" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
4572
+ summary?: "count" | "none" | "min" | "max" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
4554
4573
  link?: boolean | undefined;
4555
4574
  action?: string | undefined;
4556
4575
  }[];
@@ -4599,7 +4618,7 @@ declare const FeedReaction: Omit<{
4599
4618
  bordered?: boolean | undefined;
4600
4619
  compactToolbar?: boolean | undefined;
4601
4620
  selection?: {
4602
- type: "multiple" | "single" | "none";
4621
+ type: "none" | "multiple" | "single";
4603
4622
  } | undefined;
4604
4623
  navigation?: {
4605
4624
  mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
@@ -4794,7 +4813,7 @@ declare const FeedReaction: Omit<{
4794
4813
  apiMethods?: ("search" | "create" | "import" | "delete" | "list" | "get" | "update" | "upsert" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
4795
4814
  } | undefined;
4796
4815
  recordTypes?: string[] | undefined;
4797
- sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
4816
+ sharingModel?: "private" | "full" | "read" | "read_write" | undefined;
4798
4817
  publicSharing?: {
4799
4818
  enabled: boolean;
4800
4819
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -4897,6 +4916,11 @@ declare const FeedReaction: Omit<{
4897
4916
  role?: string | undefined;
4898
4917
  } | undefined;
4899
4918
  }[] | undefined;
4919
+ protection?: {
4920
+ lock: "full" | "none" | "no-overlay" | "no-delete";
4921
+ reason: string;
4922
+ docsUrl?: string | undefined;
4923
+ } | undefined;
4900
4924
  }, "fields"> & Pick<{
4901
4925
  readonly name: "feed_reaction";
4902
4926
  readonly label: "Feed Reaction";
@@ -6007,6 +6031,13 @@ declare const RecordSubscription: Omit<{
6007
6031
  caseSensitive?: boolean | undefined;
6008
6032
  autonumberFormat?: string | undefined;
6009
6033
  }>;
6034
+ _lock?: "full" | "none" | "no-overlay" | "no-delete" | undefined;
6035
+ _lockReason?: string | undefined;
6036
+ _lockSource?: "artifact" | "package" | "env-forced" | undefined;
6037
+ _provenance?: "package" | "env-forced" | "org" | undefined;
6038
+ _packageId?: string | undefined;
6039
+ _packageVersion?: string | undefined;
6040
+ _lockDocsUrl?: string | undefined;
6010
6041
  label?: string | undefined;
6011
6042
  pluralLabel?: string | undefined;
6012
6043
  description?: string | undefined;
@@ -6152,7 +6183,7 @@ declare const RecordSubscription: Omit<{
6152
6183
  wrap?: boolean | undefined;
6153
6184
  type?: string | undefined;
6154
6185
  pinned?: "left" | "right" | undefined;
6155
- summary?: "count" | "min" | "max" | "sum" | "avg" | "none" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
6186
+ summary?: "count" | "none" | "min" | "max" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
6156
6187
  link?: boolean | undefined;
6157
6188
  action?: string | undefined;
6158
6189
  }[];
@@ -6201,7 +6232,7 @@ declare const RecordSubscription: Omit<{
6201
6232
  bordered?: boolean | undefined;
6202
6233
  compactToolbar?: boolean | undefined;
6203
6234
  selection?: {
6204
- type: "multiple" | "single" | "none";
6235
+ type: "none" | "multiple" | "single";
6205
6236
  } | undefined;
6206
6237
  navigation?: {
6207
6238
  mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
@@ -6396,7 +6427,7 @@ declare const RecordSubscription: Omit<{
6396
6427
  apiMethods?: ("search" | "create" | "import" | "delete" | "list" | "get" | "update" | "upsert" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
6397
6428
  } | undefined;
6398
6429
  recordTypes?: string[] | undefined;
6399
- sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
6430
+ sharingModel?: "private" | "full" | "read" | "read_write" | undefined;
6400
6431
  publicSharing?: {
6401
6432
  enabled: boolean;
6402
6433
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -6499,6 +6530,11 @@ declare const RecordSubscription: Omit<{
6499
6530
  role?: string | undefined;
6500
6531
  } | undefined;
6501
6532
  }[] | undefined;
6533
+ protection?: {
6534
+ lock: "full" | "none" | "no-overlay" | "no-delete";
6535
+ reason: string;
6536
+ docsUrl?: string | undefined;
6537
+ } | undefined;
6502
6538
  }, "fields"> & Pick<{
6503
6539
  readonly name: "record_subscription";
6504
6540
  readonly label: "Record Subscription";
package/dist/index.d.ts CHANGED
@@ -350,6 +350,13 @@ declare const FeedItem: Omit<{
350
350
  caseSensitive?: boolean | undefined;
351
351
  autonumberFormat?: string | undefined;
352
352
  }>;
353
+ _lock?: "full" | "none" | "no-overlay" | "no-delete" | undefined;
354
+ _lockReason?: string | undefined;
355
+ _lockSource?: "artifact" | "package" | "env-forced" | undefined;
356
+ _provenance?: "package" | "env-forced" | "org" | undefined;
357
+ _packageId?: string | undefined;
358
+ _packageVersion?: string | undefined;
359
+ _lockDocsUrl?: string | undefined;
353
360
  label?: string | undefined;
354
361
  pluralLabel?: string | undefined;
355
362
  description?: string | undefined;
@@ -495,7 +502,7 @@ declare const FeedItem: Omit<{
495
502
  wrap?: boolean | undefined;
496
503
  type?: string | undefined;
497
504
  pinned?: "left" | "right" | undefined;
498
- summary?: "count" | "min" | "max" | "sum" | "avg" | "none" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
505
+ summary?: "count" | "none" | "min" | "max" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
499
506
  link?: boolean | undefined;
500
507
  action?: string | undefined;
501
508
  }[];
@@ -544,7 +551,7 @@ declare const FeedItem: Omit<{
544
551
  bordered?: boolean | undefined;
545
552
  compactToolbar?: boolean | undefined;
546
553
  selection?: {
547
- type: "multiple" | "single" | "none";
554
+ type: "none" | "multiple" | "single";
548
555
  } | undefined;
549
556
  navigation?: {
550
557
  mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
@@ -739,7 +746,7 @@ declare const FeedItem: Omit<{
739
746
  apiMethods?: ("search" | "create" | "import" | "delete" | "list" | "get" | "update" | "upsert" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
740
747
  } | undefined;
741
748
  recordTypes?: string[] | undefined;
742
- sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
749
+ sharingModel?: "private" | "full" | "read" | "read_write" | undefined;
743
750
  publicSharing?: {
744
751
  enabled: boolean;
745
752
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -842,6 +849,11 @@ declare const FeedItem: Omit<{
842
849
  role?: string | undefined;
843
850
  } | undefined;
844
851
  }[] | undefined;
852
+ protection?: {
853
+ lock: "full" | "none" | "no-overlay" | "no-delete";
854
+ reason: string;
855
+ docsUrl?: string | undefined;
856
+ } | undefined;
845
857
  }, "fields"> & Pick<{
846
858
  readonly name: "feed_item";
847
859
  readonly label: "Feed Item";
@@ -4405,6 +4417,13 @@ declare const FeedReaction: Omit<{
4405
4417
  caseSensitive?: boolean | undefined;
4406
4418
  autonumberFormat?: string | undefined;
4407
4419
  }>;
4420
+ _lock?: "full" | "none" | "no-overlay" | "no-delete" | undefined;
4421
+ _lockReason?: string | undefined;
4422
+ _lockSource?: "artifact" | "package" | "env-forced" | undefined;
4423
+ _provenance?: "package" | "env-forced" | "org" | undefined;
4424
+ _packageId?: string | undefined;
4425
+ _packageVersion?: string | undefined;
4426
+ _lockDocsUrl?: string | undefined;
4408
4427
  label?: string | undefined;
4409
4428
  pluralLabel?: string | undefined;
4410
4429
  description?: string | undefined;
@@ -4550,7 +4569,7 @@ declare const FeedReaction: Omit<{
4550
4569
  wrap?: boolean | undefined;
4551
4570
  type?: string | undefined;
4552
4571
  pinned?: "left" | "right" | undefined;
4553
- summary?: "count" | "min" | "max" | "sum" | "avg" | "none" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
4572
+ summary?: "count" | "none" | "min" | "max" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
4554
4573
  link?: boolean | undefined;
4555
4574
  action?: string | undefined;
4556
4575
  }[];
@@ -4599,7 +4618,7 @@ declare const FeedReaction: Omit<{
4599
4618
  bordered?: boolean | undefined;
4600
4619
  compactToolbar?: boolean | undefined;
4601
4620
  selection?: {
4602
- type: "multiple" | "single" | "none";
4621
+ type: "none" | "multiple" | "single";
4603
4622
  } | undefined;
4604
4623
  navigation?: {
4605
4624
  mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
@@ -4794,7 +4813,7 @@ declare const FeedReaction: Omit<{
4794
4813
  apiMethods?: ("search" | "create" | "import" | "delete" | "list" | "get" | "update" | "upsert" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
4795
4814
  } | undefined;
4796
4815
  recordTypes?: string[] | undefined;
4797
- sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
4816
+ sharingModel?: "private" | "full" | "read" | "read_write" | undefined;
4798
4817
  publicSharing?: {
4799
4818
  enabled: boolean;
4800
4819
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -4897,6 +4916,11 @@ declare const FeedReaction: Omit<{
4897
4916
  role?: string | undefined;
4898
4917
  } | undefined;
4899
4918
  }[] | undefined;
4919
+ protection?: {
4920
+ lock: "full" | "none" | "no-overlay" | "no-delete";
4921
+ reason: string;
4922
+ docsUrl?: string | undefined;
4923
+ } | undefined;
4900
4924
  }, "fields"> & Pick<{
4901
4925
  readonly name: "feed_reaction";
4902
4926
  readonly label: "Feed Reaction";
@@ -6007,6 +6031,13 @@ declare const RecordSubscription: Omit<{
6007
6031
  caseSensitive?: boolean | undefined;
6008
6032
  autonumberFormat?: string | undefined;
6009
6033
  }>;
6034
+ _lock?: "full" | "none" | "no-overlay" | "no-delete" | undefined;
6035
+ _lockReason?: string | undefined;
6036
+ _lockSource?: "artifact" | "package" | "env-forced" | undefined;
6037
+ _provenance?: "package" | "env-forced" | "org" | undefined;
6038
+ _packageId?: string | undefined;
6039
+ _packageVersion?: string | undefined;
6040
+ _lockDocsUrl?: string | undefined;
6010
6041
  label?: string | undefined;
6011
6042
  pluralLabel?: string | undefined;
6012
6043
  description?: string | undefined;
@@ -6152,7 +6183,7 @@ declare const RecordSubscription: Omit<{
6152
6183
  wrap?: boolean | undefined;
6153
6184
  type?: string | undefined;
6154
6185
  pinned?: "left" | "right" | undefined;
6155
- summary?: "count" | "min" | "max" | "sum" | "avg" | "none" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
6186
+ summary?: "count" | "none" | "min" | "max" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
6156
6187
  link?: boolean | undefined;
6157
6188
  action?: string | undefined;
6158
6189
  }[];
@@ -6201,7 +6232,7 @@ declare const RecordSubscription: Omit<{
6201
6232
  bordered?: boolean | undefined;
6202
6233
  compactToolbar?: boolean | undefined;
6203
6234
  selection?: {
6204
- type: "multiple" | "single" | "none";
6235
+ type: "none" | "multiple" | "single";
6205
6236
  } | undefined;
6206
6237
  navigation?: {
6207
6238
  mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
@@ -6396,7 +6427,7 @@ declare const RecordSubscription: Omit<{
6396
6427
  apiMethods?: ("search" | "create" | "import" | "delete" | "list" | "get" | "update" | "upsert" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
6397
6428
  } | undefined;
6398
6429
  recordTypes?: string[] | undefined;
6399
- sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
6430
+ sharingModel?: "private" | "full" | "read" | "read_write" | undefined;
6400
6431
  publicSharing?: {
6401
6432
  enabled: boolean;
6402
6433
  allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
@@ -6499,6 +6530,11 @@ declare const RecordSubscription: Omit<{
6499
6530
  role?: string | undefined;
6500
6531
  } | undefined;
6501
6532
  }[] | undefined;
6533
+ protection?: {
6534
+ lock: "full" | "none" | "no-overlay" | "no-delete";
6535
+ reason: string;
6536
+ docsUrl?: string | undefined;
6537
+ } | undefined;
6502
6538
  }, "fields"> & Pick<{
6503
6539
  readonly name: "record_subscription";
6504
6540
  readonly label: "Record Subscription";
package/dist/index.js CHANGED
@@ -481,7 +481,7 @@ var FeedServicePlugin = class {
481
481
  name: "Feed Service",
482
482
  version: "1.0.0",
483
483
  type: "plugin",
484
- scope: "project",
484
+ scope: "system",
485
485
  objects: [FeedItem, FeedReaction, RecordSubscription]
486
486
  });
487
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 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"]}
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: 'system',\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": "7.1.0",
3
+ "version": "7.2.1",
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,8 +14,8 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@objectstack/core": "7.1.0",
18
- "@objectstack/spec": "7.1.0"
17
+ "@objectstack/core": "7.2.1",
18
+ "@objectstack/spec": "7.2.1"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^25.9.1",