@happyvertical/smrt-core 0.46.0 → 0.47.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/AGENTS.md +39 -0
- package/agents/generators.md +19 -5
- package/agents/system-diagnostics.md +43 -0
- package/dist/browser.js +2 -1
- package/dist/change-feed.d.ts +8 -0
- package/dist/change-feed.d.ts.map +1 -1
- package/dist/change-feed.js +1 -1
- package/dist/change-feed.js.map +1 -1
- package/dist/decorators/compatibility.d.ts +46 -0
- package/dist/decorators/compatibility.d.ts.map +1 -1
- package/dist/decorators/compatibility.js +48 -5
- package/dist/decorators/compatibility.js.map +1 -1
- package/dist/decorators/index.d.ts +119 -1
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +52 -8
- package/dist/decorators/index.js.map +1 -1
- package/dist/generators/custom-action.d.ts +379 -2
- package/dist/generators/custom-action.d.ts.map +1 -1
- package/dist/generators/custom-action.js +694 -17
- package/dist/generators/custom-action.js.map +1 -1
- package/dist/generators/index.d.ts +1 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +2 -2
- package/dist/generators/preflight-route.d.ts +12 -10
- package/dist/generators/preflight-route.d.ts.map +1 -1
- package/dist/generators/preflight-route.js +46 -14
- package/dist/generators/preflight-route.js.map +1 -1
- package/dist/generators/rest.d.ts +44 -0
- package/dist/generators/rest.d.ts.map +1 -1
- package/dist/generators/rest.js +84 -9
- package/dist/generators/rest.js.map +1 -1
- package/dist/generators.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/knowledge.d.ts.map +1 -1
- package/dist/knowledge.js +59 -15
- package/dist/knowledge.js.map +1 -1
- package/dist/manifest/static-manifest.d.ts.map +1 -1
- package/dist/manifest/static-manifest.js +125 -53
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest.json +184 -53
- package/dist/postgres-permissions.d.ts +9 -1
- package/dist/postgres-permissions.d.ts.map +1 -1
- package/dist/postgres-permissions.js +127 -13
- package/dist/postgres-permissions.js.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/shared-state.d.ts +19 -0
- package/dist/registry/shared-state.d.ts.map +1 -1
- package/dist/registry/shared-state.js +16 -1
- package/dist/registry/shared-state.js.map +1 -1
- package/dist/registry.d.ts +136 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +231 -1
- package/dist/registry.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +18 -16
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/scanner/types.d.ts +59 -6
- package/dist/scanner/types.d.ts.map +1 -1
- package/dist/scanner/types.js.map +1 -1
- package/dist/smrt-knowledge.json +42 -35
- package/dist/system/diagnostics.d.ts +299 -0
- package/dist/system/diagnostics.d.ts.map +1 -0
- package/dist/system/diagnostics.js +530 -0
- package/dist/system/diagnostics.js.map +1 -0
- package/dist/system/index.d.ts +1 -0
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +2 -1
- package/dist/utils/scanner-module.d.ts +16 -0
- package/dist/utils/scanner-module.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.js +10 -8
- package/dist/vite-plugin/api-client-entries.js.map +1 -1
- package/dist/vite-plugin/index.d.ts +34 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +82 -3
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts +28 -2
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +121 -51
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js +1 -1
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/dist/vite-plugin.js +2 -2
- package/package.json +16 -11
|
@@ -179,6 +179,50 @@ export declare class APIGenerator {
|
|
|
179
179
|
* a returned `{ ok: false, ... }` failure becomes its requested non-2xx
|
|
180
180
|
* status with a redacted payload, and success wraps as `{ action, result }`.
|
|
181
181
|
*/
|
|
182
|
+
/**
|
|
183
|
+
* Every action this transport treats as DECLARED for a collection route,
|
|
184
|
+
* paired with its manifest method definition when one is known.
|
|
185
|
+
*
|
|
186
|
+
* The union of two declaration sources, so migrating a route entry onto its
|
|
187
|
+
* method does not silently drop the route here (#2686):
|
|
188
|
+
*
|
|
189
|
+
* - a `api.routes[action]` entry, this transport's only source before;
|
|
190
|
+
* - a method whose `@method()` supplies route-shaping metadata
|
|
191
|
+
* (`httpMethod`, `path`, or `scope`).
|
|
192
|
+
*
|
|
193
|
+
* Deliberately still DECLARATION-gated rather than adopting the generated
|
|
194
|
+
* transport's default-route heuristic: this router's URL shape supports only
|
|
195
|
+
* single-segment collection paths, and widening it to every wire-able public
|
|
196
|
+
* method would publish endpoints that have never existed here. That is a
|
|
197
|
+
* separate contract change, not a compatibility fix.
|
|
198
|
+
*
|
|
199
|
+
* `declaresRuntimeRestRoute` is shared with `isRestActionRoutable`, the
|
|
200
|
+
* browser-plane preflight prediction of this same dispatch, so the route and
|
|
201
|
+
* the prediction of the route cannot drift.
|
|
202
|
+
*/
|
|
203
|
+
private declaredCollectionActions;
|
|
204
|
+
/**
|
|
205
|
+
* The method view a RUNTIME transport should read for one action: the
|
|
206
|
+
* manifest entry when the project was scanned, with its `@method()` config
|
|
207
|
+
* backfilled from the live decorator store when it is not.
|
|
208
|
+
*/
|
|
209
|
+
private runtimeMethod;
|
|
210
|
+
/**
|
|
211
|
+
* Refuse a request that matched a DECLARED action's own path and verb but
|
|
212
|
+
* whose action is withheld — or return `null` to let it fall through.
|
|
213
|
+
*
|
|
214
|
+
* Only `POST` is refused, and the asymmetry is the whole point.
|
|
215
|
+
* `getCrudAction` maps `POST` to `create` and DISCARDS the path segment, so
|
|
216
|
+
* falling through writes a row and answers 201 for a request aimed at an
|
|
217
|
+
* operation the author withheld: silent, mutating, and the opposite of what
|
|
218
|
+
* the generated SvelteKit surface does for the same URL, which 404s because
|
|
219
|
+
* it wrote no route file. Every other verb carries the segment into a by-id
|
|
220
|
+
* operation that 404s on its own when the segment is not an id — and that
|
|
221
|
+
* fall-through is load-bearing, because an object's id may legitimately equal
|
|
222
|
+
* a declared action's path, and `GET /<collection>/<id>` must keep resolving
|
|
223
|
+
* to that object (#2686).
|
|
224
|
+
*/
|
|
225
|
+
private refuseWithheldAction;
|
|
182
226
|
private dispatchCustomCollectionAction;
|
|
183
227
|
/**
|
|
184
228
|
* Public-safe projection for custom-action results, mirroring the generated
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/generators/rest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,WAAW,CAAC;AAQ/D,OAAO,KAAK,EAEV,eAAe,EAGhB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/generators/rest.ts"],"names":[],"mappings":"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"}
|
package/dist/generators/rest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isTenantScopedClassResolved, resolveDispatchTenantScope } from "../dispatch/tenant-resolver.js";
|
|
2
2
|
import { getTableVersion } from "../change-feed.js";
|
|
3
3
|
import { buildDefaultListOrderBy, resolveListLimit, resolveListOffset } from "../query-bounds.js";
|
|
4
|
-
import { buildCustomActionInvocationArgs, normalizeCustomActionFailure, resolveCustomActionMetadata } from "./custom-action.js";
|
|
4
|
+
import { buildCustomActionInvocationArgs, declaresRuntimeRestRouteShape, normalizeCustomActionFailure, readMethodDecoratorConfig, resolveCustomActionMetadata, resolveEffectiveActionMetadata } from "./custom-action.js";
|
|
5
5
|
import { isFrameworkBaseClass } from "../registry/framework-base-classes.js";
|
|
6
6
|
import { ObjectRegistry } from "../registry.js";
|
|
7
7
|
import "../dispatch/index.js";
|
|
@@ -385,28 +385,103 @@ var APIGenerator = class {
|
|
|
385
385
|
* a returned `{ ok: false, ... }` failure becomes its requested non-2xx
|
|
386
386
|
* status with a redacted payload, and success wraps as `{ action, result }`.
|
|
387
387
|
*/
|
|
388
|
+
/**
|
|
389
|
+
* Every action this transport treats as DECLARED for a collection route,
|
|
390
|
+
* paired with its manifest method definition when one is known.
|
|
391
|
+
*
|
|
392
|
+
* The union of two declaration sources, so migrating a route entry onto its
|
|
393
|
+
* method does not silently drop the route here (#2686):
|
|
394
|
+
*
|
|
395
|
+
* - a `api.routes[action]` entry, this transport's only source before;
|
|
396
|
+
* - a method whose `@method()` supplies route-shaping metadata
|
|
397
|
+
* (`httpMethod`, `path`, or `scope`).
|
|
398
|
+
*
|
|
399
|
+
* Deliberately still DECLARATION-gated rather than adopting the generated
|
|
400
|
+
* transport's default-route heuristic: this router's URL shape supports only
|
|
401
|
+
* single-segment collection paths, and widening it to every wire-able public
|
|
402
|
+
* method would publish endpoints that have never existed here. That is a
|
|
403
|
+
* separate contract change, not a compatibility fix.
|
|
404
|
+
*
|
|
405
|
+
* `declaresRuntimeRestRoute` is shared with `isRestActionRoutable`, the
|
|
406
|
+
* browser-plane preflight prediction of this same dispatch, so the route and
|
|
407
|
+
* the prediction of the route cannot drift.
|
|
408
|
+
*/
|
|
409
|
+
declaredCollectionActions(objectName, apiConfig) {
|
|
410
|
+
const names = new Set(Object.keys(apiConfig.routes ?? {}));
|
|
411
|
+
for (const name of ObjectRegistry.listDecoratedMethodNames(objectName)) if (declaresRuntimeRestRouteShape(this.runtimeMethod(objectName, name))) names.add(name);
|
|
412
|
+
return [...names].map((name) => [name, this.runtimeMethod(objectName, name)]);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* The method view a RUNTIME transport should read for one action: the
|
|
416
|
+
* manifest entry when the project was scanned, with its `@method()` config
|
|
417
|
+
* backfilled from the live decorator store when it is not.
|
|
418
|
+
*/
|
|
419
|
+
runtimeMethod(objectName, methodName) {
|
|
420
|
+
return ObjectRegistry.resolveRuntimeMethod(objectName, methodName).method;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Refuse a request that matched a DECLARED action's own path and verb but
|
|
424
|
+
* whose action is withheld — or return `null` to let it fall through.
|
|
425
|
+
*
|
|
426
|
+
* Only `POST` is refused, and the asymmetry is the whole point.
|
|
427
|
+
* `getCrudAction` maps `POST` to `create` and DISCARDS the path segment, so
|
|
428
|
+
* falling through writes a row and answers 201 for a request aimed at an
|
|
429
|
+
* operation the author withheld: silent, mutating, and the opposite of what
|
|
430
|
+
* the generated SvelteKit surface does for the same URL, which 404s because
|
|
431
|
+
* it wrote no route file. Every other verb carries the segment into a by-id
|
|
432
|
+
* operation that 404s on its own when the segment is not an id — and that
|
|
433
|
+
* fall-through is load-bearing, because an object's id may legitimately equal
|
|
434
|
+
* a declared action's path, and `GET /<collection>/<id>` must keep resolving
|
|
435
|
+
* to that object (#2686).
|
|
436
|
+
*/
|
|
437
|
+
refuseWithheldAction(req, actionName, withheldBy) {
|
|
438
|
+
if (req.method.toUpperCase() !== "POST") return null;
|
|
439
|
+
return this.createErrorResponse(404, `Custom action '${actionName}' is not exposed (${withheldBy})`);
|
|
440
|
+
}
|
|
388
441
|
async dispatchCustomCollectionAction(req, collection, pathSegment, url, objectName) {
|
|
389
442
|
const apiConfig = ObjectRegistry.getConfig(objectName)?.api;
|
|
390
|
-
if (!apiConfig || typeof apiConfig !== "object"
|
|
391
|
-
|
|
392
|
-
|
|
443
|
+
if (!apiConfig || typeof apiConfig !== "object") return null;
|
|
444
|
+
const declaredActions = this.declaredCollectionActions(objectName, apiConfig);
|
|
445
|
+
if (declaredActions.length === 0) return null;
|
|
446
|
+
for (const [actionName, declaredMethod] of declaredActions) {
|
|
447
|
+
const effective = resolveEffectiveActionMetadata({
|
|
448
|
+
actionName,
|
|
449
|
+
...declaredMethod ? { method: declaredMethod } : {},
|
|
450
|
+
apiConfig
|
|
451
|
+
});
|
|
452
|
+
const routePath = effective.path || actionName;
|
|
393
453
|
if (routePath.includes("/") || routePath !== pathSegment) continue;
|
|
394
|
-
const routeMethod = (
|
|
454
|
+
const routeMethod = (effective.httpMethod || "POST").toUpperCase();
|
|
395
455
|
if (routeMethod !== req.method.toUpperCase()) continue;
|
|
396
|
-
if (apiConfig.include && !apiConfig.include.includes(actionName))
|
|
397
|
-
|
|
456
|
+
if (apiConfig.include && !apiConfig.include.includes(actionName)) {
|
|
457
|
+
const refusal = this.refuseWithheldAction(req, actionName, "api.include");
|
|
458
|
+
if (refusal) return refusal;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (apiConfig.exclude?.includes(actionName)) {
|
|
462
|
+
const refusal = this.refuseWithheldAction(req, actionName, "api.exclude");
|
|
463
|
+
if (refusal) return refusal;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (readMethodDecoratorConfig(declaredMethod)?.expose === false) {
|
|
467
|
+
const refusal = this.refuseWithheldAction(req, actionName, "@method({ expose: false })");
|
|
468
|
+
if (refusal) return refusal;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
398
471
|
const collectionMethod = collection[actionName];
|
|
399
472
|
const itemConstructor = ObjectRegistry.getClass(objectName)?.constructor;
|
|
400
473
|
const staticMethod = itemConstructor?.[actionName];
|
|
401
474
|
const isCollectionHosted = typeof collectionMethod === "function";
|
|
402
475
|
if (!isCollectionHosted && !(!isCollectionHosted && typeof staticMethod === "function")) {
|
|
403
|
-
if (
|
|
476
|
+
if (effective.scope === "collection") return this.createErrorResponse(501, `Custom action '${actionName}' is declared but not implemented`);
|
|
477
|
+
const refusal = this.refuseWithheldAction(req, actionName, "an item-scoped declaration, which this transport does not serve");
|
|
478
|
+
if (refusal) return refusal;
|
|
404
479
|
continue;
|
|
405
480
|
}
|
|
406
481
|
const metadata = resolveCustomActionMetadata({
|
|
407
482
|
actionName,
|
|
408
483
|
apiConfig,
|
|
409
|
-
method:
|
|
484
|
+
...declaredMethod ? { method: declaredMethod } : {},
|
|
410
485
|
defaultScope: "collection"
|
|
411
486
|
});
|
|
412
487
|
if (metadata.scope !== "collection") continue;
|