@portel/photon-core 2.8.4 → 2.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.
Files changed (57) hide show
  1. package/dist/base.d.ts +7 -7
  2. package/dist/base.d.ts.map +1 -1
  3. package/dist/base.js +8 -8
  4. package/dist/base.js.map +1 -1
  5. package/dist/collections/Collection.d.ts +2 -2
  6. package/dist/collections/Collection.js +2 -2
  7. package/dist/compiler.js +7 -7
  8. package/dist/compiler.js.map +1 -1
  9. package/dist/config.d.ts +1 -1
  10. package/dist/config.js +1 -1
  11. package/dist/index.d.ts +7 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +16 -4
  14. package/dist/index.js.map +1 -1
  15. package/dist/instance-store.d.ts +64 -0
  16. package/dist/instance-store.d.ts.map +1 -0
  17. package/dist/instance-store.js +144 -0
  18. package/dist/instance-store.js.map +1 -0
  19. package/dist/memory.d.ts +2 -2
  20. package/dist/memory.js +2 -2
  21. package/dist/middleware.d.ts +69 -0
  22. package/dist/middleware.d.ts.map +1 -0
  23. package/dist/middleware.js +570 -0
  24. package/dist/middleware.js.map +1 -0
  25. package/dist/schema-extractor.d.ts +111 -1
  26. package/dist/schema-extractor.d.ts.map +1 -1
  27. package/dist/schema-extractor.js +333 -2
  28. package/dist/schema-extractor.js.map +1 -1
  29. package/dist/stateful.d.ts +2 -0
  30. package/dist/stateful.d.ts.map +1 -1
  31. package/dist/stateful.js +2 -0
  32. package/dist/stateful.js.map +1 -1
  33. package/dist/types.d.ts +111 -5
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/types.js.map +1 -1
  36. package/dist/utils/duration.d.ts +24 -0
  37. package/dist/utils/duration.d.ts.map +1 -0
  38. package/dist/utils/duration.js +64 -0
  39. package/dist/utils/duration.js.map +1 -0
  40. package/dist/watcher.d.ts +62 -0
  41. package/dist/watcher.d.ts.map +1 -0
  42. package/dist/watcher.js +270 -0
  43. package/dist/watcher.js.map +1 -0
  44. package/package.json +2 -2
  45. package/src/base.ts +8 -8
  46. package/src/collections/Collection.ts +2 -2
  47. package/src/compiler.ts +7 -7
  48. package/src/config.ts +1 -1
  49. package/src/index.ts +34 -4
  50. package/src/instance-store.ts +155 -0
  51. package/src/memory.ts +2 -2
  52. package/src/middleware.ts +714 -0
  53. package/src/schema-extractor.ts +353 -2
  54. package/src/stateful.ts +4 -0
  55. package/src/types.ts +106 -5
  56. package/src/utils/duration.ts +67 -0
  57. package/src/watcher.ts +317 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Duration and rate parsing utilities for functional tags
