@portel/photon-core 2.1.2 → 2.2.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/README.md +61 -0
- package/dist/base.d.ts +41 -1
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +63 -1
- package/dist/base.js.map +1 -1
- package/dist/channels/daemon-broker.d.ts +35 -0
- package/dist/channels/daemon-broker.d.ts.map +1 -0
- package/dist/channels/daemon-broker.js +229 -0
- package/dist/channels/daemon-broker.js.map +1 -0
- package/dist/channels/http-broker.d.ts +45 -0
- package/dist/channels/http-broker.d.ts.map +1 -0
- package/dist/channels/http-broker.js +182 -0
- package/dist/channels/http-broker.js.map +1 -0
- package/dist/channels/index.d.ts +53 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +67 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/noop-broker.d.ts +21 -0
- package/dist/channels/noop-broker.d.ts.map +1 -0
- package/dist/channels/noop-broker.js +38 -0
- package/dist/channels/noop-broker.js.map +1 -0
- package/dist/channels/redis-broker.d.ts +45 -0
- package/dist/channels/redis-broker.d.ts.map +1 -0
- package/dist/channels/redis-broker.js +214 -0
- package/dist/channels/redis-broker.js.map +1 -0
- package/dist/channels/registry.d.ts +49 -0
- package/dist/channels/registry.d.ts.map +1 -0
- package/dist/channels/registry.js +150 -0
- package/dist/channels/registry.js.map +1 -0
- package/dist/channels/types.d.ts +85 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +8 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/decorators.d.ts +48 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +64 -0
- package/dist/decorators.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/schema-extractor.d.ts +23 -2
- package/dist/schema-extractor.d.ts.map +1 -1
- package/dist/schema-extractor.js +88 -3
- package/dist/schema-extractor.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -3
- package/src/base.ts +70 -1
- package/src/channels/daemon-broker.ts +271 -0
- package/src/channels/http-broker.ts +221 -0
- package/src/channels/index.ts +96 -0
- package/src/channels/noop-broker.ts +47 -0
- package/src/channels/redis-broker.ts +252 -0
- package/src/channels/registry.ts +170 -0
- package/src/channels/types.ts +95 -0
- package/src/decorators.ts +87 -0
- package/src/index.ts +13 -0
- package/src/schema-extractor.ts +100 -3
- package/src/types.ts +23 -0
package/src/schema-extractor.ts
CHANGED
|
@@ -142,6 +142,11 @@ export class SchemaExtractor {
|
|
|
142
142
|
const isStateful = this.hasStatefulTag(jsdoc);
|
|
143
143
|
const autorun = this.hasAutorunTag(jsdoc);
|
|
144
144
|
|
|
145
|
+
// Daemon features
|
|
146
|
+
const webhook = this.extractWebhook(jsdoc, methodName);
|
|
147
|
+
const scheduled = this.extractScheduled(jsdoc, methodName);
|
|
148
|
+
const locked = this.extractLocked(jsdoc, methodName);
|
|
149
|
+
|
|
145
150
|
tools.push({
|
|
146
151
|
name: methodName,
|
|
147
152
|
description,
|
|
@@ -154,6 +159,10 @@ export class SchemaExtractor {
|
|
|
154
159
|
...(yields && yields.length > 0 ? { yields } : {}),
|
|
155
160
|
...(isStateful ? { isStateful: true } : {}),
|
|
156
161
|
...(autorun ? { autorun: true } : {}),
|
|
162
|
+
// Daemon features
|
|
163
|
+
...(webhook !== undefined ? { webhook } : {}),
|
|
164
|
+
...(scheduled ? { scheduled } : {}),
|
|
165
|
+
...(locked !== undefined ? { locked } : {}),
|
|
157
166
|
});
|
|
158
167
|
}
|
|
159
168
|
};
|
|
@@ -699,6 +708,8 @@ export class SchemaExtractor {
|
|
|
699
708
|
.replace(/\{@label\s+[^}]+\}/g, '')
|
|
700
709
|
.replace(/\{@placeholder\s+[^}]+\}/g, '')
|
|
701
710
|
.replace(/\{@hint\s+[^}]+\}/g, '')
|
|
711
|
+
.replace(/\{@hidden\s*\}/g, '')
|
|
712
|
+
.replace(/\{@accept\s+[^}]+\}/g, '')
|
|
702
713
|
.replace(/\s+/g, ' ') // Collapse multiple spaces
|
|
703
714
|
.trim();
|
|
704
715
|
paramDocs.set(paramName, cleanDesc);
|
|
@@ -710,7 +721,7 @@ export class SchemaExtractor {
|
|
|
710
721
|
/**
|
|
711
722
|
* Extract parameter constraints from JSDoc @param tags
|
|
712
723
|
* Supports inline tags: {@min}, {@max}, {@pattern}, {@format}, {@default}, {@unique},
|
|
713
|
-
* {@example}, {@multipleOf}, {@deprecated}, {@readOnly}, {@writeOnly}
|
|
724
|
+
* {@example}, {@multipleOf}, {@deprecated}, {@readOnly}, {@writeOnly}, {@accept}
|
|
714
725
|
*/
|
|
715
726
|
private extractParamConstraints(jsdocContent: string): Map<string, any> {
|
|
716
727
|
const constraints = new Map<string, any>();
|
|
@@ -847,6 +858,12 @@ export class SchemaExtractor {
|
|
|
847
858
|
paramConstraints.hidden = true;
|
|
848
859
|
}
|
|
849
860
|
|
|
861
|
+
// Extract {@accept pattern} - file type filter for file picker (e.g., "*.ts,*.js" or ".ts,.js")
|
|
862
|
+
const acceptMatch = description.match(/\{@accept\s+([^}]+)\}/);
|
|
863
|
+
if (acceptMatch) {
|
|
864
|
+
paramConstraints.accept = acceptMatch[1].trim();
|
|
865
|
+
}
|
|
866
|
+
|
|
850
867
|
if (Object.keys(paramConstraints).length > 0) {
|
|
851
868
|
constraints.set(paramName, paramConstraints);
|
|
852
869
|
}
|
|
@@ -957,6 +974,10 @@ export class SchemaExtractor {
|
|
|
957
974
|
if (constraints.hidden === true) {
|
|
958
975
|
s.hidden = true;
|
|
959
976
|
}
|
|
977
|
+
// Apply accept pattern for file picker filtering
|
|
978
|
+
if (constraints.accept !== undefined) {
|
|
979
|
+
s.accept = constraints.accept;
|
|
980
|
+
}
|
|
960
981
|
};
|
|
961
982
|
|
|
962
983
|
// Apply to anyOf schemas or direct schema
|
|
@@ -1006,6 +1027,79 @@ export class SchemaExtractor {
|
|
|
1006
1027
|
return /@autorun/i.test(jsdocContent);
|
|
1007
1028
|
}
|
|
1008
1029
|
|
|
1030
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1031
|
+
// DAEMON FEATURE EXTRACTION
|
|
1032
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Extract webhook configuration from @webhook tag or handle* prefix
|
|
1036
|
+
* - @webhook → use method name as path
|
|
1037
|
+
* - @webhook stripe → custom path "stripe"
|
|
1038
|
+
* - handle* prefix → auto-detected as webhook
|
|
1039
|
+
*/
|
|
1040
|
+
private extractWebhook(jsdocContent: string, methodName: string): boolean | string | undefined {
|
|
1041
|
+
// Check for @webhook tag with optional path
|
|
1042
|
+
// Path must start with a word character (to exclude JSDoc asterisks and closing)
|
|
1043
|
+
const webhookMatch = jsdocContent.match(/@webhook(?:\s+(\w[\w\-\/]*))?/i);
|
|
1044
|
+
if (webhookMatch) {
|
|
1045
|
+
const path = webhookMatch[1]?.trim();
|
|
1046
|
+
// Return custom path if specified, otherwise true for bare @webhook
|
|
1047
|
+
return path || true;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// Check for handle* prefix (convention)
|
|
1051
|
+
if (methodName.startsWith('handle')) {
|
|
1052
|
+
return true;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
return undefined;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/**
|
|
1059
|
+
* Extract scheduled cron expression from @scheduled, @cron tag, or scheduled* prefix
|
|
1060
|
+
* - @scheduled 0 0 * * * → cron expression
|
|
1061
|
+
* - @cron 0 0 * * * → cron expression
|
|
1062
|
+
* - scheduled* prefix requires @cron tag for the expression
|
|
1063
|
+
*/
|
|
1064
|
+
private extractScheduled(jsdocContent: string, methodName: string): string | undefined {
|
|
1065
|
+
// Check for @scheduled with cron expression
|
|
1066
|
+
const scheduledMatch = jsdocContent.match(/@scheduled\s+([*\d,\-\/]+(?:\s+[*\d,\-\/]+){4})/i);
|
|
1067
|
+
if (scheduledMatch) {
|
|
1068
|
+
return scheduledMatch[1].trim();
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// Check for @cron tag
|
|
1072
|
+
const cronMatch = jsdocContent.match(/@cron\s+([*\d,\-\/]+(?:\s+[*\d,\-\/]+){4})/i);
|
|
1073
|
+
if (cronMatch) {
|
|
1074
|
+
return cronMatch[1].trim();
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// scheduled* prefix without explicit cron - method exists but needs @cron
|
|
1078
|
+
if (methodName.startsWith('scheduled') && !cronMatch && !scheduledMatch) {
|
|
1079
|
+
// Could log warning: scheduled* method missing @cron tag
|
|
1080
|
+
return undefined;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
return undefined;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Extract lock configuration from @locked tag
|
|
1088
|
+
* - @locked → use method name as lock
|
|
1089
|
+
* - @locked board:write → custom lock name
|
|
1090
|
+
*/
|
|
1091
|
+
private extractLocked(jsdocContent: string, methodName: string): boolean | string | undefined {
|
|
1092
|
+
// Lock name must start with a word character (to exclude JSDoc asterisks and closing)
|
|
1093
|
+
const lockedMatch = jsdocContent.match(/@locked(?:\s+(\w[\w\-:]*))?/i);
|
|
1094
|
+
if (lockedMatch) {
|
|
1095
|
+
const lockName = lockedMatch[1]?.trim();
|
|
1096
|
+
// Return custom lock name if specified, otherwise true for bare @locked
|
|
1097
|
+
return lockName || true;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
return undefined;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1009
1103
|
/**
|
|
1010
1104
|
* Extract URI pattern from @Static tag
|
|
1011
1105
|
* Example: @Static github://repos/{owner}/{repo}/readme
|
|
@@ -1093,13 +1187,16 @@ export class SchemaExtractor {
|
|
|
1093
1187
|
}
|
|
1094
1188
|
|
|
1095
1189
|
/**
|
|
1096
|
-
* Extract icon from @icon tag
|
|
1190
|
+
* Extract icon from @icon tag (standalone, not inside layout hints)
|
|
1097
1191
|
* Example: @icon calculator
|
|
1098
1192
|
* Example: @icon 🧮
|
|
1099
1193
|
* Example: @icon mdi:calculator
|
|
1194
|
+
* Note: Does NOT match @icon inside layout hints like {@icon fieldname}
|
|
1100
1195
|
*/
|
|
1101
1196
|
private extractIcon(jsdocContent: string): string | undefined {
|
|
1102
|
-
|
|
1197
|
+
// First, remove layout hints blocks to avoid matching @icon inside them
|
|
1198
|
+
const withoutLayoutHints = jsdocContent.replace(/\{[^}]+\}/g, '');
|
|
1199
|
+
const iconMatch = withoutLayoutHints.match(/@icon\s+([^\s@*,]+)/i);
|
|
1103
1200
|
if (iconMatch) {
|
|
1104
1201
|
return iconMatch[1].trim();
|
|
1105
1202
|
}
|
package/src/types.ts
CHANGED
|
@@ -63,6 +63,29 @@ export interface ExtractedSchema {
|
|
|
63
63
|
isStateful?: boolean;
|
|
64
64
|
/** True if this method should auto-execute when selected (idempotent, no required params) */
|
|
65
65
|
autorun?: boolean;
|
|
66
|
+
|
|
67
|
+
// ═══ DAEMON FEATURES ═══
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Webhook endpoint path (from @webhook tag or handle* prefix)
|
|
71
|
+
* - true: use method name as path (e.g., handleGithubPush → /webhook/handleGithubPush)
|
|
72
|
+
* - string: custom path (e.g., @webhook stripe → /webhook/stripe)
|
|
73
|
+
*/
|
|
74
|
+
webhook?: boolean | string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Cron schedule expression (from @scheduled or @cron tag, or scheduled* prefix)
|
|
78
|
+
* Standard 5-field format: minute hour day-of-month month day-of-week
|
|
79
|
+
* Example: "0 0 * * *" (daily at midnight)
|
|
80
|
+
*/
|
|
81
|
+
scheduled?: string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Distributed lock name (from @locked tag)
|
|
85
|
+
* - true: use method name as lock (e.g., batchUpdate → lock "batchUpdate")
|
|
86
|
+
* - string: custom lock name (e.g., @locked board:write)
|
|
87
|
+
*/
|
|
88
|
+
locked?: boolean | string;
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
export interface PhotonMCPClass {
|