@objectstack/service-package 7.7.0 → 7.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -145,6 +145,24 @@ var PackageServicePlugin = class {
145
145
  };
146
146
  ctx.registerService("package", packageService);
147
147
  logger.info("Package service initialized");
148
+ try {
149
+ const registry = objectql.registry;
150
+ if (registry?.installPackage && registry?.getPackage) {
151
+ let hydrated = 0;
152
+ for (const rec of await packageService.list()) {
153
+ const id = rec?.manifest?.id;
154
+ if (id && !registry.getPackage(id)) {
155
+ registry.installPackage(rec.manifest);
156
+ hydrated++;
157
+ }
158
+ }
159
+ if (hydrated > 0) {
160
+ logger.info(`Hydrated ${hydrated} package(s) from sys_packages into registry`);
161
+ }
162
+ }
163
+ } catch (error) {
164
+ logger.debug(`Package hydration from sys_packages skipped: ${error?.message}`);
165
+ }
148
166
  }
149
167
  async ensureTable(objectql, logger) {
150
168
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { createHash } from 'node:crypto';\nimport type { ObjectStackManifest } from '@objectstack/spec/kernel';\nimport type { IDataEngine } from '@objectstack/spec/contracts';\n\nexport interface PackageMetadata {\n objects?: any[];\n views?: any[];\n apps?: any[];\n flows?: any[];\n agents?: any[];\n tools?: any[];\n translations?: any[];\n}\n\nexport interface PackageRecord {\n id: string;\n version: string;\n manifest: ObjectStackManifest;\n metadata: PackageMetadata;\n hash: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface PackageService {\n publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }): Promise<{ success: boolean; error?: string }>;\n get(packageId: string, version?: string): Promise<PackageRecord | null>;\n list(): Promise<PackageRecord[]>;\n delete(packageId: string, version?: string): Promise<{ success: boolean }>;\n}\n\n/**\n * Normalize the result of `objectql.execute()` into a row array.\n *\n * Different drivers return different shapes for raw SELECT statements:\n * - SQL driver (knex/SQLite) and Turso remote transport return rows\n * directly as an array.\n * - PostgreSQL (knex/pg) returns `{ rows, rowCount, ... }`.\n * - Some drivers may return `{ rows: [...] }` wrappers in other contexts.\n *\n * This helper accepts any of those shapes and always returns an array.\n */\nfunction normalizeRows(result: any): any[] {\n if (Array.isArray(result)) return result;\n if (result && Array.isArray(result.rows)) return result.rows;\n return [];\n}\n\n/**\n * Package Management Service Plugin\n *\n * Provides package publishing, retrieval, and management capabilities.\n * Stores package metadata in the sys.packages table for dynamic loading.\n */\nexport class PackageServicePlugin implements Plugin {\n name = 'package-service';\n\n async init(ctx: PluginContext): Promise<void> {\n // Service will be registered in start() after ObjectQL is available\n ctx.logger.debug('Package service plugin initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n const logger = ctx.logger;\n\n // Get ObjectQL service (available in start() hook after dependencies are initialized)\n const objectql = ctx.getService<IDataEngine>('objectql');\n if (!objectql || !objectql.execute) {\n throw new Error('ObjectQL service with execute() support is required for PackageService');\n }\n\n // Create sys_packages table if it doesn't exist\n try {\n await this.ensureTable(objectql, logger);\n } catch (error) {\n logger.error('Failed to create sys_packages table', error as Error);\n throw error;\n }\n\n // Create the package service\n const packageService: PackageService = {\n async publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }) {\n try {\n const hash = createHash('sha256')\n .update(JSON.stringify({ manifest: data.manifest, metadata: data.metadata }))\n .digest('hex');\n\n await objectql.execute!({\n sql: `\n INSERT INTO sys_packages (id, version, manifest, metadata, hash, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT(id, version) DO UPDATE SET\n manifest = excluded.manifest,\n metadata = excluded.metadata,\n hash = excluded.hash,\n updated_at = CURRENT_TIMESTAMP\n `,\n args: [\n data.manifest.id,\n data.manifest.version,\n JSON.stringify(data.manifest),\n JSON.stringify(data.metadata),\n hash,\n ],\n });\n\n logger.info(`Published package: ${data.manifest.id}@${data.manifest.version}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to publish package', error as Error);\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n },\n\n async get(packageId: string, version: string = 'latest') {\n try {\n const sql = version === 'latest'\n ? `SELECT * FROM sys_packages WHERE id = ? ORDER BY created_at DESC LIMIT 1`\n : `SELECT * FROM sys_packages WHERE id = ? AND version = ?`;\n\n const args = version === 'latest' ? [packageId] : [packageId, version];\n const result = await objectql.execute!({ sql, args });\n const rows = normalizeRows(result);\n\n if (rows.length === 0) {\n return null;\n }\n\n const row = rows[0];\n return {\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n };\n } catch (error) {\n logger.error(`Failed to get package: ${packageId}`, error as Error);\n return null;\n }\n },\n\n async list() {\n try {\n const result = await objectql.execute!({\n sql: `\n SELECT * FROM sys_packages\n WHERE (id, created_at) IN (\n SELECT id, MAX(created_at) FROM sys_packages GROUP BY id\n )\n ORDER BY created_at DESC\n `,\n });\n\n return normalizeRows(result).map((row: any) => ({\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }));\n } catch (error) {\n logger.error('Failed to list packages', error as Error);\n return [];\n }\n },\n\n async delete(packageId: string, version?: string) {\n try {\n const sql = version\n ? `DELETE FROM sys_packages WHERE id = ? AND version = ?`\n : `DELETE FROM sys_packages WHERE id = ?`;\n\n const args = version ? [packageId, version] : [packageId];\n await objectql.execute!({ sql, args });\n\n logger.info(`Deleted package: ${packageId}${version ? `@${version}` : ''}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to delete package', error as Error);\n return { success: false };\n }\n },\n };\n\n ctx.registerService('package', packageService);\n logger.info('Package service initialized');\n }\n\n private async ensureTable(objectql: IDataEngine, logger: any): Promise<void> {\n try {\n // Create the sys_packages table\n await objectql.execute!({\n sql: `\n CREATE TABLE IF NOT EXISTS sys_packages (\n id TEXT NOT NULL,\n version TEXT NOT NULL,\n manifest TEXT NOT NULL,\n metadata TEXT NOT NULL,\n hash TEXT NOT NULL,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, version)\n )\n `,\n });\n\n // Create index for faster latest version queries\n await objectql.execute!({\n sql: `\n CREATE INDEX IF NOT EXISTS idx_packages_latest\n ON sys_packages(id, created_at DESC)\n `,\n });\n\n logger.debug('sys_packages table ensured');\n } catch (error) {\n // Table might already exist, log and continue\n logger.debug('sys_packages table creation skipped (may already exist)');\n }\n }\n}\n\nexport { PackageServicePlugin as default };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { createHash } from 'node:crypto';\nimport type { ObjectStackManifest } from '@objectstack/spec/kernel';\nimport type { IDataEngine } from '@objectstack/spec/contracts';\n\nexport interface PackageMetadata {\n objects?: any[];\n views?: any[];\n apps?: any[];\n flows?: any[];\n agents?: any[];\n tools?: any[];\n translations?: any[];\n}\n\nexport interface PackageRecord {\n id: string;\n version: string;\n manifest: ObjectStackManifest;\n metadata: PackageMetadata;\n hash: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface PackageService {\n publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }): Promise<{ success: boolean; error?: string }>;\n get(packageId: string, version?: string): Promise<PackageRecord | null>;\n list(): Promise<PackageRecord[]>;\n delete(packageId: string, version?: string): Promise<{ success: boolean }>;\n}\n\n/**\n * Normalize the result of `objectql.execute()` into a row array.\n *\n * Different drivers return different shapes for raw SELECT statements:\n * - SQL driver (knex/SQLite) and Turso remote transport return rows\n * directly as an array.\n * - PostgreSQL (knex/pg) returns `{ rows, rowCount, ... }`.\n * - Some drivers may return `{ rows: [...] }` wrappers in other contexts.\n *\n * This helper accepts any of those shapes and always returns an array.\n */\nfunction normalizeRows(result: any): any[] {\n if (Array.isArray(result)) return result;\n if (result && Array.isArray(result.rows)) return result.rows;\n return [];\n}\n\n/**\n * Package Management Service Plugin\n *\n * Provides package publishing, retrieval, and management capabilities.\n * Stores package metadata in the sys.packages table for dynamic loading.\n */\nexport class PackageServicePlugin implements Plugin {\n name = 'package-service';\n\n async init(ctx: PluginContext): Promise<void> {\n // Service will be registered in start() after ObjectQL is available\n ctx.logger.debug('Package service plugin initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n const logger = ctx.logger;\n\n // Get ObjectQL service (available in start() hook after dependencies are initialized)\n const objectql = ctx.getService<IDataEngine>('objectql');\n if (!objectql || !objectql.execute) {\n throw new Error('ObjectQL service with execute() support is required for PackageService');\n }\n\n // Create sys_packages table if it doesn't exist\n try {\n await this.ensureTable(objectql, logger);\n } catch (error) {\n logger.error('Failed to create sys_packages table', error as Error);\n throw error;\n }\n\n // Create the package service\n const packageService: PackageService = {\n async publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }) {\n try {\n const hash = createHash('sha256')\n .update(JSON.stringify({ manifest: data.manifest, metadata: data.metadata }))\n .digest('hex');\n\n await objectql.execute!({\n sql: `\n INSERT INTO sys_packages (id, version, manifest, metadata, hash, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT(id, version) DO UPDATE SET\n manifest = excluded.manifest,\n metadata = excluded.metadata,\n hash = excluded.hash,\n updated_at = CURRENT_TIMESTAMP\n `,\n args: [\n data.manifest.id,\n data.manifest.version,\n JSON.stringify(data.manifest),\n JSON.stringify(data.metadata),\n hash,\n ],\n });\n\n logger.info(`Published package: ${data.manifest.id}@${data.manifest.version}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to publish package', error as Error);\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n },\n\n async get(packageId: string, version: string = 'latest') {\n try {\n const sql = version === 'latest'\n ? `SELECT * FROM sys_packages WHERE id = ? ORDER BY created_at DESC LIMIT 1`\n : `SELECT * FROM sys_packages WHERE id = ? AND version = ?`;\n\n const args = version === 'latest' ? [packageId] : [packageId, version];\n const result = await objectql.execute!({ sql, args });\n const rows = normalizeRows(result);\n\n if (rows.length === 0) {\n return null;\n }\n\n const row = rows[0];\n return {\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n };\n } catch (error) {\n logger.error(`Failed to get package: ${packageId}`, error as Error);\n return null;\n }\n },\n\n async list() {\n try {\n const result = await objectql.execute!({\n sql: `\n SELECT * FROM sys_packages\n WHERE (id, created_at) IN (\n SELECT id, MAX(created_at) FROM sys_packages GROUP BY id\n )\n ORDER BY created_at DESC\n `,\n });\n\n return normalizeRows(result).map((row: any) => ({\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }));\n } catch (error) {\n logger.error('Failed to list packages', error as Error);\n return [];\n }\n },\n\n async delete(packageId: string, version?: string) {\n try {\n const sql = version\n ? `DELETE FROM sys_packages WHERE id = ? AND version = ?`\n : `DELETE FROM sys_packages WHERE id = ?`;\n\n const args = version ? [packageId, version] : [packageId];\n await objectql.execute!({ sql, args });\n\n logger.info(`Deleted package: ${packageId}${version ? `@${version}` : ''}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to delete package', error as Error);\n return { success: false };\n }\n },\n };\n\n ctx.registerService('package', packageService);\n logger.info('Package service initialized');\n\n // Reconcile durable packages back into the in-memory registry (ADR-0033\n // consolidation). Packages persisted to `sys_packages` — AI-authored app\n // packages, or anything HTTP-installed in a previous run — must survive a\n // restart and surface in the registry-backed read paths (the dispatcher's\n // `/api/v1/packages` list/detail and `getMetaItems({type:'package'})`, i.e.\n // Studio's package selector). Never clobber a package already registered\n // from the filesystem. Best-effort and non-fatal.\n try {\n const registry = (objectql as unknown as { registry?: any }).registry;\n if (registry?.installPackage && registry?.getPackage) {\n let hydrated = 0;\n for (const rec of await packageService.list()) {\n const id = rec?.manifest?.id;\n if (id && !registry.getPackage(id)) {\n registry.installPackage(rec.manifest);\n hydrated++;\n }\n }\n if (hydrated > 0) {\n logger.info(`Hydrated ${hydrated} package(s) from sys_packages into registry`);\n }\n }\n } catch (error) {\n logger.debug(`Package hydration from sys_packages skipped: ${(error as Error)?.message}`);\n }\n }\n\n private async ensureTable(objectql: IDataEngine, logger: any): Promise<void> {\n try {\n // Create the sys_packages table\n await objectql.execute!({\n sql: `\n CREATE TABLE IF NOT EXISTS sys_packages (\n id TEXT NOT NULL,\n version TEXT NOT NULL,\n manifest TEXT NOT NULL,\n metadata TEXT NOT NULL,\n hash TEXT NOT NULL,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, version)\n )\n `,\n });\n\n // Create index for faster latest version queries\n await objectql.execute!({\n sql: `\n CREATE INDEX IF NOT EXISTS idx_packages_latest\n ON sys_packages(id, created_at DESC)\n `,\n });\n\n logger.debug('sys_packages table ensured');\n } catch (error) {\n // Table might already exist, log and continue\n logger.debug('sys_packages table creation skipped (may already exist)');\n }\n }\n}\n\nexport { PackageServicePlugin as default };\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -120,6 +120,24 @@ var PackageServicePlugin = class {
120
120
  };
121
121
  ctx.registerService("package", packageService);
122
122
  logger.info("Package service initialized");
123
+ try {
124
+ const registry = objectql.registry;
125
+ if (registry?.installPackage && registry?.getPackage) {
126
+ let hydrated = 0;
127
+ for (const rec of await packageService.list()) {
128
+ const id = rec?.manifest?.id;
129
+ if (id && !registry.getPackage(id)) {
130
+ registry.installPackage(rec.manifest);
131
+ hydrated++;
132
+ }
133
+ }
134
+ if (hydrated > 0) {
135
+ logger.info(`Hydrated ${hydrated} package(s) from sys_packages into registry`);
136
+ }
137
+ }
138
+ } catch (error) {
139
+ logger.debug(`Package hydration from sys_packages skipped: ${error?.message}`);
140
+ }
123
141
  }
