webspresso 0.0.91 → 0.0.94

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 (86) hide show
  1. package/README.md +103 -2864
  2. package/bin/commands/admin-password.js +8 -2
  3. package/bin/commands/api.js +7 -1
  4. package/bin/commands/favicon-generate.js +6 -4
  5. package/bin/commands/mcp.js +162 -0
  6. package/bin/commands/new.js +7 -1
  7. package/bin/commands/page.js +7 -1
  8. package/bin/commands/polar-migrate.js +50 -0
  9. package/bin/commands/seed.js +7 -1
  10. package/bin/commands/service.js +8 -2
  11. package/bin/commands/skill.js +7 -1
  12. package/bin/webspresso.js +4 -0
  13. package/core/auth/tokens.js +16 -0
  14. package/core/compileSchema.js +1 -5
  15. package/core/compression/compressible.js +17 -5
  16. package/core/compression/compression-stream.js +1 -1
  17. package/core/compression/middleware.js +9 -0
  18. package/core/compression/negotiate.js +23 -11
  19. package/core/kernel/app.js +2 -1
  20. package/core/kernel/index.js +5 -1
  21. package/core/orm/cache/fingerprint.js +23 -5
  22. package/core/orm/cache/layer.js +1 -1
  23. package/core/orm/eager-loader.js +54 -9
  24. package/core/orm/index.js +42 -3
  25. package/core/orm/model.js +11 -2
  26. package/core/orm/transaction.js +3 -1
  27. package/core/queue/adapters/database.js +46 -13
  28. package/core/queue/adapters/memory.js +21 -0
  29. package/core/queue/adapters/redis.js +21 -0
  30. package/core/queue/manager.js +46 -20
  31. package/core/ssr/stream.js +58 -14
  32. package/core/validation/index.js +70 -0
  33. package/index.d.ts +99 -5
  34. package/index.js +7 -1
  35. package/package.json +9 -1
  36. package/plugins/admin-panel/auth.js +10 -0
  37. package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +6 -1
  38. package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +18 -8
  39. package/plugins/admin-panel/client/parts/07-model-list.js +9 -4
  40. package/plugins/admin-panel/client/parts/08-record-list.js +20 -2
  41. package/plugins/admin-panel/index.js +65 -6
  42. package/plugins/admin-panel/modules/bulk-actions.js +9 -2
  43. package/plugins/admin-panel/modules/dashboard.js +8 -1
  44. package/plugins/content/index.js +5 -3
  45. package/plugins/data-exchange/export-xlsx.js +28 -6
  46. package/plugins/data-exchange/import.js +120 -58
  47. package/plugins/data-exchange/index.js +5 -0
  48. package/plugins/data-exchange/parse-table.js +14 -5
  49. package/plugins/data-exchange/record-selection.js +2 -0
  50. package/plugins/index.js +6 -0
  51. package/plugins/mcp/auth.js +104 -0
  52. package/plugins/mcp/discovery.js +88 -0
  53. package/plugins/mcp/index.js +208 -0
  54. package/plugins/mcp/prompts.js +149 -0
  55. package/plugins/mcp/providers/orm.js +325 -0
  56. package/plugins/mcp/providers/services.js +190 -0
  57. package/plugins/mcp/providers/system.js +87 -0
  58. package/plugins/mcp/server.js +472 -0
  59. package/plugins/mcp/transports/sse.js +156 -0
  60. package/plugins/mcp/transports/stdio.js +108 -0
  61. package/plugins/polar/.env.example +12 -0
  62. package/plugins/polar/CHANGELOG.md +38 -0
  63. package/plugins/polar/README.md +158 -0
  64. package/plugins/polar/index.js +144 -0
  65. package/plugins/polar/src/api.js +54 -0
  66. package/plugins/polar/src/checkout.js +111 -0
  67. package/plugins/polar/src/config.js +88 -0
  68. package/plugins/polar/src/env.schema.js +36 -0
  69. package/plugins/polar/src/middleware.js +37 -0
  70. package/plugins/polar/src/migration.js +58 -0
  71. package/plugins/polar/src/nunjucks-filters.js +56 -0
  72. package/plugins/polar/src/portal.js +51 -0
  73. package/plugins/polar/src/rate-limit.js +70 -0
  74. package/plugins/polar/src/routes.js +212 -0
  75. package/plugins/polar/src/sync.js +138 -0
  76. package/plugins/polar/src/urls.js +117 -0
  77. package/plugins/polar/src/user-resolver.js +195 -0
  78. package/plugins/polar/src/webhooks.js +248 -0
  79. package/src/file-router.js +203 -125
  80. package/src/helpers.js +60 -13
  81. package/src/njk-frontmatter.js +24 -14
  82. package/src/server.js +30 -12
  83. package/src/services/discovery.js +2 -1
  84. package/src/services/registry.js +2 -0
  85. package/src/services/validator.js +2 -53
  86. package/templates/skills/webspresso-usage/REFERENCE-framework.md +7 -4
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Webspresso MCP Services Provider
3
+ * Bridges Webspresso ServiceRegistry to MCP Tools with automatic Zod -> JSON Schema conversion.
4
+ * @module plugins/mcp/providers/services
5
+ */
6
+
7
+ const { zodToJsonSchema } = require('zod-to-json-schema');
8
+
9
+ /**
10
+ * Normalizes a dot-separated service name to an MCP-safe tool name
11
+ * e.g. "user.create" -> "service__user__create"
12
+ * @param {string} serviceName
13
+ * @returns {string}
14
+ */
15
+ function serviceNameToToolName(serviceName) {
16
+ return `service__${serviceName.replace(/\./g, '__').replace(/[^a-zA-Z0-9_-]/g, '_')}`;
17
+ }
18
+
19
+ /**
20
+ * Reconstructs original service name from tool name
21
+ * @param {string} toolName
22
+ * @returns {string|null}
23
+ */
24
+ function toolNameToServiceName(toolName) {
25
+ if (!toolName.startsWith('service__')) return null;
26
+ return toolName.slice('service__'.length).replace(/__/g, '.');
27
+ }
28
+
29
+ /**
30
+ * Check if a service name matches any pattern in a list (e.g. ['user.*', 'order.get'])
31
+ * @param {string} name
32
+ * @param {Array<string>} patterns
33
+ * @returns {boolean}
34
+ */
35
+ function matchesPattern(name, patterns) {
36
+ if (!patterns || patterns.length === 0) return true;
37
+ return patterns.some((pattern) => {
38
+ if (pattern === '*' || pattern === name) return true;
39
+ if (pattern.endsWith('*')) {
40
+ const prefix = pattern.slice(0, -1);
41
+ return name.startsWith(prefix);
42
+ }
43
+ return false;
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Checks if a service is likely a mutation (create, update, delete, remove, post, send, prune, etc.)
49
+ * @param {string} serviceName
50
+ * @param {Object} [serviceDef]
51
+ * @returns {boolean}
52
+ */
53
+ function isMutationService(serviceName, serviceDef) {
54
+ if (serviceDef?.mutation !== undefined) {
55
+ return Boolean(serviceDef.mutation);
56
+ }
57
+ const parts = serviceName.toLowerCase().split('.');
58
+ const lastPart = parts[parts.length - 1];
59
+ const mutationKeywords = [
60
+ 'create',
61
+ 'add',
62
+ 'insert',
63
+ 'update',
64
+ 'patch',
65
+ 'edit',
66
+ 'delete',
67
+ 'remove',
68
+ 'destroy',
69
+ 'prune',
70
+ 'reset',
71
+ 'send',
72
+ 'dispatch',
73
+ 'cancel',
74
+ 'pay',
75
+ 'checkout',
76
+ 'execute',
77
+ 'import',
78
+ 'clear',
79
+ 'flush',
80
+ 'purge',
81
+ 'drop',
82
+ 'truncate',
83
+ ];
84
+ return mutationKeywords.some((kw) => lastPart.includes(kw));
85
+ }
86
+
87
+ /**
88
+ * Converts a Webspresso Zod schema to a clean MCP inputSchema
89
+ * @param {import('zod').ZodTypeAny} schema
90
+ * @returns {Object}
91
+ */
92
+ function convertZodToInputSchema(schema) {
93
+ if (!schema) {
94
+ return {
95
+ type: 'object',
96
+ properties: {},
97
+ additionalProperties: true,
98
+ };
99
+ }
100
+
101
+ try {
102
+ const rawSchema = zodToJsonSchema(schema, {
103
+ $refStrategy: 'none',
104
+ removeAdditionalStrategy: 'strict',
105
+ });
106
+
107
+ // Clean up definition wrapper if present
108
+ if (rawSchema && typeof rawSchema === 'object') {
109
+ const { $schema, ...clean } = rawSchema;
110
+ if (!clean.type) {
111
+ clean.type = 'object';
112
+ }
113
+ return clean;
114
+ }
115
+ return { type: 'object', properties: {} };
116
+ } catch (err) {
117
+ return {
118
+ type: 'object',
119
+ properties: {},
120
+ description: `Input schema auto-conversion error: ${err.message}`,
121
+ };
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Generates MCP tool definitions from a Webspresso ServiceRegistry
127
+ * @param {Object} options
128
+ * @param {import('../../src/services').ServiceRegistry} options.registry
129
+ * @param {Array<string>} [options.include] - Whitelist of service patterns
130
+ * @param {Array<string>} [options.exclude] - Blacklist of service patterns
131
+ * @param {boolean} [options.readOnly=false] - When true, filters out mutation services
132
+ * @param {string|Array<string>} [options.role] - Simulated user role for auth
133
+ * @returns {Array<Object>}
134
+ */
135
+ function createServiceTools(options = {}) {
136
+ const { registry, include, exclude, readOnly = false, role = 'admin' } = options;
137
+ if (!registry) return [];
138
+
139
+ const tools = [];
140
+ const serviceNames = registry.list();
141
+
142
+ for (const name of serviceNames) {
143
+ // Check include / exclude patterns
144
+ if (include && !matchesPattern(name, include)) continue;
145
+ if (exclude && matchesPattern(name, exclude)) continue;
146
+
147
+ const def = registry.get(name);
148
+ if (!def) continue;
149
+
150
+ const isMutation = isMutationService(name, def);
151
+ if (readOnly && isMutation) {
152
+ continue;
153
+ }
154
+
155
+ const toolName = serviceNameToToolName(name);
156
+ const inputSchema = convertZodToInputSchema(def.schema);
157
+
158
+ const description =
159
+ def.description ||
160
+ def.metadata?.description ||
161
+ `Executes Webspresso service '${name}'.${isMutation ? ' (Mutation)' : ' (Query)'}`;
162
+
163
+ tools.push({
164
+ name: toolName,
165
+ description,
166
+ inputSchema,
167
+ handler: async (args, ctx) => {
168
+ // Execute service via registry
169
+ const execCtx = {
170
+ ...ctx,
171
+ user: ctx.user || (role ? { id: 'mcp-agent', role } : null),
172
+ };
173
+
174
+ const result = await registry.execute(name, args, execCtx);
175
+ return result;
176
+ },
177
+ });
178
+ }
179
+
180
+ return tools;
181
+ }
182
+
183
+ module.exports = {
184
+ createServiceTools,
185
+ serviceNameToToolName,
186
+ toolNameToServiceName,
187
+ convertZodToInputSchema,
188
+ isMutationService,
189
+ matchesPattern,
190
+ };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Webspresso MCP System Provider
3
+ * Exposes application routes, services index, and health info as MCP Resources
4
+ * @module plugins/mcp/providers/system
5
+ */
6
+
7
+ /**
8
+ * Creates system MCP resources
9
+ * @param {Object} options
10
+ * @param {Object} [options.appContext]
11
+ * @param {Object} [options.serviceRegistry]
12
+ * @param {Object} [options.routes]
13
+ * @param {Object} [options.db]
14
+ * @returns {Array<Object>}
15
+ */
16
+ function createSystemResources(options = {}) {
17
+ const { appContext, serviceRegistry, routes, db } = options;
18
+
19
+ return [
20
+ {
21
+ uri: 'webspresso://routes',
22
+ name: 'Application Routes',
23
+ description: 'List of all file-based SSR and API routes mounted in the Webspresso application.',
24
+ mimeType: 'application/json',
25
+ handler: async () => {
26
+ const rawRoutes = routes || appContext?.routes || [];
27
+ if (Array.isArray(rawRoutes)) {
28
+ return rawRoutes.map((r) => ({
29
+ path: r.path || r.route,
30
+ method: r.method ? r.method.toUpperCase() : 'GET',
31
+ isApi: Boolean(r.isApi || r.path?.startsWith('/api/')),
32
+ middleware: r.middleware || [],
33
+ sourceFile: r.filePath || r.file,
34
+ }));
35
+ }
36
+ return rawRoutes;
37
+ },
38
+ },
39
+ {
40
+ uri: 'webspresso://services',
41
+ name: 'Services Directory',
42
+ description: 'List of all business logic services discovered and registered in the application.',
43
+ mimeType: 'application/json',
44
+ handler: async () => {
45
+ if (!serviceRegistry) return [];
46
+ const names = serviceRegistry.list();
47
+ return names.map((name) => {
48
+ const def = serviceRegistry.get(name);
49
+ return {
50
+ name,
51
+ description: def?.description || '',
52
+ hasSchema: Boolean(def?.schema),
53
+ hasAuth: Boolean(def?.auth),
54
+ timeout: def?.timeout || null,
55
+ transaction: Boolean(def?.transaction),
56
+ };
57
+ });
58
+ },
59
+ },
60
+ {
61
+ uri: 'webspresso://health',
62
+ name: 'System Health & Metrics',
63
+ description: 'Framework runtime information, node version, memory usage, and uptime.',
64
+ mimeType: 'application/json',
65
+ handler: async () => {
66
+ const memory = process.memoryUsage();
67
+ return {
68
+ status: 'ok',
69
+ uptimeSeconds: Math.floor(process.uptime()),
70
+ nodeVersion: process.version,
71
+ platform: process.platform,
72
+ memory: {
73
+ heapUsedMB: Math.round(memory.heapUsed / 1024 / 1024),
74
+ heapTotalMB: Math.round(memory.heapTotal / 1024 / 1024),
75
+ rssMB: Math.round(memory.rss / 1024 / 1024),
76
+ },
77
+ databaseConnected: Boolean(db),
78
+ timestamp: new Date().toISOString(),
79
+ };
80
+ },
81
+ },
82
+ ];
83
+ }
84
+
85
+ module.exports = {
86
+ createSystemResources,
87
+ };