@objectstack/core 0.9.0 → 0.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @objectstack/core
2
2
 
3
+ ## 0.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Patch release for maintenance and stability improvements. All packages updated with unified versioning.
8
+ - Updated dependencies
9
+ - @objectstack/spec@0.9.1
10
+
3
11
  ## 0.8.2
4
12
 
5
13
  ### Patch Changes
package/README.md CHANGED
@@ -82,6 +82,42 @@ const service = kernel.getService('my-service');
82
82
  await kernel.shutdown();
83
83
  ```
84
84
 
85
+ ## 🤖 AI Quick Reference
86
+
87
+ **For AI Agents:** This package implements a microkernel architecture. Key concepts:
88
+
89
+ 1. **Plugin Lifecycle**: `init()` → `start()` → `destroy()`
90
+ 2. **Service Registry**: Share functionality via `ctx.registerService(name, service)` and `ctx.getService(name)`
91
+ 3. **Dependencies**: Declare plugin dependencies for automatic load ordering
92
+ 4. **Hooks/Events**: Decouple plugins with `ctx.hook(event, handler)` and `ctx.trigger(event, ...args)`
93
+ 5. **Logger**: Always use `ctx.logger` for consistent, structured logging
94
+
95
+ **Common Plugin Pattern:**
96
+ ```typescript
97
+ const plugin: Plugin = {
98
+ name: 'my-plugin',
99
+ dependencies: ['other-plugin'], // Load after these plugins
100
+
101
+ async init(ctx: PluginContext) {
102
+ // Register services and hooks
103
+ const otherService = ctx.getService('other-service');
104
+ ctx.registerService('my-service', new MyService(otherService));
105
+ ctx.hook('data:created', async (data) => { /* ... */ });
106
+ },
107
+
108
+ async start(ctx: PluginContext) {
109
+ // Execute business logic
110
+ const service = ctx.getService('my-service');
111
+ await service.initialize();
112
+ },
113
+
114
+ async destroy() {
115
+ // Cleanup resources
116
+ await service.close();
117
+ }
118
+ };
119
+ ```
120
+
85
121
  ## Configurable Logger
86
122
 
87
123
  The logger uses **[Pino](https://github.com/pinojs/pino)** for Node.js environments (high-performance, low-overhead) and a simple console-based logger for browsers. It automatically detects the runtime environment.
package/dist/logger.d.ts CHANGED
@@ -20,6 +20,7 @@ export declare class ObjectLogger implements Logger {
20
20
  private isNode;
21
21
  private pinoLogger?;
22
22
  private pinoInstance?;
23
+ private require?;
23
24
  constructor(config?: Partial<LoggerConfig>);
24
25
  /**
25
26
  * Initialize Pino logger for Node.js
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,0BAA0B,CAAC;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,YAAW,MAAM;IACvC,OAAO,CAAC,MAAM,CAAkJ;IAChK,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,UAAU,CAAC,CAAM;IACzB,OAAO,CAAC,YAAY,CAAC,CAAM;gBAEf,MAAM,GAAE,OAAO,CAAC,YAAY,CAAM;IAwB9C;;OAEG;IACH,OAAO,CAAC,cAAc;IA+EtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqBvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsCxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAelB;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQxD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQvD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQvD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IASvE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IASvE;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,YAAY;IAYjD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY;IAIzD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAG7C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAEzE"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,0BAA0B,CAAC;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,YAAW,MAAM;IACvC,OAAO,CAAC,MAAM,CAAkJ;IAChK,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,UAAU,CAAC,CAAM;IACzB,OAAO,CAAC,YAAY,CAAC,CAAM;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAM;gBAEV,MAAM,GAAE,OAAO,CAAC,YAAY,CAAM;IAwB9C;;OAEG;IACH,OAAO,CAAC,cAAc;IAuGtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqBvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsCxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAelB;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQxD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQvD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQvD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IASvE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IASvE;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,YAAY;IAYjD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY;IAIzD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAG7C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAEzE"}
package/dist/logger.js CHANGED
@@ -42,8 +42,12 @@ export class ObjectLogger {
42
42
  if (!this.isNode)
43
43
  return;
44
44
  try {
45
- // Dynamic import for Pino (Node.js only)
46
- const pino = require('pino');
45
+ // Create require function dynamically for Node.js (avoids bundling issues in browser)
46
+ // @ts-ignore - dynamic import of Node.js module
47
+ const { createRequire } = eval('require("module")');
48
+ this.require = createRequire(import.meta.url);
49
+ // Synchronous import for Pino using createRequire (works in ESM)
50
+ const pino = this.require('pino');
47
51
  // Build Pino options
48
52
  const pinoOptions = {
49
53
  level: this.config.level,
@@ -60,15 +64,35 @@ export class ObjectLogger {
60
64
  const targets = [];
61
65
  // Console transport
62
66
  if (this.config.format === 'pretty') {
63
- targets.push({
64
- target: 'pino-pretty',
65
- options: {
66
- colorize: true,
67
- translateTime: 'SYS:standard',
68
- ignore: 'pid,hostname'
69
- },
70
- level: this.config.level
71
- });
67
+ // Check if pino-pretty is available
68
+ let hasPretty = false;
69
+ try {
70
+ this.require.resolve('pino-pretty');
71
+ hasPretty = true;
72
+ }
73
+ catch (e) {
74
+ // ignore
75
+ }
76
+ if (hasPretty) {
77
+ targets.push({
78
+ target: 'pino-pretty',
79
+ options: {
80
+ colorize: true,
81
+ translateTime: 'SYS:standard',
82
+ ignore: 'pid,hostname'
83
+ },
84
+ level: this.config.level
85
+ });
86
+ }
87
+ else {
88
+ console.warn('[Logger] pino-pretty not found. Install it for pretty logging: pnpm add -D pino-pretty');
89
+ // Fallback to text/simple
90
+ targets.push({
91
+ target: 'pino/file',
92
+ options: { destination: 1 },
93
+ level: this.config.level
94
+ });
95
+ }
72
96
  }
73
97
  else if (this.config.format === 'json') {
74
98
  // JSON to stdout
@@ -2,9 +2,9 @@
2
2
  let cryptoModule = null;
3
3
  if (typeof globalThis.window === 'undefined') {
4
4
  try {
5
- // Dynamic import for Node.js crypto module
6
- // eslint-disable-next-line @typescript-eslint/no-var-requires
7
- cryptoModule = require('crypto');
5
+ // Dynamic import for Node.js crypto module (using eval to avoid bundling issues)
6
+ // @ts-ignore - dynamic require for Node.js
7
+ cryptoModule = eval('require("crypto")');
8
8
  }
9
9
  catch {
10
10
  // Crypto module not available (e.g., browser environment)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/core",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Microkernel Core for ObjectStack",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,7 +14,7 @@
14
14
  "pino": "^8.17.0",
15
15
  "pino-pretty": "^10.3.0",
16
16
  "zod": "^4.3.6",
17
- "@objectstack/spec": "0.9.0"
17
+ "@objectstack/spec": "0.9.1"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "pino": "^8.0.0"
package/src/logger.ts CHANGED
@@ -21,6 +21,7 @@ export class ObjectLogger implements Logger {
21
21
  private isNode: boolean;
22
22
  private pinoLogger?: any; // Pino logger instance for Node.js
23
23
  private pinoInstance?: any; // Base Pino instance for creating child loggers
24
+ private require?: any; // CommonJS require function for Node.js
24
25
 
25
26
  constructor(config: Partial<LoggerConfig> = {}) {
26
27
  // Detect runtime environment
@@ -53,8 +54,13 @@ export class ObjectLogger implements Logger {
53
54
  if (!this.isNode) return;
54
55
 
55
56
  try {
56
- // Dynamic import for Pino (Node.js only)
57
- const pino = require('pino');
57
+ // Create require function dynamically for Node.js (avoids bundling issues in browser)
58
+ // @ts-ignore - dynamic import of Node.js module
59
+ const { createRequire } = eval('require("module")');
60
+ this.require = createRequire(import.meta.url);
61
+
62
+ // Synchronous import for Pino using createRequire (works in ESM)
63
+ const pino = this.require('pino');
58
64
 
59
65
  // Build Pino options
60
66
  const pinoOptions: any = {
@@ -75,15 +81,34 @@ export class ObjectLogger implements Logger {
75
81
 
76
82
  // Console transport
77
83
  if (this.config.format === 'pretty') {
78
- targets.push({
79
- target: 'pino-pretty',
80
- options: {
81
- colorize: true,
82
- translateTime: 'SYS:standard',
83
- ignore: 'pid,hostname'
84
- },
85
- level: this.config.level
86
- });
84
+ // Check if pino-pretty is available
85
+ let hasPretty = false;
86
+ try {
87
+ this.require.resolve('pino-pretty');
88
+ hasPretty = true;
89
+ } catch (e) {
90
+ // ignore
91
+ }
92
+
93
+ if (hasPretty) {
94
+ targets.push({
95
+ target: 'pino-pretty',
96
+ options: {
97
+ colorize: true,
98
+ translateTime: 'SYS:standard',
99
+ ignore: 'pid,hostname'
100
+ },
101
+ level: this.config.level
102
+ });
103
+ } else {
104
+ console.warn('[Logger] pino-pretty not found. Install it for pretty logging: pnpm add -D pino-pretty');
105
+ // Fallback to text/simple
106
+ targets.push({
107
+ target: 'pino/file',
108
+ options: { destination: 1 },
109
+ level: this.config.level
110
+ });
111
+ }
87
112
  } else if (this.config.format === 'json') {
88
113
  // JSON to stdout
89
114
  targets.push({
@@ -5,9 +5,9 @@ import type { PluginMetadata } from '../plugin-loader.js';
5
5
  let cryptoModule: typeof import('crypto') | null = null;
6
6
  if (typeof (globalThis as any).window === 'undefined') {
7
7
  try {
8
- // Dynamic import for Node.js crypto module
9
- // eslint-disable-next-line @typescript-eslint/no-var-requires
10
- cryptoModule = require('crypto');
8
+ // Dynamic import for Node.js crypto module (using eval to avoid bundling issues)
9
+ // @ts-ignore - dynamic require for Node.js
10
+ cryptoModule = eval('require("crypto")');
11
11
  } catch {
12
12
  // Crypto module not available (e.g., browser environment)
13
13
  }