124
142
  async ensureTable(objectql, logger) {
125
143
  try {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { createHash } from 'node:crypto';\nimport type { ObjectStackManifest } from '@objectstack/spec/kernel';\nimport type { IDataEngine } from '@objectstack/spec/contracts';\n\nexport interface PackageMetadata {\n objects?: any[];\n views?: any[];\n apps?: any[];\n flows?: any[];\n agents?: any[];\n tools?: any[];\n translations?: any[];\n}\n\nexport interface PackageRecord {\n id: string;\n version: string;\n manifest: ObjectStackManifest;\n metadata: PackageMetadata;\n hash: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface PackageService {\n publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }): Promise<{ success: boolean; error?: string }>;\n get(packageId: string, version?: string): Promise<PackageRecord | null>;\n list(): Promise<PackageRecord[]>;\n delete(packageId: string, version?: string): Promise<{ success: boolean }>;\n}\n\n/**\n * Normalize the result of `objectql.execute()` into a row array.\n *\n * Different drivers return different shapes for raw SELECT statements:\n * - SQL driver (knex/SQLite) and Turso remote transport return rows\n * directly as an array.\n * - PostgreSQL (knex/pg) returns `{ rows, rowCount, ... }`.\n * - Some drivers may return `{ rows: [...] }` wrappers in other contexts.\n *\n * This helper accepts any of those shapes and always returns an array.\n */\nfunction normalizeRows(result: any): any[] {\n if (Array.isArray(result)) return result;\n if (result && Array.isArray(result.rows)) return result.rows;\n return [];\n}\n\n/**\n * Package Management Service Plugin\n *\n * Provides package publishing, retrieval, and management capabilities.\n * Stores package metadata in the sys.packages table for dynamic loading.\n */\nexport class PackageServicePlugin implements Plugin {\n name = 'package-service';\n\n async init(ctx: PluginContext): Promise<void> {\n // Service will be registered in start() after ObjectQL is available\n ctx.logger.debug('Package service plugin initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n const logger = ctx.logger;\n\n // Get ObjectQL service (available in start() hook after dependencies are initialized)\n const objectql = ctx.getService<IDataEngine>('objectql');\n if (!objectql || !objectql.execute) {\n throw new Error('ObjectQL service with execute() support is required for PackageService');\n }\n\n // Create sys_packages table if it doesn't exist\n try {\n await this.ensureTable(objectql, logger);\n } catch (error) {\n logger.error('Failed to create sys_packages table', error as Error);\n throw error;\n }\n\n // Create the package service\n const packageService: PackageService = {\n async publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }) {\n try {\n const hash = createHash('sha256')\n .update(JSON.stringify({ manifest: data.manifest, metadata: data.metadata }))\n .digest('hex');\n\n await objectql.execute!({\n sql: `\n INSERT INTO sys_packages (id, version, manifest, metadata, hash, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT(id, version) DO UPDATE SET\n manifest = excluded.manifest,\n metadata = excluded.metadata,\n hash = excluded.hash,\n updated_at = CURRENT_TIMESTAMP\n `,\n args: [\n data.manifest.id,\n data.manifest.version,\n JSON.stringify(data.manifest),\n JSON.stringify(data.metadata),\n hash,\n ],\n });\n\n logger.info(`Published package: ${data.manifest.id}@${data.manifest.version}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to publish package', error as Error);\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n },\n\n async get(packageId: string, version: string = 'latest') {\n try {\n const sql = version === 'latest'\n ? `SELECT * FROM sys_packages WHERE id = ? ORDER BY created_at DESC LIMIT 1`\n : `SELECT * FROM sys_packages WHERE id = ? AND version = ?`;\n\n const args = version === 'latest' ? [packageId] : [packageId, version];\n const result = await objectql.execute!({ sql, args });\n const rows = normalizeRows(result);\n\n if (rows.length === 0) {\n return null;\n }\n\n const row = rows[0];\n return {\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n };\n } catch (error) {\n logger.error(`Failed to get package: ${packageId}`, error as Error);\n return null;\n }\n },\n\n async list() {\n try {\n const result = await objectql.execute!({\n sql: `\n SELECT * FROM sys_packages\n WHERE (id, created_at) IN (\n SELECT id, MAX(created_at) FROM sys_packages GROUP BY id\n )\n ORDER BY created_at DESC\n `,\n });\n\n return normalizeRows(result).map((row: any) => ({\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }));\n } catch (error) {\n logger.error('Failed to list packages', error as Error);\n return [];\n }\n },\n\n async delete(packageId: string, version?: string) {\n try {\n const sql = version\n ? `DELETE FROM sys_packages WHERE id = ? AND version = ?`\n : `DELETE FROM sys_packages WHERE id = ?`;\n\n const args = version ? [packageId, version] : [packageId];\n await objectql.execute!({ sql, args });\n\n logger.info(`Deleted package: ${packageId}${version ? `@${version}` : ''}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to delete package', error as Error);\n return { success: false };\n }\n },\n };\n\n ctx.registerService('package', packageService);\n logger.info('Package service initialized');\n }\n\n private async ensureTable(objectql: IDataEngine, logger: any): Promise<void> {\n try {\n // Create the sys_packages table\n await objectql.execute!({\n sql: `\n CREATE TABLE IF NOT EXISTS sys_packages (\n id TEXT NOT NULL,\n version TEXT NOT NULL,\n manifest TEXT NOT NULL,\n metadata TEXT NOT NULL,\n hash TEXT NOT NULL,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, version)\n )\n `,\n });\n\n // Create index for faster latest version queries\n await objectql.execute!({\n sql: `\n CREATE INDEX IF NOT EXISTS idx_packages_latest\n ON sys_packages(id, created_at DESC)\n `,\n });\n\n logger.debug('sys_packages table ensured');\n } catch (error) {\n // Table might already exist, log and continue\n logger.debug('sys_packages table creation skipped (may already exist)');\n }\n }\n}\n\nexport { PackageServicePlugin as default };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { createHash } from 'node:crypto';\nimport type { ObjectStackManifest } from '@objectstack/spec/kernel';\nimport type { IDataEngine } from '@objectstack/spec/contracts';\n\nexport interface PackageMetadata {\n objects?: any[];\n views?: any[];\n apps?: any[];\n flows?: any[];\n agents?: any[];\n tools?: any[];\n translations?: any[];\n}\n\nexport interface PackageRecord {\n id: string;\n version: string;\n manifest: ObjectStackManifest;\n metadata: PackageMetadata;\n hash: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface PackageService {\n publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }): Promise<{ success: boolean; error?: string }>;\n get(packageId: string, version?: string): Promise<PackageRecord | null>;\n list(): Promise<PackageRecord[]>;\n delete(packageId: string, version?: string): Promise<{ success: boolean }>;\n}\n\n/**\n * Normalize the result of `objectql.execute()` into a row array.\n *\n * Different drivers return different shapes for raw SELECT statements:\n * - SQL driver (knex/SQLite) and Turso remote transport return rows\n * directly as an array.\n * - PostgreSQL (knex/pg) returns `{ rows, rowCount, ... }`.\n * - Some drivers may return `{ rows: [...] }` wrappers in other contexts.\n *\n * This helper accepts any of those shapes and always returns an array.\n */\nfunction normalizeRows(result: any): any[] {\n if (Array.isArray(result)) return result;\n if (result && Array.isArray(result.rows)) return result.rows;\n return [];\n}\n\n/**\n * Package Management Service Plugin\n *\n * Provides package publishing, retrieval, and management capabilities.\n * Stores package metadata in the sys.packages table for dynamic loading.\n */\nexport class PackageServicePlugin implements Plugin {\n name = 'package-service';\n\n async init(ctx: PluginContext): Promise<void> {\n // Service will be registered in start() after ObjectQL is available\n ctx.logger.debug('Package service plugin initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n const logger = ctx.logger;\n\n // Get ObjectQL service (available in start() hook after dependencies are initialized)\n const objectql = ctx.getService<IDataEngine>('objectql');\n if (!objectql || !objectql.execute) {\n throw new Error('ObjectQL service with execute() support is required for PackageService');\n }\n\n // Create sys_packages table if it doesn't exist\n try {\n await this.ensureTable(objectql, logger);\n } catch (error) {\n logger.error('Failed to create sys_packages table', error as Error);\n throw error;\n }\n\n // Create the package service\n const packageService: PackageService = {\n async publish(data: { manifest: ObjectStackManifest; metadata: PackageMetadata }) {\n try {\n const hash = createHash('sha256')\n .update(JSON.stringify({ manifest: data.manifest, metadata: data.metadata }))\n .digest('hex');\n\n await objectql.execute!({\n sql: `\n INSERT INTO sys_packages (id, version, manifest, metadata, hash, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT(id, version) DO UPDATE SET\n manifest = excluded.manifest,\n metadata = excluded.metadata,\n hash = excluded.hash,\n updated_at = CURRENT_TIMESTAMP\n `,\n args: [\n data.manifest.id,\n data.manifest.version,\n JSON.stringify(data.manifest),\n JSON.stringify(data.metadata),\n hash,\n ],\n });\n\n logger.info(`Published package: ${data.manifest.id}@${data.manifest.version}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to publish package', error as Error);\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n },\n\n async get(packageId: string, version: string = 'latest') {\n try {\n const sql = version === 'latest'\n ? `SELECT * FROM sys_packages WHERE id = ? ORDER BY created_at DESC LIMIT 1`\n : `SELECT * FROM sys_packages WHERE id = ? AND version = ?`;\n\n const args = version === 'latest' ? [packageId] : [packageId, version];\n const result = await objectql.execute!({ sql, args });\n const rows = normalizeRows(result);\n\n if (rows.length === 0) {\n return null;\n }\n\n const row = rows[0];\n return {\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n };\n } catch (error) {\n logger.error(`Failed to get package: ${packageId}`, error as Error);\n return null;\n }\n },\n\n async list() {\n try {\n const result = await objectql.execute!({\n sql: `\n SELECT * FROM sys_packages\n WHERE (id, created_at) IN (\n SELECT id, MAX(created_at) FROM sys_packages GROUP BY id\n )\n ORDER BY created_at DESC\n `,\n });\n\n return normalizeRows(result).map((row: any) => ({\n id: row.id,\n version: row.version,\n manifest: JSON.parse(row.manifest),\n metadata: JSON.parse(row.metadata),\n hash: row.hash,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }));\n } catch (error) {\n logger.error('Failed to list packages', error as Error);\n return [];\n }\n },\n\n async delete(packageId: string, version?: string) {\n try {\n const sql = version\n ? `DELETE FROM sys_packages WHERE id = ? AND version = ?`\n : `DELETE FROM sys_packages WHERE id = ?`;\n\n const args = version ? [packageId, version] : [packageId];\n await objectql.execute!({ sql, args });\n\n logger.info(`Deleted package: ${packageId}${version ? `@${version}` : ''}`);\n return { success: true };\n } catch (error) {\n logger.error('Failed to delete package', error as Error);\n return { success: false };\n }\n },\n };\n\n ctx.registerService('package', packageService);\n logger.info('Package service initialized');\n\n // Reconcile durable packages back into the in-memory registry (ADR-0033\n // consolidation). Packages persisted to `sys_packages` — AI-authored app\n // packages, or anything HTTP-installed in a previous run — must survive a\n // restart and surface in the registry-backed read paths (the dispatcher's\n // `/api/v1/packages` list/detail and `getMetaItems({type:'package'})`, i.e.\n // Studio's package selector). Never clobber a package already registered\n // from the filesystem. Best-effort and non-fatal.\n try {\n const registry = (objectql as unknown as { registry?: any }).registry;\n if (registry?.installPackage && registry?.getPackage) {\n let hydrated = 0;\n for (const rec of await packageService.list()) {\n const id = rec?.manifest?.id;\n if (id && !registry.getPackage(id)) {\n registry.installPackage(rec.manifest);\n hydrated++;\n }\n }\n if (hydrated > 0) {\n logger.info(`Hydrated ${hydrated} package(s) from sys_packages into registry`);\n }\n }\n } catch (error) {\n logger.debug(`Package hydration from sys_packages skipped: ${(error as Error)?.message}`);\n }\n }\n\n private async ensureTable(objectql: IDataEngine, logger: any): Promise<void> {\n try {\n // Create the sys_packages table\n await objectql.execute!({\n sql: `\n CREATE TABLE IF NOT EXISTS sys_packages (\n id TEXT NOT NULL,\n version TEXT NOT NULL,\n manifest TEXT NOT NULL,\n metadata TEXT NOT NULL,\n hash TEXT NOT NULL,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, version)\n )\n `,\n });\n\n // Create index for faster latest version queries\n await objectql.execute!({\n sql: `\n CREATE INDEX IF NOT EXISTS idx_packages_latest\n ON sys_packages(id, created_at DESC)\n `,\n });\n\n logger.debug('sys_packages table ensured');\n } catch (error) {\n // Table might already exist, log and continue\n logger.debug('sys_packages table creation skipped (may already exist)');\n }\n }\n}\n\nexport { PackageServicePlugin as default };\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/service-package",
3
- "version": "7.7.0",
3
+ "version": "7.9.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Package management service for ObjectStack — publish, install, and manage packages",
6
6
  "type": "module",
@@ -14,8 +14,8 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@objectstack/core": "7.7.0",
18
- "@objectstack/spec": "7.7.0"
17
+ "@objectstack/core": "7.9.0",
18
+ "@objectstack/spec": "7.9.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^25.9.1",