3
+ *
4
+ * Supports duration strings: 30s, 5m, 1h, 1d, 500ms
5
+ * Supports rate expressions: 10/min, 100/h, 5/s
6
+ */
7
+ const DURATION_MULTIPLIERS = {
8
+ ms: 1,
9
+ s: 1_000,
10
+ sec: 1_000,
11
+ m: 60_000,
12
+ min: 60_000,
13
+ h: 3_600_000,
14
+ hr: 3_600_000,
15
+ d: 86_400_000,
16
+ day: 86_400_000,
17
+ };
18
+ /**
19
+ * Parse a duration string into milliseconds
20
+ * @example parseDuration('30s') → 30000
21
+ * @example parseDuration('5m') → 300000
22
+ * @example parseDuration('500ms') → 500
23
+ * @example parseDuration('1234') → 1234 (raw ms fallback)
24
+ */
25
+ export function parseDuration(input) {
26
+ const trimmed = input.trim();
27
+ const match = trimmed.match(/^(\d+(?:\.\d+)?)(ms|s|sec|m|min|h|hr|d|day)$/i);
28
+ if (match) {
29
+ const value = parseFloat(match[1]);
30
+ const unit = match[2].toLowerCase();
31
+ return Math.round(value * DURATION_MULTIPLIERS[unit]);
32
+ }
33
+ // Fallback: raw milliseconds
34
+ const raw = parseInt(trimmed, 10);
35
+ return isNaN(raw) ? 0 : raw;
36
+ }
37
+ const RATE_WINDOW_MULTIPLIERS = {
38
+ s: 1_000,
39
+ sec: 1_000,
40
+ m: 60_000,
41
+ min: 60_000,
42
+ h: 3_600_000,
43
+ hr: 3_600_000,
44
+ d: 86_400_000,
45
+ day: 86_400_000,
46
+ };
47
+ /**
48
+ * Parse a rate expression into count and window
49
+ * @example parseRate('10/min') → { count: 10, windowMs: 60000 }
50
+ * @example parseRate('100/h') → { count: 100, windowMs: 3600000 }
51
+ */
52
+ export function parseRate(input) {
53
+ const trimmed = input.trim();
54
+ const match = trimmed.match(/^(\d+)\/(s|sec|m|min|h|hr|d|day)$/i);
55
+ if (match) {
56
+ const count = parseInt(match[1], 10);
57
+ const unit = match[2].toLowerCase();
58
+ return { count, windowMs: RATE_WINDOW_MULTIPLIERS[unit] };
59
+ }
60
+ // Fallback: treat as count per minute
61
+ const count = parseInt(trimmed, 10);
62
+ return { count: isNaN(count) ? 10 : count, windowMs: 60_000 };
63
+ }
64
+ //# sourceMappingURL=duration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration.js","sourceRoot":"","sources":["../../src/utils/duration.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,oBAAoB,GAA2B;IACnD,EAAE,EAAE,CAAC;IACL,CAAC,EAAE,KAAK;IACR,GAAG,EAAE,KAAK;IACV,CAAC,EAAE,MAAM;IACT,GAAG,EAAE,MAAM;IACX,CAAC,EAAE,SAAS;IACZ,EAAE,EAAE,SAAS;IACb,CAAC,EAAE,UAAU;IACb,GAAG,EAAE,UAAU;CAChB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC7E,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,6BAA6B;IAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9B,CAAC;AAED,MAAM,uBAAuB,GAA2B;IACtD,CAAC,EAAE,KAAK;IACR,GAAG,EAAE,KAAK;IACV,CAAC,EAAE,MAAM;IACT,GAAG,EAAE,MAAM;IACX,CAAC,EAAE,SAAS;IACZ,EAAE,EAAE,SAAS;IACb,CAAC,EAAE,UAAU;IACb,GAAG,EAAE,UAAU;CAChB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAClE,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5D,CAAC;IACD,sCAAsC;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAChE,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * PhotonWatcher
3
+ *
4
+ * Reusable file watcher for .photon.ts/.photon.js files.
5
+ * Extracted from the daemon's battle-tested implementation with:
6
+ * - Symlink resolution (macOS fs.watch fix)
7
+ * - Debouncing (configurable, default 100ms)
8
+ * - Temp file filtering (.swp, .bak, ~, .DS_Store, vim 4913)
9
+ * - Rename handling (macOS sed -i new inode → re-establish watcher)
10
+ * - Directory watching for added/removed photons
11
+ *
12
+ * Zero new dependencies — uses Node.js fs.watch().
13
+ */
14
+ import { EventEmitter } from 'events';
15
+ export interface PhotonWatcherOptions {
16
+ /** Directories to scan for photon files */
17
+ directories: string[];
18
+ /** File extensions to watch (default: ['.photon.ts', '.photon.js']) */
19
+ extensions?: string[];
20
+ /** Debounce interval in ms (default: 100) */
21
+ debounceMs?: number;
22
+ /** Watch directories for new/removed files (default: true) */
23
+ watchDirectories?: boolean;
24
+ }
25
+ export declare class PhotonWatcher extends EventEmitter {
26
+ private options;
27
+ private fileWatchers;
28
+ private dirWatchers;
29
+ private debounceTimers;
30
+ /** Maps watchPath (real) → { photonName, originalPath } */
31
+ private watchedFiles;
32
+ /** Tracks known photon files per directory for diff-based add/remove detection */
33
+ private knownFiles;
34
+ private running;
35
+ constructor(options: PhotonWatcherOptions);
36
+ /**
37
+ * Start watching. Scans directories for existing photon files and sets up watchers.
38
+ */
39
+ start(): Promise<void>;
40
+ /**
41
+ * Stop all watchers and clean up.
42
+ */
43
+ stop(): Promise<void>;
44
+ /**
45
+ * Watch a specific photon file. Called automatically during scan,
46
+ * but can also be called manually for dynamically discovered files.
47
+ */
48
+ watchFile(photonName: string, filePath: string): void;
49
+ /**
50
+ * Stop watching a specific file by its original path.
51
+ */
52
+ unwatchFile(filePath: string): void;
53
+ /**
54
+ * Get a map of currently watched files: photonName → originalPath
55
+ */
56
+ getWatchedFiles(): Map<string, string>;
57
+ private handleFileEvent;
58
+ private unwatchByRealPath;
59
+ private scanDirectory;
60
+ private watchDirectory;
61
+ }
62
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,MAAM,WAAW,oBAAoB;IACnC,2CAA2C;IAC3C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA8BD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,cAAc,CAAoD;IAC1E,2DAA2D;IAC3D,OAAO,CAAC,YAAY,CAAmE;IACvF,kFAAkF;IAClF,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,oBAAoB;IAUzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB3B;;;OAGG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IA6BrD;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAUnC;;OAEG;IACH,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAYtC,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,iBAAiB;YAeX,aAAa;IAkD3B,OAAO,CAAC,cAAc;CAkCvB"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * PhotonWatcher
3
+ *
4
+ * Reusable file watcher for .photon.ts/.photon.js files.
5
+ * Extracted from the daemon's battle-tested implementation with:
6
+ * - Symlink resolution (macOS fs.watch fix)
7
+ * - Debouncing (configurable, default 100ms)
8
+ * - Temp file filtering (.swp, .bak, ~, .DS_Store, vim 4913)
9
+ * - Rename handling (macOS sed -i new inode → re-establish watcher)
10
+ * - Directory watching for added/removed photons
11
+ *
12
+ * Zero new dependencies — uses Node.js fs.watch().
13
+ */
14
+ import { EventEmitter } from 'events';
15
+ import * as fs from 'fs';
16
+ import * as fsPromises from 'fs/promises';
17
+ import * as path from 'path';
18
+ /** Temp/junk files to ignore */
19
+ const IGNORED_PATTERNS = [
20
+ /\.swp$/,
21
+ /\.bak$/,
22
+ /~$/,
23
+ /\.DS_Store$/,
24
+ /^4913$/, // vim temp file check
25
+ /\.tmp$/,
26
+ /^\.#/, // emacs lock files
27
+ ];
28
+ function isIgnored(filename) {
29
+ return IGNORED_PATTERNS.some((p) => p.test(filename));
30
+ }
31
+ function isPhotonFile(filename, extensions) {
32
+ return extensions.some((ext) => filename.endsWith(ext));
33
+ }
34
+ function photonNameFromFile(filename, extensions) {
35
+ for (const ext of extensions) {
36
+ if (filename.endsWith(ext)) {
37
+ return filename.slice(0, -ext.length);
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ export class PhotonWatcher extends EventEmitter {
43
+ options;
44
+ fileWatchers = new Map();
45
+ dirWatchers = new Map();
46
+ debounceTimers = new Map();
47
+ /** Maps watchPath (real) → { photonName, originalPath } */
48
+ watchedFiles = new Map();
49
+ /** Tracks known photon files per directory for diff-based add/remove detection */
50
+ knownFiles = new Map();
51
+ running = false;
52
+ constructor(options) {
53
+ super();
54
+ this.options = {
55
+ directories: options.directories,
56
+ extensions: options.extensions ?? ['.photon.ts', '.photon.js'],
57
+ debounceMs: options.debounceMs ?? 100,
58
+ watchDirectories: options.watchDirectories ?? true,
59
+ };
60
+ }
61
+ /**
62
+ * Start watching. Scans directories for existing photon files and sets up watchers.
63
+ */
64
+ async start() {
65
+ if (this.running)
66
+ return;
67
+ this.running = true;
68
+ for (const dir of this.options.directories) {
69
+ await this.scanDirectory(dir);
70
+ if (this.options.watchDirectories) {
71
+ this.watchDirectory(dir);
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Stop all watchers and clean up.
77
+ */
78
+ async stop() {
79
+ this.running = false;
80
+ for (const [, watcher] of this.fileWatchers) {
81
+ watcher.close();
82
+ }
83
+ this.fileWatchers.clear();
84
+ for (const [, watcher] of this.dirWatchers) {
85
+ watcher.close();
86
+ }
87
+ this.dirWatchers.clear();
88
+ for (const [, timer] of this.debounceTimers) {
89
+ clearTimeout(timer);
90
+ }
91
+ this.debounceTimers.clear();
92
+ this.watchedFiles.clear();
93
+ this.knownFiles.clear();
94
+ }
95
+ /**
96
+ * Watch a specific photon file. Called automatically during scan,
97
+ * but can also be called manually for dynamically discovered files.
98
+ */
99
+ watchFile(photonName, filePath) {
100
+ // Resolve symlink so fs.watch() fires when the real file changes.
101
+ // On macOS, fs.watch on a symlink only detects changes to the symlink inode itself.
102
+ let watchPath = filePath;
103
+ try {
104
+ watchPath = fs.realpathSync(filePath);
105
+ }
106
+ catch {
107
+ // Symlink target doesn't exist yet — fall back to original path
108
+ }
109
+ if (this.fileWatchers.has(watchPath))
110
+ return;
111
+ try {
112
+ const watcher = fs.watch(watchPath, (eventType) => {
113
+ this.handleFileEvent(eventType, watchPath, photonName, filePath);
114
+ });
115
+ watcher.on('error', (err) => {
116
+ this.emit('error', err, { photonName, path: filePath });
117
+ this.unwatchByRealPath(watchPath);
118
+ });
119
+ this.fileWatchers.set(watchPath, watcher);
120
+ this.watchedFiles.set(watchPath, { photonName, originalPath: filePath });
121
+ }
122
+ catch (err) {
123
+ this.emit('error', err, { photonName, path: filePath });
124
+ }
125
+ }
126
+ /**
127
+ * Stop watching a specific file by its original path.
128
+ */
129
+ unwatchFile(filePath) {
130
+ // Find the real path entry
131
+ for (const [watchPath, info] of this.watchedFiles) {
132
+ if (info.originalPath === filePath) {
133
+ this.unwatchByRealPath(watchPath);
134
+ return;
135
+ }
136
+ }
137
+ }
138
+ /**
139
+ * Get a map of currently watched files: photonName → originalPath
140
+ */
141
+ getWatchedFiles() {
142
+ const result = new Map();
143
+ for (const [, info] of this.watchedFiles) {
144
+ result.set(info.photonName, info.originalPath);
145
+ }
146
+ return result;
147
+ }
148
+ // ──────────────────────────────────────────────────────────────────────────────
149
+ // Internal
150
+ // ──────────────────────────────────────────────────────────────────────────────
151
+ handleFileEvent(eventType, watchPath, photonName, originalPath) {
152
+ // Debounce
153
+ const existing = this.debounceTimers.get(watchPath);
154
+ if (existing)
155
+ clearTimeout(existing);
156
+ this.debounceTimers.set(watchPath, setTimeout(() => {
157
+ this.debounceTimers.delete(watchPath);
158
+ // On macOS, editors like sed -i replace the file (new inode),
159
+ // killing the watcher. Re-watch via original path to re-resolve symlinks.
160
+ if (eventType === 'rename') {
161
+ this.unwatchByRealPath(watchPath);
162
+ if (fs.existsSync(originalPath)) {
163
+ this.watchFile(photonName, originalPath);
164
+ }
165
+ else {
166
+ this.emit('removed', photonName);
167
+ return;
168
+ }
169
+ }
170
+ if (!fs.existsSync(originalPath)) {
171
+ this.emit('removed', photonName);
172
+ return;
173
+ }
174
+ this.emit('changed', photonName, originalPath);
175
+ }, this.options.debounceMs));
176
+ }
177
+ unwatchByRealPath(watchPath) {
178
+ const watcher = this.fileWatchers.get(watchPath);
179
+ if (watcher) {
180
+ watcher.close();
181
+ this.fileWatchers.delete(watchPath);
182
+ }
183
+ this.watchedFiles.delete(watchPath);
184
+ const timer = this.debounceTimers.get(watchPath);
185
+ if (timer) {
186
+ clearTimeout(timer);
187
+ this.debounceTimers.delete(watchPath);
188
+ }
189
+ }
190
+ async scanDirectory(dir) {
191
+ let entries;
192
+ try {
193
+ entries = await fsPromises.readdir(dir, { withFileTypes: true });
194
+ }
195
+ catch (error) {
196
+ if (error.code !== 'ENOENT') {
197
+ this.emit('error', error, { directory: dir });
198
+ }
199
+ return;
200
+ }
201
+ const currentFiles = new Set();
202
+ for (const entry of entries) {
203
+ if (!entry.isFile() && !entry.isSymbolicLink())
204
+ continue;
205
+ if (isIgnored(entry.name))
206
+ continue;
207
+ if (!isPhotonFile(entry.name, this.options.extensions))
208
+ continue;
209
+ const photonName = photonNameFromFile(entry.name, this.options.extensions);
210
+ if (!photonName)
211
+ continue;
212
+ const filePath = path.join(dir, entry.name);
213
+ currentFiles.add(entry.name);
214
+ // Only emit 'added' and watch if this is a new file
215
+ const known = this.knownFiles.get(dir);
216
+ if (!known || !known.has(entry.name)) {
217
+ this.emit('added', photonName, filePath);
218
+ this.watchFile(photonName, filePath);
219
+ }
220
+ }
221
+ // Detect removals (files that were known but no longer present)
222
+ const previousFiles = this.knownFiles.get(dir);
223
+ if (previousFiles) {
224
+ for (const filename of previousFiles) {
225
+ if (!currentFiles.has(filename)) {
226
+ const photonName = photonNameFromFile(filename, this.options.extensions);
227
+ if (photonName) {
228
+ const filePath = path.join(dir, filename);
229
+ this.unwatchFile(filePath);
230
+ this.emit('removed', photonName);
231
+ }
232
+ }
233
+ }
234
+ }
235
+ this.knownFiles.set(dir, currentFiles);
236
+ }
237
+ watchDirectory(dir) {
238
+ if (this.dirWatchers.has(dir))
239
+ return;
240
+ try {
241
+ const watcher = fs.watch(dir, (eventType, filename) => {
242
+ if (!filename)
243
+ return;
244
+ if (isIgnored(filename))
245
+ return;
246
+ if (!isPhotonFile(filename, this.options.extensions))
247
+ return;
248
+ // Debounce directory events
249
+ const key = `dir:${dir}`;
250
+ const existing = this.debounceTimers.get(key);
251
+ if (existing)
252
+ clearTimeout(existing);
253
+ this.debounceTimers.set(key, setTimeout(() => {
254
+ this.debounceTimers.delete(key);
255
+ if (this.running) {
256
+ this.scanDirectory(dir);
257
+ }
258
+ }, this.options.debounceMs));
259
+ });
260
+ watcher.on('error', (err) => {
261
+ this.emit('error', err, { directory: dir });
262
+ });
263
+ this.dirWatchers.set(dir, watcher);
264
+ }
265
+ catch (err) {
266
+ this.emit('error', err, { directory: dir });
267
+ }
268
+ }
269
+ }
270
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portel/photon-core",
3
- "version": "2.8.4",
3
+ "version": "2.9.0",
4
4
  "description": "Core library for parsing, loading, and managing .photon.ts files - runtime-agnostic foundation for building custom Photon runtimes",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  "build": "tsc",
34
34
  "clean": "rm -rf dist",
35
35
  "prepublishOnly": "npm run clean && npm run build",
36
- "test": "npm run build && npx tsx tests/channels.test.ts && npx tsx tests/shared-utils.test.ts && npx tsx tests/collections.test.ts && npx tsx tests/audit.test.ts && npx tsx tests/memory.test.ts",
36
+ "test": "npm run build && npx tsx tests/channels.test.ts && npx tsx tests/shared-utils.test.ts && npx tsx tests/collections.test.ts && npx tsx tests/audit.test.ts && npx tsx tests/memory.test.ts && npx tsx tests/instance-store.test.ts && npx tsx tests/watcher.test.ts",
37
37
  "test:channels": "npx tsx tests/channels.test.ts"
38
38
  },
39
39
  "keywords": [
package/src/base.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
- * PhotonMCP Base Class
2
+ * Photon Base Class
3
3
  *
4
- * Optional base class for creating Photon MCPs.
4
+ * Optional base class for creating Photons.
5
5
  * You don't need to extend this - any class with async methods works!
6
6
  *
7
7
  * Usage:
8
8
  * ```typescript
9
- * export default class Calculator extends PhotonMCP {
9
+ * export default class Calculator extends Photon {
10
10
  * /**
11
11
  * * Add two numbers together
12
12
  * * @param a First number
@@ -29,7 +29,7 @@
29
29
  *
30
30
  * With MCP access (requires runtime support):
31
31
  * ```typescript
32
- * export default class SlackReporter extends PhotonMCP {
32
+ * export default class SlackReporter extends Photon {
33
33
  * async report() {
34
34
  * const github = this.mcp('github');
35
35
  * const issues = await github.call('list_issues', { repo: 'foo/bar' });
@@ -46,13 +46,13 @@ import { withLock as withLockHelper } from './decorators.js';
46
46
  import { MemoryProvider } from './memory.js';
47
47
 
48
48
  /**
49
- * Simple base class for creating Photon MCPs
49
+ * Simple base class for creating Photons
50
50
  *
51
- * - Class name = MCP name
51
+ * - Class name = Photon name
52
52
  * - Public async methods = Tools
53
53
  * - Return value = Tool result
54
54
  */
55
- export class PhotonMCP {
55
+ export class Photon {
56
56
  /**
57
57
  * Photon name (MCP name) - set by runtime loader
58
58
  * Used to identify the source of emitted events for injected photon routing
@@ -247,7 +247,7 @@ export class PhotonMCP {
247
247
 
248
248
  // Get all property names from prototype chain
249
249
  let current = prototype;
250
- while (current && current !== PhotonMCP.prototype) {
250
+ while (current && current !== Photon.prototype) {
251
251
  Object.getOwnPropertyNames(current).forEach((name) => {
252
252
  // Skip private methods (starting with _) and convention methods
253
253
  if (
@@ -7,9 +7,9 @@
7
7
  *
8
8
  * @example
9
9
  * ```typescript
10
- * import { PhotonMCP, Collection } from '@portel/photon-core';
10
+ * import { Photon, Collection } from '@portel/photon-core';
11
11
  *
12
- * export default class ProductCatalog extends PhotonMCP {
12
+ * export default class ProductCatalog extends Photon {
13
13
  * products = new Collection<Product>();
14
14
  *
15
15
  * async catalog() {
package/src/compiler.ts CHANGED
@@ -21,9 +21,9 @@ import * as crypto from 'crypto';
21
21
  * @returns Absolute path to the compiled .mjs file
22
22
  */
23
23
  /**
24
- * Transform arrays to reactive collections for PhotonMCP classes
24
+ * Transform arrays to reactive collections for Photon classes
25
25
  *
26
- * ZERO-EFFORT REACTIVITY: If a class extends PhotonMCP and has array properties,
26
+ * ZERO-EFFORT REACTIVITY: If a class extends Photon (or PhotonMCP) and has array properties,
27
27
  * this transform automatically:
28
28
  * 1. Injects `import { Array as ReactiveArray } from '@portel/photon-core'`
29
29
  * 2. Transforms `= []` to `= new ReactiveArray()` for class properties
@@ -32,23 +32,23 @@ import * as crypto from 'crypto';
32
32
  *
33
33
  * ```typescript
34
34
  * // Developer writes this (normal TypeScript):
35
- * export default class TodoList extends PhotonMCP {
35
+ * export default class TodoList extends Photon {
36
36
  * items: Task[] = [];
37
37
  * async add(text: string) { this.items.push({...}); }
38
38
  * }
39
39
  *
40
40
  * // Compiler transforms to:
41
41
  * import { Array as ReactiveArray } from '@portel/photon-core';
42
- * export default class TodoList extends PhotonMCP {
42
+ * export default class TodoList extends Photon {
43
43
  * items = new ReactiveArray();
44
44
  * async add(text: string) { this.items.push({...}); } // Auto-emits!
45
45
  * }
46
46
  * ```
47
47
  */
48
48
  function transformReactiveCollections(source: string): string {
49
- // Check if this is a PhotonMCP class (extends PhotonMCP)
50
- const isPhotonMCP = /class\s+\w+\s+extends\s+PhotonMCP\b/.test(source);
51
- if (!isPhotonMCP) return source;
49
+ // Check if this is a Photon class (extends Photon or extends PhotonMCP)
50
+ const isPhotonClass = /class\s+\w+\s+extends\s+(?:Photon|PhotonMCP)\b/.test(source);
51
+ if (!isPhotonClass) return source;
52
52
 
53
53
  // Check if there are array properties with = [] that need transformation
54
54
  // Look for patterns like: `items: Type[] = []` or `items = []` (class properties)
package/src/config.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * ```typescript
9
9
  * import { loadPhotonConfig, savePhotonConfig, getPhotonConfigPath } from '@portel/photon-core';
10
10
  *
11
- * export default class MyPhoton extends PhotonMCP {
11
+ * export default class MyPhoton extends Photon {
12
12
  * async configure(params: { apiKey: string }) {
13
13
  * savePhotonConfig('my-photon', params);
14
14
  * return { success: true, config: params };
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * import { PhotonMCP, DependencyManager, SchemaExtractor } from '@portel/photon-core';
14
+ * import { Photon, DependencyManager, SchemaExtractor } from '@portel/photon-core';
15
15
  *
16
16
  * // Load and parse a Photon class
17
17
  * const photonClass = await import('./my-tool.photon.ts');
@@ -152,13 +152,13 @@ export {
152
152
  // ===== PHOTON-SPECIFIC EXPORTS =====
153
153
 
154
154
  // Core base class with lifecycle hooks
155
- export { PhotonMCP } from './base.js';
155
+ export { Photon, Photon as PhotonMCP } from './base.js';
156
156
 
157
157
  // Dependency management
158
158
  export { DependencyManager } from './dependency-manager.js';
159
159
 
160
160
  // Schema extraction
161
- export { SchemaExtractor } from './schema-extractor.js';
161
+ export { SchemaExtractor, detectCapabilities, type PhotonCapability } from './schema-extractor.js';
162
162
 
163
163
  // Path resolution (Photon-specific paths)
164
164
  export {
@@ -433,7 +433,7 @@ export {
433
433
  } from './audit.js';
434
434
 
435
435
  // ===== SCOPED MEMORY =====
436
- // Framework-level key-value storage (this.memory on PhotonMCP)
436
+ // Framework-level key-value storage (this.memory on Photon base class)
437
437
  export {
438
438
  MemoryProvider,
439
439
  type MemoryScope,
@@ -446,6 +446,36 @@ export {
446
446
  autoDiscoverAssets,
447
447
  } from './asset-discovery.js';
448
448
 
449
+ // ===== DURATION PARSING =====
450
+ // Duration and rate string parsing for functional tags
451
+ export { parseDuration, parseRate } from './utils/duration.js';
452
+
453
+ // ===== EXTENSIBLE MIDDLEWARE =====
454
+ // Registry-based middleware system for functional tags and custom middleware
455
+ export {
456
+ defineMiddleware,
457
+ builtinRegistry,
458
+ MiddlewareRegistry,
459
+ createStateStore,
460
+ buildMiddlewareChain,
461
+ hashParams,
462
+ BUILT_IN_VALIDATORS,
463
+ type MiddlewareDefinition,
464
+ type MiddlewareContext,
465
+ type MiddlewareHandler,
466
+ type MiddlewareState,
467
+ type MiddlewareDeclaration,
468
+ type NextFn,
469
+ } from './middleware.js';
470
+
471
+ // ===== FILE WATCHING =====
472
+ // Reusable photon file watcher with symlink resolution, debouncing, rename handling
473
+ export { PhotonWatcher, type PhotonWatcherOptions } from './watcher.js';
474
+
475
+ // ===== INSTANCE STORE =====
476
+ // Named instance state persistence for daemon, NCP, Lumina
477
+ export { InstanceStore, type InstanceStoreOptions } from './instance-store.js';
478
+
449
479
  // ===== MANAGED COLLECTIONS =====
450
480
  // Auto-emit events on mutations for seamless real-time sync
451
481
  export {