@happyvertical/smrt-core 0.46.0 → 0.47.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/AGENTS.md +38 -0
- 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 +4 -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 +6 -1
- package/dist/postgres-permissions.d.ts.map +1 -1
- package/dist/postgres-permissions.js +78 -7
- 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 +33 -32
- 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.map +1 -1
- package/dist/vite-plugin/index.js +1 -1
- 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/package.json +10 -5
package/AGENTS.md
CHANGED
|
@@ -53,6 +53,44 @@ and repository rules.
|
|
|
53
53
|
constructor, explicit package, and isolated one-object manifest. Never infer
|
|
54
54
|
ownership from paths, simple names, or table names; packages can share names.
|
|
55
55
|
Consumer regression gate: `packages/bundle-gate/src/__tests__/registry-identity.spec.ts`.
|
|
56
|
+
- API custom-action eligibility has ONE resolver, `resolveApiMethodExposure()`
|
|
57
|
+
in `generators/custom-action.ts`: both SvelteKit route emitters,
|
|
58
|
+
`resolveApiActionSet`, and `knowledge.ts` read it, and a new consumer must too
|
|
59
|
+
— a local mirror is how a method gets reported unavailable while its route
|
|
60
|
+
file is still written. A public method routes by default only when every
|
|
61
|
+
parameter is JSON-shaped; `@method({ expose })` overrides in both directions,
|
|
62
|
+
`expose: true` bypasses the heuristic ALONE, and an explicit `api.include` or
|
|
63
|
+
`api.routes` entry keeps its pre-#2686 route. Fail closed on scanner
|
|
64
|
+
uncertainty: read `parameters[].typeUnresolved`, never the `'any'` it
|
|
65
|
+
substitutes. Accepting `Date` as wire-able and hydrating it
|
|
66
|
+
(`toCustomActionDate`) are one decision — changing either breaks the other.
|
|
67
|
+
The runtime `APIGenerator` transport stays declaration-gated: `rest.ts`
|
|
68
|
+
dispatch and `preflight-route.ts` prediction both read
|
|
69
|
+
`declaresRuntimeRestRoute()`, which must accept every `ApiCustomRouteConfig`
|
|
70
|
+
option so a sweep moving one onto its method cannot delete the endpoint. Its
|
|
71
|
+
twin `declaresRuntimeRestRouteShape()` deliberately ignores `expose: false`:
|
|
72
|
+
the dispatcher must still SEE a withheld declaration to answer 404, because
|
|
73
|
+
`POST /<collection>/<segment>` resolves to `create` when nothing claims the
|
|
74
|
+
segment. Split unions and type arguments with `splitTopLevel()` — a naive
|
|
75
|
+
`split('|')` truncates `Record<string, Asset | null>` into fragments that
|
|
76
|
+
match no rule and are then accepted, widening the gate. `extractTypeName`
|
|
77
|
+
returns `null` for a generic with an unresolvable ARGUMENT or a union with an
|
|
78
|
+
unresolvable BRANCH so those reach that fail-closed path instead of arriving
|
|
79
|
+
as a bare `'Array'`. Runtime transports read
|
|
80
|
+
`ObjectRegistry.resolveRuntimeMethod()`, which tries the item class's manifest
|
|
81
|
+
entry, then the COLLECTION class's (where a collection-hosted action's
|
|
82
|
+
parameters live), then the live `@method()` store — keyed by CONSTRUCTOR,
|
|
83
|
+
never by simple name (`Account` exists in two packages), and recording
|
|
84
|
+
`isStatic` because an unscanned runtime has no manifest to recover the
|
|
85
|
+
receiver from. `isRestActionRoutable` ANDs "declared" with that receiver, so
|
|
86
|
+
it never predicts `allow` for an action dispatch refuses. A declared action
|
|
87
|
+
with no receiver is refused (501 collection-scoped, 404 item-scoped), never
|
|
88
|
+
allowed to fall through into `create`. All eight consumers read the resolver,
|
|
89
|
+
including `packages/smrt-workbench/src/discovery.ts`; it imports the
|
|
90
|
+
`./generators/custom-action` LEAF subpath, not `./generators`, because that
|
|
91
|
+
barrel value-re-exports `MCPGenerator` and so drags `@happyvertical/ai` and
|
|
92
|
+
`@happyvertical/sql` into a build-time helper (2 modules vs 109). Keep
|
|
93
|
+
`custom-action.ts` free of value imports outside `tools/tool-generator`.
|
|
56
94
|
|
|
57
95
|
## Gotchas
|
|
58
96
|
|
|
@@ -8,7 +8,53 @@ export interface CompatiblePropertyDecorator<This = unknown, Value = unknown> {
|
|
|
8
8
|
(target: object, propertyKey: string | symbol): void;
|
|
9
9
|
(value: undefined, context: ClassFieldDecoratorContext<This, Value>): void;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* A method decorator that works under BOTH decorator implementations, the same
|
|
13
|
+
* way {@link CompatiblePropertyDecorator} does for class fields.
|
|
14
|
+
*
|
|
15
|
+
* Legacy (TypeScript `experimentalDecorators`, and the Oxc legacy mode this
|
|
16
|
+
* repo builds with) calls `(target, propertyKey, descriptor)`, where `target`
|
|
17
|
+
* is the prototype for an instance method and the constructor for a static
|
|
18
|
+
* one. TC39 standard decorators call `(value, context)`. Returning `void` from
|
|
19
|
+
* either leaves the method untouched, which is all a metadata-only decorator
|
|
20
|
+
* needs (#2686).
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The constraint `ClassMethodDecoratorContext<This, Value>` imposes on its
|
|
24
|
+
* `Value`, restated so this module's own generics can satisfy it. Any narrower
|
|
25
|
+
* spelling (`...args: never`, `unknown[]`) is rejected by the lib type, and a
|
|
26
|
+
* method decorator has to accept every method signature anyway.
|
|
27
|
+
*/
|
|
28
|
+
type AnyMethodOf<This> = (this: This, ...args: any) => any;
|
|
29
|
+
type AnyMethod = (this: any, ...args: any) => any;
|
|
30
|
+
export type CompatibleMethodDecoratorContext<This, Value extends AnyMethodOf<This>> = string | symbol | ClassMethodDecoratorContext<This, Value>;
|
|
31
|
+
export interface CompatibleMethodDecorator<This = unknown, Value extends AnyMethodOf<This> = AnyMethod> {
|
|
32
|
+
(target: object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): void;
|
|
33
|
+
(value: Value, context: ClassMethodDecoratorContext<This, Value>): void;
|
|
34
|
+
}
|
|
11
35
|
export declare function resolveDecoratorClassName(target: unknown): string | undefined;
|
|
12
36
|
export declare function applyPendingDecoratorRegistrations(target: Function, decoratorContext?: ClassDecoratorContext): void;
|
|
37
|
+
/**
|
|
38
|
+
* Register a method decorator's metadata under the decorated class's name,
|
|
39
|
+
* under whichever decorator implementation is running.
|
|
40
|
+
*
|
|
41
|
+
* The class-field twin below is the model, but the two cannot share one
|
|
42
|
+
* function: their legacy signatures differ (a method decorator receives a
|
|
43
|
+
* property descriptor as a third argument), and a static method's legacy
|
|
44
|
+
* `target` is the CONSTRUCTOR while an instance method's is the prototype —
|
|
45
|
+
* `getDecoratorConstructor` already handles both, which is why the receiver
|
|
46
|
+
* resolution is shared even though the entry point is not.
|
|
47
|
+
*
|
|
48
|
+
* Registration is keyed by the CONSTRUCTOR, not by its name: two packages may
|
|
49
|
+
* legitimately declare a class with the same simple name (`Account` exists in
|
|
50
|
+
* both `smrt-ledgers` and `smrt-messages`), and the kernel forbids inferring
|
|
51
|
+
* ownership from simple names. A name-keyed store would let one package's
|
|
52
|
+
* `@method({ expose: false })` withhold the other's identically-named action.
|
|
53
|
+
*
|
|
54
|
+
* Metadata-only: nothing is wrapped and nothing is returned, so the decorated
|
|
55
|
+
* method keeps its identity and remains directly callable (#2686).
|
|
56
|
+
*/
|
|
57
|
+
export declare function registerCompatibleMethodDecorator<This, Value extends AnyMethodOf<This>>(targetOrValue: LegacyPropertyDecoratorTarget | Value | undefined, propertyKeyOrContext: CompatibleMethodDecoratorContext<This, Value>, registerMethodDecorator: (ctor: Function, methodName: string, isStatic: boolean) => void): void;
|
|
13
58
|
export declare function registerCompatibleFieldDecorator<This, Value>(targetOrValue: LegacyPropertyDecoratorTarget | undefined, propertyKeyOrContext: CompatiblePropertyDecoratorContext<This, Value>, registerFieldDecorator: (className: string, propertyKey: string) => void): void;
|
|
59
|
+
export {};
|
|
14
60
|
//# sourceMappingURL=compatibility.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/decorators/compatibility.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,WAAW,CAAC,EAAE,QAAQ,GAAG;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kCAAkC,CAAC,IAAI,EAAE,KAAK,IACtD,MAAM,GACN,MAAM,GACN,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAE5C,MAAM,WAAW,2BAA2B,CAAC,IAAI,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO;IAC1E,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrD,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CAC5E;
|
|
1
|
+
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/decorators/compatibility.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,WAAW,CAAC,EAAE,QAAQ,GAAG;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kCAAkC,CAAC,IAAI,EAAE,KAAK,IACtD,MAAM,GACN,MAAM,GACN,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAE5C,MAAM,WAAW,2BAA2B,CAAC,IAAI,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO;IAC1E,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrD,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CAC5E;AAED;;;;;;;;;;GAUG;AACH;;;;;GAKG;AAEH,KAAK,WAAW,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;AAG3D,KAAK,SAAS,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;AAElD,MAAM,MAAM,gCAAgC,CAC1C,IAAI,EACJ,KAAK,SAAS,WAAW,CAAC,IAAI,CAAC,IAC7B,MAAM,GAAG,MAAM,GAAG,2BAA2B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAE/D,MAAM,WAAW,yBAAyB,CACxC,IAAI,GAAG,OAAO,EACd,KAAK,SAAS,WAAW,CAAC,IAAI,CAAC,GAAG,SAAS;IAE3C,CACE,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAAC;IACR,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,2BAA2B,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CACzE;AA4FD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAU7E;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,QAAQ,EAChB,gBAAgB,CAAC,EAAE,qBAAqB,GACvC,IAAI,CAsBN;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iCAAiC,CAC/C,IAAI,EACJ,KAAK,SAAS,WAAW,CAAC,IAAI,CAAC,EAE/B,aAAa,EAAE,6BAA6B,GAAG,KAAK,GAAG,SAAS,EAChE,oBAAoB,EAAE,gCAAgC,CAAC,IAAI,EAAE,KAAK,CAAC,EACnE,uBAAuB,EAAE,CACvB,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,KACd,IAAI,GACR,IAAI,CA8CN;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,KAAK,EAC1D,aAAa,EAAE,6BAA6B,GAAG,SAAS,EACxD,oBAAoB,EAAE,kCAAkC,CAAC,IAAI,EAAE,KAAK,CAAC,EACrE,sBAAsB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,GACvE,IAAI,CAqCN"}
|
|
@@ -46,10 +46,51 @@ function applyPendingDecoratorRegistrations(target, decoratorContext) {
|
|
|
46
46
|
if (!pendingDecorators || pendingDecorators.length === 0) return;
|
|
47
47
|
for (const { register } of pendingDecorators) {
|
|
48
48
|
if (!markStandardDecoratorRegistration(target, register)) continue;
|
|
49
|
-
register(target
|
|
49
|
+
register(target);
|
|
50
50
|
}
|
|
51
51
|
Reflect.deleteProperty(metadata, PENDING_FIELD_DECORATORS_KEY);
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Register a method decorator's metadata under the decorated class's name,
|
|
55
|
+
* under whichever decorator implementation is running.
|
|
56
|
+
*
|
|
57
|
+
* The class-field twin below is the model, but the two cannot share one
|
|
58
|
+
* function: their legacy signatures differ (a method decorator receives a
|
|
59
|
+
* property descriptor as a third argument), and a static method's legacy
|
|
60
|
+
* `target` is the CONSTRUCTOR while an instance method's is the prototype —
|
|
61
|
+
* `getDecoratorConstructor` already handles both, which is why the receiver
|
|
62
|
+
* resolution is shared even though the entry point is not.
|
|
63
|
+
*
|
|
64
|
+
* Registration is keyed by the CONSTRUCTOR, not by its name: two packages may
|
|
65
|
+
* legitimately declare a class with the same simple name (`Account` exists in
|
|
66
|
+
* both `smrt-ledgers` and `smrt-messages`), and the kernel forbids inferring
|
|
67
|
+
* ownership from simple names. A name-keyed store would let one package's
|
|
68
|
+
* `@method({ expose: false })` withhold the other's identically-named action.
|
|
69
|
+
*
|
|
70
|
+
* Metadata-only: nothing is wrapped and nothing is returned, so the decorated
|
|
71
|
+
* method keeps its identity and remains directly callable (#2686).
|
|
72
|
+
*/
|
|
73
|
+
function registerCompatibleMethodDecorator(targetOrValue, propertyKeyOrContext, registerMethodDecorator) {
|
|
74
|
+
if (typeof propertyKeyOrContext === "string" || typeof propertyKeyOrContext === "symbol") {
|
|
75
|
+
const ctor = getDecoratorConstructor(targetOrValue);
|
|
76
|
+
if (ctor) registerMethodDecorator(ctor, String(propertyKeyOrContext), typeof targetOrValue === "function");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const context = propertyKeyOrContext;
|
|
80
|
+
const methodName = String(context.name);
|
|
81
|
+
const isStatic = context.static === true;
|
|
82
|
+
const register = (ctor) => registerMethodDecorator(ctor, methodName, isStatic);
|
|
83
|
+
const metadata = getDecoratorMetadata(context);
|
|
84
|
+
if (metadata) {
|
|
85
|
+
queuePendingFieldDecorator(metadata, register);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
context.addInitializer?.(function registerSmrtMethodDecorator() {
|
|
89
|
+
if (!markStandardDecoratorRegistration(this, register)) return;
|
|
90
|
+
const ctor = getDecoratorConstructor(this);
|
|
91
|
+
if (ctor) register(ctor);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
53
94
|
function registerCompatibleFieldDecorator(targetOrValue, propertyKeyOrContext, registerFieldDecorator) {
|
|
54
95
|
if (typeof propertyKeyOrContext === "string" || typeof propertyKeyOrContext === "symbol") {
|
|
55
96
|
const className = resolveDecoratorClassName(targetOrValue);
|
|
@@ -58,7 +99,9 @@ function registerCompatibleFieldDecorator(targetOrValue, propertyKeyOrContext, r
|
|
|
58
99
|
}
|
|
59
100
|
const context = propertyKeyOrContext;
|
|
60
101
|
const propertyKey = String(context.name);
|
|
61
|
-
const register = (
|
|
102
|
+
const register = (ctor) => {
|
|
103
|
+
if (ctor.name) registerFieldDecorator(ctor.name, propertyKey);
|
|
104
|
+
};
|
|
62
105
|
const metadata = getDecoratorMetadata(context);
|
|
63
106
|
if (metadata) {
|
|
64
107
|
queuePendingFieldDecorator(metadata, register);
|
|
@@ -66,11 +109,11 @@ function registerCompatibleFieldDecorator(targetOrValue, propertyKeyOrContext, r
|
|
|
66
109
|
}
|
|
67
110
|
context.addInitializer?.(function registerSmrtDecorator() {
|
|
68
111
|
if (!markStandardDecoratorRegistration(this, register)) return;
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
112
|
+
const ctor = getDecoratorConstructor(this);
|
|
113
|
+
if (ctor) register(ctor);
|
|
71
114
|
});
|
|
72
115
|
}
|
|
73
116
|
//#endregion
|
|
74
|
-
export { applyPendingDecoratorRegistrations, registerCompatibleFieldDecorator, resolveDecoratorClassName };
|
|
117
|
+
export { applyPendingDecoratorRegistrations, registerCompatibleFieldDecorator, registerCompatibleMethodDecorator, resolveDecoratorClassName };
|
|
75
118
|
|
|
76
119
|
//# sourceMappingURL=compatibility.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.js","names":[],"sources":["../../src/decorators/compatibility.ts"],"sourcesContent":["type DecoratorMetadataStore = Record<PropertyKey, unknown>;\n\nconst PENDING_FIELD_DECORATORS_KEY = Symbol.for(\n '@happyvertical/smrt-core/pending-field-decorators',\n);\nconst standardDecoratorRegistrations = new WeakMap<\n Function,\n WeakSet<(className: string) => void>\n>();\n\ntype PendingDecoratorRegistration = {\n register: (className: string) => void;\n};\n\nexport type LegacyPropertyDecoratorTarget = {\n constructor?: Function & {\n name?: string;\n };\n};\n\nexport type CompatiblePropertyDecoratorContext<This, Value> =\n | string\n | symbol\n | ClassFieldDecoratorContext<This, Value>;\n\nexport interface CompatiblePropertyDecorator<This = unknown, Value = unknown> {\n (target: object, propertyKey: string | symbol): void;\n (value: undefined, context: ClassFieldDecoratorContext<This, Value>): void;\n}\n\nfunction getDecoratorConstructor(target: unknown): Function | undefined {\n if (typeof target === 'function') {\n return target;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor;\n }\n\n return undefined;\n}\n\nfunction markStandardDecoratorRegistration(\n target: unknown,\n register: (className: string) => void,\n): boolean {\n const ctor = getDecoratorConstructor(target);\n if (!ctor) {\n return false;\n }\n\n const registeredCallbacks =\n standardDecoratorRegistrations.get(ctor) ?? new WeakSet();\n if (registeredCallbacks.has(register)) {\n return false;\n }\n\n registeredCallbacks.add(register);\n standardDecoratorRegistrations.set(ctor, registeredCallbacks);\n return true;\n}\n\nfunction getDecoratorMetadata(\n contextOrMetadata:\n | ClassFieldDecoratorContext<unknown, unknown>\n | ClassDecoratorContext\n | DecoratorMetadataStore\n | undefined,\n): DecoratorMetadataStore | undefined {\n if (!contextOrMetadata || typeof contextOrMetadata !== 'object') {\n return undefined;\n }\n\n if ('metadata' in contextOrMetadata) {\n const { metadata } = contextOrMetadata as {\n metadata?: DecoratorMetadataStore;\n };\n return metadata && typeof metadata === 'object' ? metadata : undefined;\n }\n\n return contextOrMetadata;\n}\n\nfunction getClassDecoratorMetadata(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): DecoratorMetadataStore | undefined {\n const metadataFromContext = getDecoratorMetadata(decoratorContext);\n if (metadataFromContext) {\n return metadataFromContext;\n }\n\n const metadataSymbol = (Symbol as typeof Symbol & { metadata?: symbol })\n .metadata;\n if (!metadataSymbol) {\n return undefined;\n }\n\n const metadata = (target as unknown as Record<PropertyKey, unknown>)[\n metadataSymbol\n ];\n return metadata && typeof metadata === 'object'\n ? (metadata as DecoratorMetadataStore)\n : undefined;\n}\n\nfunction queuePendingFieldDecorator(\n metadata: DecoratorMetadataStore,\n register: (className: string) => void,\n): void {\n const pendingDecorators =\n (metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined) ?? [];\n\n pendingDecorators.push({ register });\n metadata[PENDING_FIELD_DECORATORS_KEY] = pendingDecorators;\n}\n\nexport function resolveDecoratorClassName(target: unknown): string | undefined {\n if (typeof target === 'function') {\n return target.name;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor?.name;\n }\n\n return undefined;\n}\n\nexport function applyPendingDecoratorRegistrations(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): void {\n const metadata = getClassDecoratorMetadata(target, decoratorContext);\n if (!metadata) {\n return;\n }\n\n const pendingDecorators = metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined;\n if (!pendingDecorators || pendingDecorators.length === 0) {\n return;\n }\n\n for (const { register } of pendingDecorators) {\n if (!markStandardDecoratorRegistration(target, register)) {\n continue;\n }\n\n register(target.name);\n }\n\n Reflect.deleteProperty(metadata, PENDING_FIELD_DECORATORS_KEY);\n}\n\nexport function registerCompatibleFieldDecorator<This, Value>(\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<This, Value>,\n registerFieldDecorator: (className: string, propertyKey: string) => void,\n): void {\n if (\n typeof propertyKeyOrContext === 'string' ||\n typeof propertyKeyOrContext === 'symbol'\n ) {\n const className = resolveDecoratorClassName(targetOrValue);\n if (className) {\n registerFieldDecorator(className, String(propertyKeyOrContext));\n }\n return;\n }\n\n const context = propertyKeyOrContext;\n const propertyKey = String(context.name);\n const register = (className: string) =>\n registerFieldDecorator(className, propertyKey);\n const metadata = getDecoratorMetadata(context);\n\n if (metadata) {\n queuePendingFieldDecorator(metadata, register);\n return;\n }\n\n context.addInitializer?.(function registerSmrtDecorator() {\n if (!markStandardDecoratorRegistration(this, register)) {\n return;\n }\n\n const className = resolveDecoratorClassName(this);\n if (className) {\n register(className);\n }\n });\n}\n"],"mappings":";AAEA,IAAM,+BAA+B,OAAO,IAC1C,mDACF;AACA,IAAM,iDAAiC,IAAI,QAGzC;AAsBF,SAAS,wBAAwB,QAAuC;CACtE,IAAI,OAAO,WAAW,YACpB,OAAO;CAGT,IAAI,UAAU,OAAO,WAAW,UAC9B,OAAQ,OAAyC;AAIrD;AAEA,SAAS,kCACP,QACA,UACS;CACT,MAAM,OAAO,wBAAwB,MAAM;CAC3C,IAAI,CAAC,MACH,OAAO;CAGT,MAAM,sBACJ,+BAA+B,IAAI,IAAI,qBAAK,IAAI,QAAQ;CAC1D,IAAI,oBAAoB,IAAI,QAAQ,GAClC,OAAO;CAGT,oBAAoB,IAAI,QAAQ;CAChC,+BAA+B,IAAI,MAAM,mBAAmB;CAC5D,OAAO;AACT;AAEA,SAAS,qBACP,mBAKoC;CACpC,IAAI,CAAC,qBAAqB,OAAO,sBAAsB,UACrD;CAGF,IAAI,cAAc,mBAAmB;EACnC,MAAM,EAAE,aAAa;EAGrB,OAAO,YAAY,OAAO,aAAa,WAAW,WAAW,KAAA;CAC/D;CAEA,OAAO;AACT;AAEA,SAAS,0BACP,QACA,kBACoC;CACpC,MAAM,sBAAsB,qBAAqB,gBAAgB;CACjE,IAAI,qBACF,OAAO;CAGT,MAAM,iBAAkB,OACrB;CACH,IAAI,CAAC,gBACH;CAGF,MAAM,WAAY,OAChB;CAEF,OAAO,YAAY,OAAO,aAAa,WAClC,WACD,KAAA;AACN;AAEA,SAAS,2BACP,UACA,UACM;CACN,MAAM,oBACH,SAAS,iCAEQ,CAAC;CAErB,kBAAkB,KAAK,EAAE,SAAS,CAAC;CACnC,SAAS,gCAAgC;AAC3C;AAEA,SAAgB,0BAA0B,QAAqC;CAC7E,IAAI,OAAO,WAAW,YACpB,OAAO,OAAO;CAGhB,IAAI,UAAU,OAAO,WAAW,UAC9B,OAAQ,OAAyC,aAAa;AAIlE;AAEA,SAAgB,mCACd,QACA,kBACM;CACN,MAAM,WAAW,0BAA0B,QAAQ,gBAAgB;CACnE,IAAI,CAAC,UACH;CAGF,MAAM,oBAAoB,SAAS;CAGnC,IAAI,CAAC,qBAAqB,kBAAkB,WAAW,GACrD;CAGF,KAAK,MAAM,EAAE,cAAc,mBAAmB;EAC5C,IAAI,CAAC,kCAAkC,QAAQ,QAAQ,GACrD;EAGF,SAAS,OAAO,IAAI;CACtB;CAEA,QAAQ,eAAe,UAAU,4BAA4B;AAC/D;AAEA,SAAgB,iCACd,eACA,sBACA,wBACM;CACN,IACE,OAAO,yBAAyB,YAChC,OAAO,yBAAyB,UAChC;EACA,MAAM,YAAY,0BAA0B,aAAa;EACzD,IAAI,WACF,uBAAuB,WAAW,OAAO,oBAAoB,CAAC;EAEhE;CACF;CAEA,MAAM,UAAU;CAChB,MAAM,cAAc,OAAO,QAAQ,IAAI;CACvC,MAAM,YAAY,cAChB,uBAAuB,WAAW,WAAW;CAC/C,MAAM,WAAW,qBAAqB,OAAO;CAE7C,IAAI,UAAU;EACZ,2BAA2B,UAAU,QAAQ;EAC7C;CACF;CAEA,QAAQ,iBAAiB,SAAS,wBAAwB;EACxD,IAAI,CAAC,kCAAkC,MAAM,QAAQ,GACnD;EAGF,MAAM,YAAY,0BAA0B,IAAI;EAChD,IAAI,WACF,SAAS,SAAS;CAEtB,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"compatibility.js","names":[],"sources":["../../src/decorators/compatibility.ts"],"sourcesContent":["type DecoratorMetadataStore = Record<PropertyKey, unknown>;\n\nconst PENDING_FIELD_DECORATORS_KEY = Symbol.for(\n '@happyvertical/smrt-core/pending-field-decorators',\n);\nconst standardDecoratorRegistrations = new WeakMap<\n Function,\n WeakSet<(ctor: Function) => void>\n>();\n\ntype PendingDecoratorRegistration = {\n register: (ctor: Function) => void;\n};\n\nexport type LegacyPropertyDecoratorTarget = {\n constructor?: Function & {\n name?: string;\n };\n};\n\nexport type CompatiblePropertyDecoratorContext<This, Value> =\n | string\n | symbol\n | ClassFieldDecoratorContext<This, Value>;\n\nexport interface CompatiblePropertyDecorator<This = unknown, Value = unknown> {\n (target: object, propertyKey: string | symbol): void;\n (value: undefined, context: ClassFieldDecoratorContext<This, Value>): void;\n}\n\n/**\n * A method decorator that works under BOTH decorator implementations, the same\n * way {@link CompatiblePropertyDecorator} does for class fields.\n *\n * Legacy (TypeScript `experimentalDecorators`, and the Oxc legacy mode this\n * repo builds with) calls `(target, propertyKey, descriptor)`, where `target`\n * is the prototype for an instance method and the constructor for a static\n * one. TC39 standard decorators call `(value, context)`. Returning `void` from\n * either leaves the method untouched, which is all a metadata-only decorator\n * needs (#2686).\n */\n/**\n * The constraint `ClassMethodDecoratorContext<This, Value>` imposes on its\n * `Value`, restated so this module's own generics can satisfy it. Any narrower\n * spelling (`...args: never`, `unknown[]`) is rejected by the lib type, and a\n * method decorator has to accept every method signature anyway.\n */\n// biome-ignore lint/suspicious/noExplicitAny: mirrors the lib's own `ClassMethodDecoratorContext` constraint; a narrower type does not satisfy it. Same rationale as `SmrtObjectConstructor` in registry/types.ts. S4 #1579.\ntype AnyMethodOf<This> = (this: This, ...args: any) => any;\n\n// biome-ignore lint/suspicious/noExplicitAny: see AnyMethodOf above. S4 #1579.\ntype AnyMethod = (this: any, ...args: any) => any;\n\nexport type CompatibleMethodDecoratorContext<\n This,\n Value extends AnyMethodOf<This>,\n> = string | symbol | ClassMethodDecoratorContext<This, Value>;\n\nexport interface CompatibleMethodDecorator<\n This = unknown,\n Value extends AnyMethodOf<This> = AnyMethod,\n> {\n (\n target: object,\n propertyKey: string | symbol,\n descriptor?: PropertyDescriptor,\n ): void;\n (value: Value, context: ClassMethodDecoratorContext<This, Value>): void;\n}\n\nfunction getDecoratorConstructor(target: unknown): Function | undefined {\n if (typeof target === 'function') {\n return target;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor;\n }\n\n return undefined;\n}\n\nfunction markStandardDecoratorRegistration(\n target: unknown,\n register: (ctor: Function) => void,\n): boolean {\n const ctor = getDecoratorConstructor(target);\n if (!ctor) {\n return false;\n }\n\n const registeredCallbacks =\n standardDecoratorRegistrations.get(ctor) ?? new WeakSet();\n if (registeredCallbacks.has(register)) {\n return false;\n }\n\n registeredCallbacks.add(register);\n standardDecoratorRegistrations.set(ctor, registeredCallbacks);\n return true;\n}\n\nfunction getDecoratorMetadata(\n contextOrMetadata:\n | ClassFieldDecoratorContext<unknown, unknown>\n | ClassMethodDecoratorContext<unknown, AnyMethod>\n | ClassDecoratorContext\n | DecoratorMetadataStore\n | undefined,\n): DecoratorMetadataStore | undefined {\n if (!contextOrMetadata || typeof contextOrMetadata !== 'object') {\n return undefined;\n }\n\n if ('metadata' in contextOrMetadata) {\n const { metadata } = contextOrMetadata as {\n metadata?: DecoratorMetadataStore;\n };\n return metadata && typeof metadata === 'object' ? metadata : undefined;\n }\n\n return contextOrMetadata;\n}\n\nfunction getClassDecoratorMetadata(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): DecoratorMetadataStore | undefined {\n const metadataFromContext = getDecoratorMetadata(decoratorContext);\n if (metadataFromContext) {\n return metadataFromContext;\n }\n\n const metadataSymbol = (Symbol as typeof Symbol & { metadata?: symbol })\n .metadata;\n if (!metadataSymbol) {\n return undefined;\n }\n\n const metadata = (target as unknown as Record<PropertyKey, unknown>)[\n metadataSymbol\n ];\n return metadata && typeof metadata === 'object'\n ? (metadata as DecoratorMetadataStore)\n : undefined;\n}\n\nfunction queuePendingFieldDecorator(\n metadata: DecoratorMetadataStore,\n register: (ctor: Function) => void,\n): void {\n const pendingDecorators =\n (metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined) ?? [];\n\n pendingDecorators.push({ register });\n metadata[PENDING_FIELD_DECORATORS_KEY] = pendingDecorators;\n}\n\nexport function resolveDecoratorClassName(target: unknown): string | undefined {\n if (typeof target === 'function') {\n return target.name;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor?.name;\n }\n\n return undefined;\n}\n\nexport function applyPendingDecoratorRegistrations(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): void {\n const metadata = getClassDecoratorMetadata(target, decoratorContext);\n if (!metadata) {\n return;\n }\n\n const pendingDecorators = metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined;\n if (!pendingDecorators || pendingDecorators.length === 0) {\n return;\n }\n\n for (const { register } of pendingDecorators) {\n if (!markStandardDecoratorRegistration(target, register)) {\n continue;\n }\n\n register(target);\n }\n\n Reflect.deleteProperty(metadata, PENDING_FIELD_DECORATORS_KEY);\n}\n\n/**\n * Register a method decorator's metadata under the decorated class's name,\n * under whichever decorator implementation is running.\n *\n * The class-field twin below is the model, but the two cannot share one\n * function: their legacy signatures differ (a method decorator receives a\n * property descriptor as a third argument), and a static method's legacy\n * `target` is the CONSTRUCTOR while an instance method's is the prototype —\n * `getDecoratorConstructor` already handles both, which is why the receiver\n * resolution is shared even though the entry point is not.\n *\n * Registration is keyed by the CONSTRUCTOR, not by its name: two packages may\n * legitimately declare a class with the same simple name (`Account` exists in\n * both `smrt-ledgers` and `smrt-messages`), and the kernel forbids inferring\n * ownership from simple names. A name-keyed store would let one package's\n * `@method({ expose: false })` withhold the other's identically-named action.\n *\n * Metadata-only: nothing is wrapped and nothing is returned, so the decorated\n * method keeps its identity and remains directly callable (#2686).\n */\nexport function registerCompatibleMethodDecorator<\n This,\n Value extends AnyMethodOf<This>,\n>(\n targetOrValue: LegacyPropertyDecoratorTarget | Value | undefined,\n propertyKeyOrContext: CompatibleMethodDecoratorContext<This, Value>,\n registerMethodDecorator: (\n ctor: Function,\n methodName: string,\n isStatic: boolean,\n ) => void,\n): void {\n if (\n typeof propertyKeyOrContext === 'string' ||\n typeof propertyKeyOrContext === 'symbol'\n ) {\n // Legacy decorators hand a STATIC method its constructor and an instance\n // method its prototype. That distinction IS the method's receiver, and\n // nothing downstream can recover it in an unscanned runtime, so capture it\n // here (#2686).\n const ctor = getDecoratorConstructor(targetOrValue);\n if (ctor) {\n registerMethodDecorator(\n ctor,\n String(propertyKeyOrContext),\n typeof targetOrValue === 'function',\n );\n }\n return;\n }\n\n const context = propertyKeyOrContext;\n const methodName = String(context.name);\n // Standard decorators state the receiver outright.\n const isStatic = context.static === true;\n const register = (ctor: Function) =>\n registerMethodDecorator(ctor, methodName, isStatic);\n const metadata = getDecoratorMetadata(context);\n\n if (metadata) {\n queuePendingFieldDecorator(metadata, register);\n return;\n }\n\n context.addInitializer?.(function registerSmrtMethodDecorator(this: unknown) {\n // A static method's initializer runs with the constructor as `this`; an\n // instance method's runs with the instance. `getDecoratorConstructor`\n // reads the constructor in the latter case, so both land on the same class.\n if (!markStandardDecoratorRegistration(this, register)) {\n return;\n }\n\n const ctor = getDecoratorConstructor(this);\n if (ctor) {\n register(ctor);\n }\n });\n}\n\nexport function registerCompatibleFieldDecorator<This, Value>(\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<This, Value>,\n registerFieldDecorator: (className: string, propertyKey: string) => void,\n): void {\n if (\n typeof propertyKeyOrContext === 'string' ||\n typeof propertyKeyOrContext === 'symbol'\n ) {\n const className = resolveDecoratorClassName(targetOrValue);\n if (className) {\n registerFieldDecorator(className, String(propertyKeyOrContext));\n }\n return;\n }\n\n const context = propertyKeyOrContext;\n const propertyKey = String(context.name);\n // The shared queue passes the CONSTRUCTOR (the method arm needs an identity a\n // simple name cannot provide); field registration keeps its name-keyed store,\n // so it derives the name here.\n const register = (ctor: Function) => {\n if (ctor.name) registerFieldDecorator(ctor.name, propertyKey);\n };\n const metadata = getDecoratorMetadata(context);\n\n if (metadata) {\n queuePendingFieldDecorator(metadata, register);\n return;\n }\n\n context.addInitializer?.(function registerSmrtDecorator() {\n if (!markStandardDecoratorRegistration(this, register)) {\n return;\n }\n\n const ctor = getDecoratorConstructor(this);\n if (ctor) {\n register(ctor);\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { CustomActionScope, ToolEffect } from '../generators/custom-action.js';
|
|
2
|
+
import { ApiHttpMethod } from '../registry/types.js';
|
|
1
3
|
import { FieldUIHints } from '../scanner/types.js';
|
|
2
4
|
import { SQLDataType } from '../schema/types.js';
|
|
3
|
-
import { CompatiblePropertyDecorator } from './compatibility.js';
|
|
5
|
+
import { CompatibleMethodDecorator, CompatiblePropertyDecorator } from './compatibility.js';
|
|
4
6
|
export type { FieldUIHints } from '../scanner/types.js';
|
|
5
7
|
/**
|
|
6
8
|
* Meta type wrapper for STI (Single Table Inheritance) meta fields
|
|
@@ -513,4 +515,120 @@ export declare function manyToMany(relatedClass: string | Function, options?: Om
|
|
|
513
515
|
* @see {@link field} for regular (non-STI) field declarations
|
|
514
516
|
*/
|
|
515
517
|
export declare function meta(options?: FieldOptions): CompatiblePropertyDecorator;
|
|
518
|
+
/**
|
|
519
|
+
* Options for {@link method}.
|
|
520
|
+
*
|
|
521
|
+
* Every option is optional, and an omitted one falls back to the class-level
|
|
522
|
+
* `api.routes[methodName]` entry (or `ai.descriptions[methodName]` for
|
|
523
|
+
* `description`) when one exists. The merge is FIELD BY FIELD, so adding
|
|
524
|
+
* `@method({ description })` to a class that already declares a route verb and
|
|
525
|
+
* path does not reset them (#2686).
|
|
526
|
+
*/
|
|
527
|
+
export interface MethodOptions {
|
|
528
|
+
/**
|
|
529
|
+
* Override the default routing decision.
|
|
530
|
+
*
|
|
531
|
+
* Public methods are routed by default when they are WIRE-ABLE: every
|
|
532
|
+
* parameter can be built from a JSON request body or query string. Set
|
|
533
|
+
* `false` to withhold a method the heuristic accepted, `true` to expose one
|
|
534
|
+
* it rejected.
|
|
535
|
+
*
|
|
536
|
+
* `true` bypasses the heuristic and NOTHING else. It cannot manufacture a
|
|
537
|
+
* receiver, undo `api: false`, cross an `include`/`exclude` boundary, reach a
|
|
538
|
+
* non-public method, claim a CRUD verb, or hydrate a value the transport
|
|
539
|
+
* cannot build — a model-instance parameter still arrives as whatever JSON
|
|
540
|
+
* the caller sent.
|
|
541
|
+
*/
|
|
542
|
+
expose?: boolean;
|
|
543
|
+
/**
|
|
544
|
+
* Why the method is withheld. Recorded in the knowledge artifact so
|
|
545
|
+
* `smrt doctor` and agents read an explanation instead of silence.
|
|
546
|
+
*/
|
|
547
|
+
reason?: string;
|
|
548
|
+
/**
|
|
549
|
+
* HTTP verb for the generated route. Defaults to `POST`.
|
|
550
|
+
*
|
|
551
|
+
* Named `httpMethod`, not `method`: RFC 9110 calls this the request
|
|
552
|
+
* "method", so the protocol word is exactly the one that collides with the
|
|
553
|
+
* decorator's own name, and `@method({ method: 'POST' })` stutters.
|
|
554
|
+
* `httpMethod` is also already this framework's name for it — `ApiHttpMethod`
|
|
555
|
+
* is carried across the whole discovery/invoke path.
|
|
556
|
+
*
|
|
557
|
+
* Migrates from `api.routes[methodName].method`.
|
|
558
|
+
*/
|
|
559
|
+
httpMethod?: ApiHttpMethod;
|
|
560
|
+
/**
|
|
561
|
+
* Route path segment(s), used verbatim and split on `/`.
|
|
562
|
+
* Defaults to the method name. Migrates from `api.routes[methodName].path`.
|
|
563
|
+
*/
|
|
564
|
+
path?: string;
|
|
565
|
+
/**
|
|
566
|
+
* Declared receiver scope. Migrates from `api.routes[methodName].scope`.
|
|
567
|
+
*
|
|
568
|
+
* A DECLARATION checked against the method's executable receiver, not a
|
|
569
|
+
* relocation: an instance method is item-scoped and a static (or
|
|
570
|
+
* collection-class) method is collection-scoped, and no config can change
|
|
571
|
+
* that. A contradicting value is reported at build time and ignored.
|
|
572
|
+
*/
|
|
573
|
+
scope?: CustomActionScope;
|
|
574
|
+
/**
|
|
575
|
+
* Agent-visible effect classification. Omitted actions are treated as
|
|
576
|
+
* `destructive`, so missing metadata can never widen browser capability
|
|
577
|
+
* exposure. Migrates from `api.routes[methodName].effect`.
|
|
578
|
+
*/
|
|
579
|
+
effect?: ToolEffect;
|
|
580
|
+
/** Whether repeating the action with the same arguments is safe. */
|
|
581
|
+
idempotent?: boolean;
|
|
582
|
+
/** Whether the action may interact outside the SMRT application. */
|
|
583
|
+
openWorld?: boolean;
|
|
584
|
+
/**
|
|
585
|
+
* Description used by AI/tool surfaces, overriding the method's JSDoc.
|
|
586
|
+
* Migrates from `ai.descriptions[methodName]`.
|
|
587
|
+
*/
|
|
588
|
+
description?: string;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Refines how a method is exposed on generated surfaces.
|
|
592
|
+
*
|
|
593
|
+
* The method counterpart of {@link field}, and symmetric with it: a manifest
|
|
594
|
+
* records exactly two collections per object, `fields` and `methods`. Neither
|
|
595
|
+
* decorator DECLARES its member — a property is a field because it is a
|
|
596
|
+
* property, and a method is a candidate action because it is public — both
|
|
597
|
+
* REFINE what the framework already inferred. `@field()` refines an inferred
|
|
598
|
+
* column type and constraints; `@method()` refines inferred exposure, its
|
|
599
|
+
* route shape, and its tool semantics.
|
|
600
|
+
*
|
|
601
|
+
* The name is `@method()` rather than `@action()` because of the negative
|
|
602
|
+
* case: withholding a method has to read correctly, and
|
|
603
|
+
* `@action({ expose: false })` contradicts itself — declaring something an
|
|
604
|
+
* action in order to say it is not one. "Action" keeps its established meaning
|
|
605
|
+
* in the generators (a non-CRUD method exposed on a surface); this decorator
|
|
606
|
+
* is how a method BECOMES one.
|
|
607
|
+
*
|
|
608
|
+
* Metadata only: the decorated method is not wrapped and keeps its identity,
|
|
609
|
+
* so it stays directly callable.
|
|
610
|
+
*
|
|
611
|
+
* @example Shape the generated route
|
|
612
|
+
* ```typescript
|
|
613
|
+
* @method({ httpMethod: 'POST', path: 'reviews', effect: 'write' })
|
|
614
|
+
* async runReview(options?: RunContentReviewOptions) { … }
|
|
615
|
+
* ```
|
|
616
|
+
*
|
|
617
|
+
* @example Withhold a method the heuristic would have routed
|
|
618
|
+
* ```typescript
|
|
619
|
+
* @method({ expose: false, reason: 'callback registration, not a wire operation' })
|
|
620
|
+
* static registerValidator(validator: ValidatorFunction) { … }
|
|
621
|
+
* ```
|
|
622
|
+
*
|
|
623
|
+
* @example Force a route the heuristic rejected
|
|
624
|
+
* ```typescript
|
|
625
|
+
* // `expose: true` bypasses the heuristic only — this method must still
|
|
626
|
+
* // accept whatever JSON the caller sends for `asset`.
|
|
627
|
+
* @method({ expose: true })
|
|
628
|
+
* async addAsset(asset: Asset) { … }
|
|
629
|
+
* ```
|
|
630
|
+
*
|
|
631
|
+
* @see {@link field} for the property-side refinement decorator
|
|
632
|
+
*/
|
|
633
|
+
export declare function method(options?: MethodOptions): CompatibleMethodDecorator;
|
|
516
634
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"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"}
|
package/dist/decorators/index.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import { registerCompatibleFieldDecorator } from "./compatibility.js";
|
|
1
|
+
import { registerCompatibleFieldDecorator, registerCompatibleMethodDecorator } from "./compatibility.js";
|
|
2
2
|
import { ObjectRegistry } from "../registry.js";
|
|
3
3
|
//#region src/decorators/index.ts
|
|
4
4
|
/**
|
|
5
|
-
* Field decorators for SMRT objects
|
|
6
|
-
*
|
|
7
|
-
* Modern decorator-based API for defining SMRT object properties.
|
|
8
|
-
* Properties are typed as primitives with decorator metadata.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
5
|
* Resolve a relationship decorator's target argument to a class name.
|
|
12
6
|
*
|
|
13
7
|
* Accepted target forms:
|
|
@@ -407,7 +401,57 @@ function meta(options = {}) {
|
|
|
407
401
|
});
|
|
408
402
|
});
|
|
409
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* Refines how a method is exposed on generated surfaces.
|
|
406
|
+
*
|
|
407
|
+
* The method counterpart of {@link field}, and symmetric with it: a manifest
|
|
408
|
+
* records exactly two collections per object, `fields` and `methods`. Neither
|
|
409
|
+
* decorator DECLARES its member — a property is a field because it is a
|
|
410
|
+
* property, and a method is a candidate action because it is public — both
|
|
411
|
+
* REFINE what the framework already inferred. `@field()` refines an inferred
|
|
412
|
+
* column type and constraints; `@method()` refines inferred exposure, its
|
|
413
|
+
* route shape, and its tool semantics.
|
|
414
|
+
*
|
|
415
|
+
* The name is `@method()` rather than `@action()` because of the negative
|
|
416
|
+
* case: withholding a method has to read correctly, and
|
|
417
|
+
* `@action({ expose: false })` contradicts itself — declaring something an
|
|
418
|
+
* action in order to say it is not one. "Action" keeps its established meaning
|
|
419
|
+
* in the generators (a non-CRUD method exposed on a surface); this decorator
|
|
420
|
+
* is how a method BECOMES one.
|
|
421
|
+
*
|
|
422
|
+
* Metadata only: the decorated method is not wrapped and keeps its identity,
|
|
423
|
+
* so it stays directly callable.
|
|
424
|
+
*
|
|
425
|
+
* @example Shape the generated route
|
|
426
|
+
* ```typescript
|
|
427
|
+
* @method({ httpMethod: 'POST', path: 'reviews', effect: 'write' })
|
|
428
|
+
* async runReview(options?: RunContentReviewOptions) { … }
|
|
429
|
+
* ```
|
|
430
|
+
*
|
|
431
|
+
* @example Withhold a method the heuristic would have routed
|
|
432
|
+
* ```typescript
|
|
433
|
+
* @method({ expose: false, reason: 'callback registration, not a wire operation' })
|
|
434
|
+
* static registerValidator(validator: ValidatorFunction) { … }
|
|
435
|
+
* ```
|
|
436
|
+
*
|
|
437
|
+
* @example Force a route the heuristic rejected
|
|
438
|
+
* ```typescript
|
|
439
|
+
* // `expose: true` bypasses the heuristic only — this method must still
|
|
440
|
+
* // accept whatever JSON the caller sends for `asset`.
|
|
441
|
+
* @method({ expose: true })
|
|
442
|
+
* async addAsset(asset: Asset) { … }
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* @see {@link field} for the property-side refinement decorator
|
|
446
|
+
*/
|
|
447
|
+
function method(options = {}) {
|
|
448
|
+
return ((targetOrValue, propertyKeyOrContext) => {
|
|
449
|
+
registerCompatibleMethodDecorator(targetOrValue, propertyKeyOrContext, (ctor, methodName, isStatic) => {
|
|
450
|
+
ObjectRegistry.registerMethodDecorator(ctor, methodName, options, isStatic);
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
}
|
|
410
454
|
//#endregion
|
|
411
|
-
export { crossPackageRef, field, foreignKey, manyToMany, meta, oneToMany };
|
|
455
|
+
export { crossPackageRef, field, foreignKey, manyToMany, meta, method, oneToMany };
|
|
412
456
|
|
|
413
457
|
//# sourceMappingURL=index.js.map
|