@astrale-os/kernel-dsl 0.2.0-beta.39 → 0.2.0-beta.40
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/dist/v1/builder/callable/authoring.d.ts +22 -6
- package/dist/v1/builder/callable/authoring.js +13 -0
- package/dist/v1/builder/class/authoring.d.ts +5 -3
- package/dist/v1/builder/index.d.ts +2 -2
- package/dist/v1/builder/index.js +1 -1
- package/dist/v1/builder/lowering/callable.js +18 -5
- package/dist/v1/builder/schema/handle.d.ts +1 -1
- package/dist/v1/builder/schema/projection.d.ts +11 -8
- package/dist/v1/compiled/admission/accept.js +15 -1
- package/dist/v1/compiled/admission/revision.js +7 -1
- package/dist/v1/compiled/admission/semantics.js +2 -2
- package/dist/v1/compiled/compiler/compile.js +13 -2
- package/dist/v1/compiled/loader/load.js +8 -2
- package/dist/v1/compiled/model/schema.d.ts +5 -1
- package/dist/v1/index.d.ts +3 -2
- package/dist/v1/index.js +2 -1
- package/dist/v1/language/callable/model/callable.d.ts +18 -4
- package/dist/v1/language/callable/model/callable.js +3 -1
- package/dist/v1/language/callable/resolved.d.ts +7 -2
- package/dist/v1/language/class/facets.d.ts +2 -1
- package/dist/v1/language/class/resolved.d.ts +11 -4
- package/dist/v1/language/index.d.ts +1 -0
- package/dist/v1/language/index.js +1 -0
- package/dist/v1/language/value/evaluate/evaluator.js +4 -0
- package/dist/v1/language/value/model/blob.d.ts +33 -0
- package/dist/v1/language/value/model/blob.js +90 -0
- package/dist/v1/language/value/profile/rules.js +36 -4
- package/dist/v1/schema/compatibility/comparators/callables.d.ts +2 -3
- package/dist/v1/schema/compatibility/comparators/callables.js +8 -1
- package/dist/v1/schema/normalization/domain.js +9 -1
- package/dist/v1/schema/resolution/domain.js +2 -1
- package/dist/v1/schema/resolution/origins.js +2 -1
- package/dist/v1/schema/validation/class.js +5 -0
- package/dist/v1/schema/validation/domain.structure.js +7 -0
- package/dist/v1/schema/validation/policy/uses.js +2 -1
- package/dist/v1/schema/validation/value-api.d.ts +2 -0
- package/dist/v1/schema/validation/value-api.js +1 -0
- package/dist/v1/schema/validation/value.js +7 -1
- package/dist/value/canonical.js +2 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Value as PortableValue } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import type { z } from 'zod';
|
|
3
|
-
import type { FunctionAuth } from '../../language/callable/model/callable.js';
|
|
3
|
+
import type { BinaryInputProjection, FunctionAuth } from '../../language/callable/model/callable.js';
|
|
4
4
|
import type { PolicyCheckExpression, PolicyCheckObject, PolicyObjectRef } from '../../language/policy/model/policy.js';
|
|
5
5
|
import type { Class } from '../class/authoring.js';
|
|
6
6
|
import type { ValueSchemaInput } from '../class/property.js';
|
|
@@ -11,6 +11,7 @@ import type { TypedValueSchema } from '../value/schema.js';
|
|
|
11
11
|
import type { View } from '../view/authoring.js';
|
|
12
12
|
import { type AUTHORING } from '../schema/handle.js';
|
|
13
13
|
declare const CALLABLE_OUTPUT: unique symbol;
|
|
14
|
+
declare const CALLABLE_INPUT: unique symbol;
|
|
14
15
|
declare const CALLABLE_PROJECTION: unique symbol;
|
|
15
16
|
declare const CALLABLE_PROJECTION_VALUE: unique symbol;
|
|
16
17
|
export interface CallablePolicyContext {
|
|
@@ -39,12 +40,19 @@ export interface BinaryOutput {
|
|
|
39
40
|
readonly [CALLABLE_OUTPUT]: true;
|
|
40
41
|
}
|
|
41
42
|
export type CallableOutputInput = ValueSchemaInput | StreamOutput | BinaryOutput;
|
|
42
|
-
export interface
|
|
43
|
+
export interface BinaryInputAuthoring<out Metadata extends ValueSchemaInput = ValueSchemaInput> {
|
|
44
|
+
readonly mode: 'binary';
|
|
45
|
+
readonly metadata: Metadata;
|
|
46
|
+
readonly maximumBytes: number;
|
|
47
|
+
readonly [CALLABLE_INPUT]: true;
|
|
48
|
+
}
|
|
49
|
+
export type FunctionInputSchema = ValueSchemaInput | BinaryInputAuthoring;
|
|
50
|
+
export interface CallableInputBase<Input extends FunctionInputSchema = ValueSchemaInput> {
|
|
43
51
|
readonly description?: string;
|
|
44
|
-
readonly input:
|
|
52
|
+
readonly input: Input;
|
|
45
53
|
readonly output: CallableOutputInput;
|
|
46
54
|
}
|
|
47
|
-
type ConcreteCallableInput = CallableInputBase & ({
|
|
55
|
+
type ConcreteCallableInput<Input extends FunctionInputSchema = ValueSchemaInput> = CallableInputBase<Input> & ({
|
|
48
56
|
readonly auth: 'anonymous';
|
|
49
57
|
readonly policy?: never;
|
|
50
58
|
} | {
|
|
@@ -54,7 +62,7 @@ type ConcreteCallableInput = CallableInputBase & ({
|
|
|
54
62
|
readonly auth: 'authorized';
|
|
55
63
|
readonly policy?: CallablePolicyBuilder;
|
|
56
64
|
});
|
|
57
|
-
export type FunctionInput = ConcreteCallableInput & {
|
|
65
|
+
export type FunctionInput = ConcreteCallableInput<FunctionInputSchema> & {
|
|
58
66
|
readonly static?: never;
|
|
59
67
|
readonly abstract?: never;
|
|
60
68
|
};
|
|
@@ -73,6 +81,7 @@ export interface CallableProjection<out Input = unknown, out Output = unknown, o
|
|
|
73
81
|
readonly abstract: Abstract;
|
|
74
82
|
}
|
|
75
83
|
type ValueInputOf<Schema> = Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.input<Schema> : PortableValue;
|
|
84
|
+
type FunctionInputOf<Schema> = Schema extends BinaryInputAuthoring<infer Metadata> ? BinaryInputProjection<ValueInputOf<Metadata>> : ValueInputOf<Schema>;
|
|
76
85
|
type ValueOutputOf<Schema> = Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.output<Schema> : PortableValue;
|
|
77
86
|
type CallableOutputOf<Input extends CallableOutputInput> = Input extends StreamOutput<infer Item> ? {
|
|
78
87
|
readonly mode: 'stream';
|
|
@@ -96,7 +105,7 @@ export type ProjectionOfCallable<Value extends Function | Method> = Value extend
|
|
|
96
105
|
export declare function callableConfiguration(value: Function | Method): CallableInput;
|
|
97
106
|
export type PolicyObjectAuthoring = Class | Function | Method | Policy | View | CoreNode;
|
|
98
107
|
export type PolicyObjectInput = Lazy<PolicyObjectAuthoring | PolicyObjectRef>;
|
|
99
|
-
export declare function func<const Config extends FunctionInput, Input =
|
|
108
|
+
export declare function func<const Config extends FunctionInput, Input = FunctionInputOf<Config['input']>, Output = CallableOutputOf<Config['output']>, Auth extends FunctionAuth = Config['auth']>(config: Config): Function<CallableProjection<Input, Output, Auth, false, false>>;
|
|
100
109
|
export declare function method<const Config extends MethodInput, Input = ValueInputOf<Config['input']>, Output = CallableOutputOf<Config['output']>, Auth extends FunctionAuth = Config['auth'], Static extends boolean = Config extends {
|
|
101
110
|
readonly static: true;
|
|
102
111
|
} ? true : false, Abstract extends boolean = Config extends {
|
|
@@ -117,5 +126,12 @@ export declare const output: {
|
|
|
117
126
|
readonly stream: <const Item extends ValueSchemaInput>(item: Item) => StreamOutput<Item>;
|
|
118
127
|
readonly binary: () => BinaryOutput;
|
|
119
128
|
};
|
|
129
|
+
/** Explicit binary Function input. Plain schemas remain value inputs. */
|
|
130
|
+
export declare const input: {
|
|
131
|
+
readonly binary: <const Metadata extends ValueSchemaInput>(metadata: Metadata, options: {
|
|
132
|
+
readonly maximumBytes: number;
|
|
133
|
+
}) => BinaryInputAuthoring<Metadata>;
|
|
134
|
+
};
|
|
135
|
+
export declare function isBinaryInputAuthoring(value: FunctionInputSchema): value is BinaryInputAuthoring;
|
|
120
136
|
export declare function isCallableOutputAuthoring(value: CallableOutputInput): value is StreamOutput | BinaryOutput;
|
|
121
137
|
export {};
|
|
@@ -62,6 +62,19 @@ export const output = Object.freeze({
|
|
|
62
62
|
});
|
|
63
63
|
},
|
|
64
64
|
});
|
|
65
|
+
/** Explicit binary Function input. Plain schemas remain value inputs. */
|
|
66
|
+
export const input = Object.freeze({
|
|
67
|
+
binary(metadata, options) {
|
|
68
|
+
return authoringValue('callable-input', {
|
|
69
|
+
mode: 'binary',
|
|
70
|
+
metadata,
|
|
71
|
+
maximumBytes: options.maximumBytes,
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
export function isBinaryInputAuthoring(value) {
|
|
76
|
+
return isAuthoringValue(value, 'callable-input');
|
|
77
|
+
}
|
|
65
78
|
export function isCallableOutputAuthoring(value) {
|
|
66
79
|
return isAuthoringValue(value, 'callable-output');
|
|
67
80
|
}
|
|
@@ -7,6 +7,7 @@ import type { MediaType } from '../../language/class/model/data.js';
|
|
|
7
7
|
import type { EdgeCount } from '../../language/class/model/edge.js';
|
|
8
8
|
import type { ResolvedClass, ResolvedProperty } from '../../language/class/resolved.js';
|
|
9
9
|
import type { StateTopology, StateTopologyOf } from '../../language/state/topology.js';
|
|
10
|
+
import type { BlobReceipt, BlobRef, BlobSchema } from '../../language/value/model/blob.js';
|
|
10
11
|
import type { Method, ProjectionOfCallable } from '../callable/authoring.js';
|
|
11
12
|
import type { Policy } from '../policy/authoring.js';
|
|
12
13
|
import type { Lazy } from '../schema/lazy.js';
|
|
@@ -106,8 +107,8 @@ export interface AuthoredMethodProjection<out Value extends Method = Method, out
|
|
|
106
107
|
}
|
|
107
108
|
type PropertySchemaOf<Field> = Field extends AutoProperty<infer Value> ? PropertySchemaOf<Value> : Field extends Property<infer Schema, PropertyOptions, unknown> ? Schema : Field;
|
|
108
109
|
type PropertyOptionsOf<Field> = Field extends AutoProperty<infer Value> ? PropertyOptionsOf<Value> : Field extends Property<ValueSchemaInput, infer Options, unknown> ? Options : Record<never, never>;
|
|
109
|
-
type ValueInputOf<Schema> = Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.input<Schema> : PortableValue;
|
|
110
|
-
type ValueOutputOf<Schema> = Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.output<Schema> : PortableValue;
|
|
110
|
+
type ValueInputOf<Schema> = Schema extends BlobSchema ? BlobReceipt : Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.input<Schema> : PortableValue;
|
|
111
|
+
type ValueOutputOf<Schema> = Schema extends BlobSchema ? BlobRef : Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.output<Schema> : PortableValue;
|
|
111
112
|
type PropertyRequiredOf<Field> = PropertyOptionsOf<Field> extends {
|
|
112
113
|
readonly required: infer Required extends boolean;
|
|
113
114
|
} ? Required : undefined extends ValueInputOf<PropertySchemaOf<Field>> ? false : true;
|
|
@@ -228,11 +229,12 @@ type UndirectedEdgeClassIdentity<Config> = Config extends {
|
|
|
228
229
|
readonly endpoints: Endpoints;
|
|
229
230
|
readonly constraints: Constraints;
|
|
230
231
|
} : never;
|
|
231
|
-
type OwnerErasedPropertyProjection<Entry> = Entry extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer Name, unknown, infer State> ? AuthoredPropertyProjection<Input, Output, Required, Name, unknown, State> : Entry extends ResolvedProperty<infer Value, infer Required, infer State> & {
|
|
232
|
+
type OwnerErasedPropertyProjection<Entry> = Entry extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer Name, unknown, infer State> ? AuthoredPropertyProjection<Input, Output, Required, Name, unknown, State> : Entry extends ResolvedProperty<infer Value, infer Required, infer State, infer Input> & {
|
|
232
233
|
readonly name: infer Name;
|
|
233
234
|
readonly key: infer Key;
|
|
234
235
|
} ? {
|
|
235
236
|
readonly value: Value;
|
|
237
|
+
readonly input: Input;
|
|
236
238
|
readonly required: Required;
|
|
237
239
|
readonly name: Name;
|
|
238
240
|
readonly key: Key;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { func, method, output } from './callable/authoring.js';
|
|
1
|
+
export { func, input, method, output } from './callable/authoring.js';
|
|
2
2
|
export { core } from './core/authoring.js';
|
|
3
3
|
export { defineClass, edgeClass, nodeClass } from './class/authoring.js';
|
|
4
4
|
export { fullMatch } from './value/full-match.js';
|
|
@@ -12,7 +12,7 @@ export { valueSchema } from './value/schema.js';
|
|
|
12
12
|
export { view } from './view/authoring.js';
|
|
13
13
|
export { BuilderError as Error } from './schema/diagnostic.js';
|
|
14
14
|
export type { BuilderDiagnostic as Diagnostic, BuilderDiagnosticCode as DiagnosticCode, } from './schema/diagnostic.js';
|
|
15
|
-
export type { CallableInputBase, CallableInput, CallableOutputInput, CallableProjection, CallablePolicyBuilder, CallablePolicyContext, BinaryOutput, Function, FunctionInput, Method, MethodInput, PolicyObjectInput, StreamOutput, } from './callable/authoring.js';
|
|
15
|
+
export type { CallableInputBase, CallableInput, BinaryInputAuthoring, CallableOutputInput, CallableProjection, CallablePolicyBuilder, CallablePolicyContext, BinaryOutput, Function, FunctionInput, Method, MethodInput, PolicyObjectInput, StreamOutput, } from './callable/authoring.js';
|
|
16
16
|
export type { CoreEdge, CoreEndpoint, CoreInput, CoreNode } from './core/authoring.js';
|
|
17
17
|
export type { AuthoredPropertyProjection, AuthoredMethodProjection, Class, ClassIdentityProjection, ClassOwnerProjection, ClassReferenceProjection, ClassReferenceInput as ClassReference, DirectedEdgeInput, DirectedEdgeClass, DirectedSourceInput, DirectedTargetInput, EdgeClassCommon, EdgeClassInput, EdgeClass, EdgeClassReferenceInput as EdgeClassReference, IncidentEndpointInput, NodeClass, NodeClassInput, NodeClassReferenceInput as NodeClassReference, UndirectedEdgeInput, UndirectedEdgeClass, } from './class/authoring.js';
|
|
18
18
|
export type { PathAuthoring } from './value/path.js';
|
package/dist/v1/builder/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { func, method, output } from './callable/authoring.js';
|
|
1
|
+
export { func, input, method, output } from './callable/authoring.js';
|
|
2
2
|
export { core } from './core/authoring.js';
|
|
3
3
|
export { defineClass, edgeClass, nodeClass } from './class/authoring.js';
|
|
4
4
|
export { fullMatch } from './value/full-match.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizePolicyChecks } from '../../language/policy/normalization/normalize.js';
|
|
2
|
-
import { callableInputField, callableConfiguration, callablePolicyObject, callableRef, callableSelf, isCallableOutputAuthoring, } from '../callable/authoring.js';
|
|
2
|
+
import { callableInputField, callableConfiguration, callablePolicyObject, callableRef, callableSelf, isBinaryInputAuthoring, isCallableOutputAuthoring, } from '../callable/authoring.js';
|
|
3
3
|
import { fail } from '../schema/diagnostic.js';
|
|
4
4
|
export class V1CallableCompiler {
|
|
5
5
|
context;
|
|
@@ -25,11 +25,19 @@ export class V1CallableCompiler {
|
|
|
25
25
|
}
|
|
26
26
|
const isStatic = method ? (config.static ?? false) : undefined;
|
|
27
27
|
const isAbstract = method ? (config.abstract ?? false) : undefined;
|
|
28
|
-
const
|
|
28
|
+
const binaryInput = isBinaryInputAuthoring(config.input) ? config.input : undefined;
|
|
29
|
+
if (method && binaryInput !== undefined) {
|
|
30
|
+
fail('BUILDER_CALLABLE_PLACEMENT', `${placement.pointer}/input`, 'Methods require Value input.');
|
|
31
|
+
}
|
|
32
|
+
const metadata = isBinaryInputAuthoring(config.input) ? config.input.metadata : config.input;
|
|
33
|
+
const inputSchema = this.values.schema(metadata, 'callable-input', binaryInput ? `${placement.pointer}/input/metadata` : `${placement.pointer}/input`);
|
|
34
|
+
const input = binaryInput
|
|
35
|
+
? { mode: 'binary', metadata: inputSchema, maximumBytes: binaryInput.maximumBytes }
|
|
36
|
+
: inputSchema;
|
|
29
37
|
const output = this.compileOutput(config.output, `${placement.pointer}/output`);
|
|
30
38
|
const policy = config.policy === undefined
|
|
31
39
|
? undefined
|
|
32
|
-
: normalizePolicyChecks(config.policy(this.policyContext(
|
|
40
|
+
: normalizePolicyChecks(config.policy(this.policyContext(inputSchema, placement, isStatic ?? false)));
|
|
33
41
|
const base = {
|
|
34
42
|
...(config.description === undefined ? {} : { description: config.description }),
|
|
35
43
|
input,
|
|
@@ -38,10 +46,15 @@ export class V1CallableCompiler {
|
|
|
38
46
|
const contract = auth === 'authorized'
|
|
39
47
|
? { ...base, auth, ...(policy === undefined ? {} : { policy }) }
|
|
40
48
|
: { ...base, auth };
|
|
41
|
-
if (!method)
|
|
42
|
-
return {
|
|
49
|
+
if (!method) {
|
|
50
|
+
return {
|
|
51
|
+
ref: placement.ref,
|
|
52
|
+
...contract,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
43
55
|
return {
|
|
44
56
|
...contract,
|
|
57
|
+
input: inputSchema,
|
|
45
58
|
static: isStatic,
|
|
46
59
|
abstract: isAbstract,
|
|
47
60
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const AUTHORING: unique symbol;
|
|
2
|
-
export type AuthoringKind = 'definition' | 'function' | 'method' | 'callable-output' | 'policy' | 'view' | 'core-node' | 'core-edge' | 'property' | 'auto';
|
|
2
|
+
export type AuthoringKind = 'definition' | 'function' | 'method' | 'callable-input' | 'callable-output' | 'policy' | 'view' | 'core-node' | 'core-edge' | 'property' | 'auto';
|
|
3
3
|
export interface AuthoringValue<Kind extends AuthoringKind> {
|
|
4
4
|
readonly [AUTHORING]: Kind;
|
|
5
5
|
}
|
|
@@ -2,16 +2,18 @@ import type { Revision } from '../../addressing/index.js';
|
|
|
2
2
|
import type * as domain from '../../domain/model/domain.js';
|
|
3
3
|
import type * as language from '../../language/index.js';
|
|
4
4
|
import type { StateTopology } from '../../language/state/index.js';
|
|
5
|
+
import type { BlobReceipt } from '../../language/value/model/blob.js';
|
|
5
6
|
import type { DomainOfSchema, DomainSchema } from '../../schema/model/schema.js';
|
|
6
7
|
import type { CallableProjection, Function, Method } from '../callable/authoring.js';
|
|
7
8
|
import type { AuthoredPropertyProjection, Class, ClassIdentityProjection, ClassIdentityProjectionOf, ClassOwnerProjection, ClassOwnerProjectionOf, ClassReferenceProjection, ClassReferenceProjectionOf, DirectedEdgeClass, NodeClass, ProjectionOfClass, UndirectedEdgeClass } from '../class/authoring.js';
|
|
8
9
|
import type { DomainSchemaInput } from './input.js';
|
|
9
|
-
export interface PropertyProjection<Value = unknown, Required extends boolean = boolean, Name extends string = string, Key extends language.PropertyKey = language.PropertyKey, State extends StateTopology | undefined = StateTopology | undefined> {
|
|
10
|
+
export interface PropertyProjection<Value = unknown, Required extends boolean = boolean, Name extends string = string, Key extends language.PropertyKey = language.PropertyKey, State extends StateTopology | undefined = StateTopology | undefined, Input = Value> {
|
|
10
11
|
readonly value: Value;
|
|
11
12
|
readonly required: Required;
|
|
12
13
|
readonly name: Name;
|
|
13
14
|
readonly key: Key;
|
|
14
15
|
readonly state?: State;
|
|
16
|
+
readonly input: Input;
|
|
15
17
|
}
|
|
16
18
|
type MethodExecutableOf<OwnerAbstract extends boolean, MethodAbstract extends boolean> = MethodAbstract extends false ? true : OwnerAbstract extends false ? true : false;
|
|
17
19
|
export interface MethodProjection<Input = unknown, Output = unknown, Static extends boolean = boolean, Abstract extends boolean = boolean, Auth extends language.FunctionAuth = language.FunctionAuth, Name extends string = string, Key extends language.MethodKey = language.MethodKey, Executable extends boolean = boolean> {
|
|
@@ -214,6 +216,7 @@ type EffectivePropertyProjectionsOfClass<Value extends Class> = ClassInputOf<Val
|
|
|
214
216
|
} ? Properties : never;
|
|
215
217
|
type AuthoredProjectionName<Entry> = Entry extends AuthoredPropertyProjection<unknown, unknown, boolean, infer Name> ? Name : never;
|
|
216
218
|
type AuthoredProjectionInput<Entry> = Entry extends AuthoredPropertyProjection<infer Input, unknown, boolean, string> ? Input : never;
|
|
219
|
+
type CoreProjectionInput<Entry> = Entry extends AuthoredPropertyProjection<infer Input, infer Output, boolean, string> ? Input extends BlobReceipt ? Output : Input : never;
|
|
217
220
|
type AuthoredProjectionRequired<Entry> = Entry extends AuthoredPropertyProjection<unknown, unknown, infer Required, string> ? Required : false;
|
|
218
221
|
type UniqueAuthoredProjections<Entries> = Entries extends unknown ? IsMultiple<Extract<Entries, {
|
|
219
222
|
readonly name: AuthoredProjectionName<Entries>;
|
|
@@ -223,11 +226,11 @@ type RequiredAuthoredPropertyNames<Entries> = CoreAuthoredProjections<Entries> e
|
|
|
223
226
|
type OptionalAuthoredPropertyNames<Entries> = Exclude<AuthoredProjectionName<CoreAuthoredProjections<Entries>>, RequiredAuthoredPropertyNames<Entries>>;
|
|
224
227
|
type AutomaticAuthoredPropertyNames<Entries> = UniqueAuthoredProjections<Entries> extends infer Entry ? Entry extends unknown ? [AuthoredProjectionInput<Entry>] extends [never] ? AuthoredProjectionName<Entry> : never : never : never;
|
|
225
228
|
type CorePropertyInputFromAuthoredProjections<Entries> = Readonly<{
|
|
226
|
-
[Name in RequiredAuthoredPropertyNames<Entries>]:
|
|
229
|
+
[Name in RequiredAuthoredPropertyNames<Entries>]: CoreProjectionInput<Extract<CoreAuthoredProjections<Entries>, {
|
|
227
230
|
readonly name: Name;
|
|
228
231
|
}>>;
|
|
229
232
|
} & {
|
|
230
|
-
[Name in OptionalAuthoredPropertyNames<Entries>]?:
|
|
233
|
+
[Name in OptionalAuthoredPropertyNames<Entries>]?: CoreProjectionInput<Extract<CoreAuthoredProjections<Entries>, {
|
|
231
234
|
readonly name: Name;
|
|
232
235
|
}>>;
|
|
233
236
|
} & {
|
|
@@ -260,10 +263,10 @@ type CallableAuthOf<Value extends Method | Function> = CallableConfig<Value>['au
|
|
|
260
263
|
type MethodProjectionOfEntry<Origin extends string, OwnerName extends string, Entry> = Entry extends language.ResolvedMethod ? MethodProjectionOfResolved<Entry> : Entry extends AuthoredMethodEntry<infer Owner, infer Name, infer Value> ? MethodProjection<CallableInputValue<Value>, CallableOutputValue<Value>, CallableStaticOf<Value>, CallableAbstractOf<Value>, CallableAuthOf<Value>, Name, language.MethodKey<Origin, OwnerName, Name>, MethodExecutableOf<AbstractOf<ClassInputOf<Owner>>, CallableAbstractOf<Value>>> : never;
|
|
261
264
|
type MethodProjectionOfEntries<Origin extends string, OwnerName extends string, Entries> = Entries extends unknown ? MethodProjectionOfEntry<Origin, OwnerName, Entries> : never;
|
|
262
265
|
type MethodCollectionOperation = 'byKey' | 'get';
|
|
263
|
-
type PropertyProjectionOfResolved<Value> = Value extends language.ResolvedProperty<infer PropertyValue, infer Required, infer State> & {
|
|
266
|
+
type PropertyProjectionOfResolved<Value> = Value extends language.ResolvedProperty<infer PropertyValue, infer Required, infer State, infer Input> & {
|
|
264
267
|
readonly name: infer Name extends string;
|
|
265
268
|
readonly key: infer Key extends language.PropertyKey;
|
|
266
|
-
} ? PropertyProjection<PropertyValue, Required, Name, Key, State> : never;
|
|
269
|
+
} ? PropertyProjection<PropertyValue, Required, Name, Key, State, Input> : never;
|
|
267
270
|
type MethodProjectionOfResolved<Value> = Value extends language.ResolvedMethod<infer Input, infer Output, infer Static, infer Abstract, infer Auth, infer _Policy, infer Key> & {
|
|
268
271
|
readonly name: infer Name extends string;
|
|
269
272
|
} ? MethodProjection<Input, Output, Static, Abstract, Auth, Name, Key, Value['executable']> : never;
|
|
@@ -292,12 +295,12 @@ type ShallowClassProjectionTupleOfResolved<Parents extends readonly unknown[]> =
|
|
|
292
295
|
type ExactClass<Value> = Value extends {
|
|
293
296
|
readonly key: infer Key extends language.DefinitionKey<string, 'class'>;
|
|
294
297
|
} ? Key extends `${infer Origin}:class.${infer Name}` ? string extends Origin ? never : string extends Name ? never : Value : never : never;
|
|
295
|
-
type OwnPropertyProjectionsOf<Origin extends string, Name extends string, Value> = OwnPropertyEntries<Value> extends infer Entry ? Entry extends AuthoredPropertyEntry<unknown, infer PropertyName, infer Field> ? Field extends AuthoredPropertyProjection<
|
|
298
|
+
type OwnPropertyProjectionsOf<Origin extends string, Name extends string, Value> = OwnPropertyEntries<Value> extends infer Entry ? Entry extends AuthoredPropertyEntry<unknown, infer PropertyName, infer Field> ? Field extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, string, unknown, infer State> ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, Name, PropertyName>, State, Input> : never : never : never;
|
|
296
299
|
type EffectivePropertyEntriesOfClass<Value> = ClassInputOf<Value> extends {
|
|
297
300
|
readonly effectiveProperties: infer Properties;
|
|
298
301
|
} ? Properties : never;
|
|
299
302
|
type OwnerNameOf<Root extends DomainSchemaInput, CurrentName extends string, Owner> = Owner extends 'self' ? CurrentName : Owner extends ClassOwnerProjection ? Extract<LocalNameOfOwner<Root, Owner>, string> : Owner extends ClassIdentityProjection ? Extract<LocalNameOfIdentity<Root, Owner>, string> : never;
|
|
300
|
-
type EffectivePropertyProjectionOfEntry<Origin extends string, CurrentName extends string, Root extends DomainSchemaInput, Entry> = Entry extends language.ResolvedProperty ? PropertyProjectionOfResolved<Entry> : Entry extends AuthoredPropertyProjection<
|
|
303
|
+
type EffectivePropertyProjectionOfEntry<Origin extends string, CurrentName extends string, Root extends DomainSchemaInput, Entry> = Entry extends language.ResolvedProperty ? PropertyProjectionOfResolved<Entry> : Entry extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer PropertyName, infer Owner, infer State> ? OwnerNameOf<Root, CurrentName, Owner> extends infer OwnerName extends string ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, OwnerName, PropertyName>, State, Input> : never : never;
|
|
301
304
|
type EffectivePropertyProjectionsOf<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput> = EffectivePropertyEntriesOfClass<Value> extends infer Entry ? Entry extends unknown ? EffectivePropertyProjectionOfEntry<Origin, Name, Root, Entry> : never : never;
|
|
302
305
|
type OwnInstanceMethodProjectionsOf<Origin extends string, Name extends string, Value> = MethodProjectionOfEntries<Origin, Name, OwnMethodEntries<Value, false>>;
|
|
303
306
|
type OwnStaticMethodProjectionsOf<Origin extends string, Name extends string, Value> = MethodProjectionOfEntries<Origin, Name, OwnMethodEntries<Value, true>>;
|
|
@@ -314,7 +317,7 @@ type ClassProjectionOfAuthoring<Origin extends string, Name extends string, Valu
|
|
|
314
317
|
type FunctionProjectionOfAuthoring<Origin extends string, Name extends string, Value> = Value extends Function ? FunctionProjection<CallableInputValue<Value>, CallableOutputValue<Value>, CallableAuthOf<Value>, language.FunctionRef<Name> & {
|
|
315
318
|
readonly origin: Origin;
|
|
316
319
|
}, language.DefinitionKey<Origin, 'function', Name>> : never;
|
|
317
|
-
type ResolvedPropertyOfProjection<Value> = Value extends PropertyProjection<infer PropertyValue, infer Required, infer Name, infer Key, infer State> ? language.ResolvedProperty<PropertyValue, Required, State> & {
|
|
320
|
+
type ResolvedPropertyOfProjection<Value> = Value extends PropertyProjection<infer PropertyValue, infer Required, infer Name, infer Key, infer State, infer Input> ? language.ResolvedProperty<PropertyValue, Required, State, Input> & {
|
|
318
321
|
readonly name: Name;
|
|
319
322
|
readonly key: Key;
|
|
320
323
|
} : never;
|
|
@@ -271,7 +271,21 @@ function compiledCallable(input, values, method, path) {
|
|
|
271
271
|
}
|
|
272
272
|
policyCheck(value.policy, 0, `${path}/policy`);
|
|
273
273
|
}
|
|
274
|
-
|
|
274
|
+
let inputIndex;
|
|
275
|
+
if (!method && typeof value.input === 'object' && value.input !== null) {
|
|
276
|
+
const inputPath = `${path}/input`;
|
|
277
|
+
const binary = object(value.input, 'Binary input', inputPath);
|
|
278
|
+
exact(binary, ['mode', 'metadata', 'maximumBytes'], 'Binary input', inputPath);
|
|
279
|
+
if (binary.mode !== 'binary')
|
|
280
|
+
invalid('Binary input mode', undefined, `${inputPath}/mode`);
|
|
281
|
+
inputIndex = index(binary.metadata, values.length, 'Binary input metadata', `${inputPath}/metadata`);
|
|
282
|
+
const maximumBytes = integer(binary.maximumBytes, 'Binary input maximumBytes', `${inputPath}/maximumBytes`);
|
|
283
|
+
if (maximumBytes < 1)
|
|
284
|
+
invalid('Binary input maximumBytes', undefined, `${inputPath}/maximumBytes`);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
inputIndex = index(value.input, values.length, 'Callable input', `${path}/input`);
|
|
288
|
+
}
|
|
275
289
|
if (value.fields !== undefined) {
|
|
276
290
|
const fieldsPath = `${path}/fields`;
|
|
277
291
|
for (const [field, nodes] of Object.entries(object(value.fields, 'Callable fields', fieldsPath))) {
|
|
@@ -54,7 +54,13 @@ function sourceFunction(entry, definition) {
|
|
|
54
54
|
const { input, fields: _, output, ...rest } = definition;
|
|
55
55
|
return {
|
|
56
56
|
...rest,
|
|
57
|
-
input:
|
|
57
|
+
input: typeof input === 'number'
|
|
58
|
+
? schemaOf(entry, input)
|
|
59
|
+
: {
|
|
60
|
+
mode: 'binary',
|
|
61
|
+
metadata: schemaOf(entry, input.metadata),
|
|
62
|
+
maximumBytes: input.maximumBytes,
|
|
63
|
+
},
|
|
58
64
|
output: sourceOutput(entry, output),
|
|
59
65
|
};
|
|
60
66
|
}
|
|
@@ -282,7 +282,7 @@ function validatePolicies(candidate, context) {
|
|
|
282
282
|
validatePolicyParity(context, entry, entryIndex, localPolicies);
|
|
283
283
|
for (const [functionIndex, callable] of entry.definitions.functions.entries()) {
|
|
284
284
|
if (callable.policy !== undefined)
|
|
285
|
-
validateCallablePolicy(context, entry, callable.policy, callable.input, callable.fields, false, `/closure/${entryIndex}/definitions/functions/${functionIndex}/policy`);
|
|
285
|
+
validateCallablePolicy(context, entry, callable.policy, typeof callable.input === 'number' ? callable.input : callable.input.metadata, callable.fields, false, `/closure/${entryIndex}/definitions/functions/${functionIndex}/policy`);
|
|
286
286
|
}
|
|
287
287
|
for (const [classIndex, definition] of entry.definitions.classes.entries()) {
|
|
288
288
|
for (const [kind, ref] of Object.entries(definition.policies)) {
|
|
@@ -523,7 +523,7 @@ function validatePolicyParity(context, entry, entryIndex, policies) {
|
|
|
523
523
|
}
|
|
524
524
|
for (const [functionIndex, callable] of entry.definitions.functions.entries()) {
|
|
525
525
|
if (callable.policy !== undefined) {
|
|
526
|
-
validateCallablePolicyTyping(context, typing, entry, callable.policy, callable.input, undefined, `/closure/${entryIndex}/definitions/functions/${functionIndex}/policy`);
|
|
526
|
+
validateCallablePolicyTyping(context, typing, entry, callable.policy, typeof callable.input === 'number' ? callable.input : callable.input.metadata, undefined, `/closure/${entryIndex}/definitions/functions/${functionIndex}/policy`);
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
529
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
1
2
|
import { inputFieldNodes } from '../../language/value/compile/fields.js';
|
|
2
3
|
import { prepareValueSchema } from '../../language/value/evaluate/preparation.js';
|
|
3
4
|
import { classifyPreparedOrdering } from '../../language/value/ordering.js';
|
|
@@ -96,8 +97,18 @@ function compileEntry(schema, lookup) {
|
|
|
96
97
|
const functions = Object.values(schema.functions)
|
|
97
98
|
.sort((left, right) => compare(left.ref.name, right.ref.name))
|
|
98
99
|
.map((definition) => {
|
|
99
|
-
const
|
|
100
|
-
const
|
|
100
|
+
const binary = isBinaryInput(definition.input);
|
|
101
|
+
const inputIndex = add(binary ? definition.input.metadata : definition.input, binary
|
|
102
|
+
? `/functions/${definition.ref.name}/input/metadata`
|
|
103
|
+
: `/functions/${definition.ref.name}/input`);
|
|
104
|
+
const input = binary
|
|
105
|
+
? {
|
|
106
|
+
mode: 'binary',
|
|
107
|
+
metadata: inputIndex,
|
|
108
|
+
maximumBytes: definition.input.maximumBytes,
|
|
109
|
+
}
|
|
110
|
+
: inputIndex;
|
|
111
|
+
const fields = inputFieldNodes(values[inputIndex]);
|
|
101
112
|
return {
|
|
102
113
|
ref: definition.ref,
|
|
103
114
|
auth: definition.auth,
|
|
@@ -86,7 +86,13 @@ function loadFunction(entry, value) {
|
|
|
86
86
|
const { input, fields: _, output, ...definition } = value;
|
|
87
87
|
return Object.freeze({
|
|
88
88
|
...definition,
|
|
89
|
-
input:
|
|
89
|
+
input: typeof input === 'number'
|
|
90
|
+
? schemaOf(entry, input)
|
|
91
|
+
: {
|
|
92
|
+
mode: 'binary',
|
|
93
|
+
metadata: schemaOf(entry, input.metadata),
|
|
94
|
+
maximumBytes: input.maximumBytes,
|
|
95
|
+
},
|
|
90
96
|
output: loadOutput(entry, output),
|
|
91
97
|
});
|
|
92
98
|
}
|
|
@@ -107,7 +113,7 @@ function schemaOf(entry, index) {
|
|
|
107
113
|
}
|
|
108
114
|
function callableProgram(value) {
|
|
109
115
|
return {
|
|
110
|
-
input: value.input,
|
|
116
|
+
input: typeof value.input === 'number' ? value.input : value.input.metadata,
|
|
111
117
|
...(value.fields === undefined ? {} : { fields: value.fields }),
|
|
112
118
|
...(value.output.mode === 'binary' ? {} : { output: value.output.value }),
|
|
113
119
|
};
|
|
@@ -38,7 +38,11 @@ export type CompiledClass = (Omit<Extract<ClassDefinition, {
|
|
|
38
38
|
readonly properties: readonly CompiledProperty[];
|
|
39
39
|
});
|
|
40
40
|
export interface CompiledFunction extends Omit<import('../../language/callable/model/callable.js').FunctionDefinition, 'input' | 'output'> {
|
|
41
|
-
readonly input: number
|
|
41
|
+
readonly input: number | {
|
|
42
|
+
readonly mode: 'binary';
|
|
43
|
+
readonly metadata: number;
|
|
44
|
+
readonly maximumBytes: number;
|
|
45
|
+
};
|
|
42
46
|
readonly fields?: Readonly<Record<string, readonly number[]>>;
|
|
43
47
|
readonly output: CompiledOutput;
|
|
44
48
|
}
|
package/dist/v1/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/** Stable aggregate facade for the V1 language. */
|
|
2
|
-
export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, method, nodeClass, output, path, policy, property, stateProperty, valueSchema, view, } from './builder/index.js';
|
|
2
|
+
export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, input, method, nodeClass, output, path, policy, property, stateProperty, valueSchema, view, } from './builder/index.js';
|
|
3
3
|
export { stateMachine } from './language/state/index.js';
|
|
4
|
+
export { isBinaryInput } from './language/callable/model/callable.js';
|
|
4
5
|
export type { EventOf, StateMachine, StateOf } from './language/state/index.js';
|
|
5
6
|
export { PropertyValues } from './language/index.js';
|
|
6
7
|
export * as metadata from './language/definition/metadata.js';
|
|
7
|
-
export type { AnyResolvedClass, BoundMethodOf, BoundMethodShortcutsOf, CallableResultOf, CallableInputOf, CallableOutputOf, ClassSatisfactionKeysOf, ClassDefinition, CoreDefinition, CoreEdge, FunctionAuth, FunctionDefinition, MethodDefinition, MethodOwnerKeyOf, PolicyCheckExpression, PolicyDefinition, PropertyInputOf, PropertyAccessOf, PropertyOutputOf, PropertyShortcutsOf, PropertyValuesOf, ResolvedClass, ResolvedCoreDefinition, ResolvedCoreEndpoint, ResolvedData, ResolvedFunction, ExecutableMethod, ResolvedMethod, ResolvedMethodCollection, ResolvedPolicy, ResolvedProperty, ResolvedView, MethodAccessOf, SelfMethodsOf, SelfPropertiesOf, SelfStaticMethodsOf, StaticMethodsOf, ViewDefinition, } from './language/index.js';
|
|
8
|
+
export type { AnyResolvedClass, BoundMethodOf, BoundMethodShortcutsOf, CallableResultOf, CallableInputOf, CallableInputModeOf, CallableOutputOf, ClassSatisfactionKeysOf, ClassDefinition, CoreDefinition, CoreEdge, FunctionAuth, FunctionDefinition, BinaryInput, BinaryInputProjection, CallableInputContract, MethodDefinition, MethodOwnerKeyOf, PolicyCheckExpression, PolicyDefinition, PropertyInputOf, PropertyAccessOf, PropertyOutputOf, PropertyShortcutsOf, PropertyValuesOf, ResolvedClass, ResolvedCoreDefinition, ResolvedCoreEndpoint, ResolvedData, ResolvedFunction, ExecutableMethod, ResolvedMethod, ResolvedMethodCollection, ResolvedPolicy, ResolvedProperty, ResolvedView, MethodAccessOf, SelfMethodsOf, SelfPropertiesOf, SelfStaticMethodsOf, StaticMethodsOf, ViewDefinition, } from './language/index.js';
|
|
8
9
|
export { acceptDefinitionRef, callableAddress, ClassKey, equalDefinitionRefs, isDefinitionRef, Key, MethodKey, PropertyKey, } from './addressing/index.js';
|
|
9
10
|
export type { ClassRef, CoreRef, DefinitionBase, DefinitionKey, DefinitionRef, FunctionRef, MethodAddress, PolicyRef, Revision, ViewRef, } from './addressing/index.js';
|
|
10
11
|
export type { Definition } from './language/index.js';
|
package/dist/v1/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Stable aggregate facade for the V1 language. */
|
|
2
|
-
export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, method, nodeClass, output, path, policy, property, stateProperty, valueSchema, view, } from './builder/index.js';
|
|
2
|
+
export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, input, method, nodeClass, output, path, policy, property, stateProperty, valueSchema, view, } from './builder/index.js';
|
|
3
3
|
export { stateMachine } from './language/state/index.js';
|
|
4
|
+
export { isBinaryInput } from './language/callable/model/callable.js';
|
|
4
5
|
export { PropertyValues } from './language/index.js';
|
|
5
6
|
export * as metadata from './language/definition/metadata.js';
|
|
6
7
|
export { acceptDefinitionRef, callableAddress, ClassKey, equalDefinitionRefs, isDefinitionRef, Key, MethodKey, PropertyKey, } from './addressing/index.js';
|
|
@@ -12,12 +12,25 @@ export type CallableOutput = {
|
|
|
12
12
|
readonly mode: 'binary';
|
|
13
13
|
};
|
|
14
14
|
export type OutputMode = CallableOutput['mode'];
|
|
15
|
-
|
|
15
|
+
/** A binary Function receives portable metadata and one required byte stream. */
|
|
16
|
+
export interface BinaryInput {
|
|
17
|
+
readonly mode: 'binary';
|
|
18
|
+
readonly metadata: JsonSchema;
|
|
19
|
+
readonly maximumBytes: number;
|
|
20
|
+
}
|
|
21
|
+
export type CallableInputContract = JsonSchema | BinaryInput;
|
|
22
|
+
declare const BINARY_INPUT_PROJECTION: unique symbol;
|
|
23
|
+
/** Type-only witness retained by authored Functions; never serialized as an input Value. */
|
|
24
|
+
export interface BinaryInputProjection<out Metadata = unknown> {
|
|
25
|
+
readonly [BINARY_INPUT_PROJECTION]: Metadata;
|
|
26
|
+
}
|
|
27
|
+
export declare function isBinaryInput(input: CallableInputContract): input is BinaryInput;
|
|
28
|
+
export interface CallableDefinitionBase<Input extends CallableInputContract = CallableInputContract> {
|
|
16
29
|
readonly description?: string;
|
|
17
|
-
readonly input:
|
|
30
|
+
readonly input: Input;
|
|
18
31
|
readonly output: CallableOutput;
|
|
19
32
|
}
|
|
20
|
-
export type CallableDefinition = CallableDefinitionBase & ({
|
|
33
|
+
export type CallableDefinition<Input extends CallableInputContract = CallableInputContract> = CallableDefinitionBase<Input> & ({
|
|
21
34
|
readonly auth: 'anonymous' | 'authenticated';
|
|
22
35
|
readonly policy?: never;
|
|
23
36
|
} | {
|
|
@@ -25,8 +38,9 @@ export type CallableDefinition = CallableDefinitionBase & ({
|
|
|
25
38
|
readonly policy?: PolicyCheckExpression;
|
|
26
39
|
});
|
|
27
40
|
export type FunctionDefinition = DefinitionBase<FunctionRef> & CallableDefinition;
|
|
28
|
-
export type MethodDefinition = CallableDefinition & {
|
|
41
|
+
export type MethodDefinition = CallableDefinition<JsonSchema> & {
|
|
29
42
|
readonly static: boolean;
|
|
30
43
|
readonly abstract: boolean;
|
|
31
44
|
};
|
|
32
45
|
export type MethodRecord = Readonly<Record<string, MethodDefinition>>;
|
|
46
|
+
export {};
|
|
@@ -2,7 +2,7 @@ import type { DefinitionKey, FunctionRef, Key, MethodKey } from '../../addressin
|
|
|
2
2
|
import type { ResolvedClass } from '../class/resolved.js';
|
|
3
3
|
import type { PolicyCheckExpression } from '../policy/model/policy.js';
|
|
4
4
|
import type { Diagnostic } from '../validation/diagnostic.js';
|
|
5
|
-
import type { FunctionDefinition, MethodDefinition } from './model/callable.js';
|
|
5
|
+
import type { BinaryInputProjection, FunctionDefinition, MethodDefinition } from './model/callable.js';
|
|
6
6
|
import type { FunctionAuth } from './model/callable.js';
|
|
7
7
|
type CallableDefinitionOf<Definition extends FunctionDefinition | MethodDefinition, Auth extends FunctionAuth, Policy extends PolicyCheckExpression> = Omit<Definition, 'auth' | 'policy'> & (Auth extends FunctionAuth ? {
|
|
8
8
|
readonly auth: Auth;
|
|
@@ -65,7 +65,12 @@ export type MethodOwnerKeyOf<Method> = Method extends {
|
|
|
65
65
|
readonly key: infer ExactKey extends MethodKey;
|
|
66
66
|
} ? MethodOwnerKeyOfKey<ExactKey> : never;
|
|
67
67
|
type MethodOwnerKeyOfKey<ExactKey extends MethodKey> = ExactKey extends `${infer Origin}:class.${infer Owner}.method.${string}` ? DefinitionKey<Extract<Origin, Key.Origin>, 'class', Owner> : never;
|
|
68
|
-
|
|
68
|
+
type ProjectedCallableInputOf<Callable> = Callable extends ResolvedMethod<infer Input, unknown, boolean> ? Input : Callable extends ResolvedFunction<infer Input, unknown> ? Input : never;
|
|
69
|
+
type InputValue<Input> = Input extends BinaryInputProjection<infer Metadata> ? Metadata : Input;
|
|
70
|
+
/** Portable metadata for a binary Function, or the Value for an ordinary callable. */
|
|
71
|
+
export type CallableInputOf<Callable> = InputValue<ProjectedCallableInputOf<Callable>>;
|
|
72
|
+
type InputMode<Input> = Input extends BinaryInputProjection ? 'binary' : 'value';
|
|
73
|
+
export type CallableInputModeOf<Callable> = InputMode<ProjectedCallableInputOf<Callable>>;
|
|
69
74
|
export type CallableOutputOf<Callable> = Callable extends ResolvedMethod<unknown, infer Output, boolean> ? Output : Callable extends ResolvedFunction<unknown, infer Output> ? Output : never;
|
|
70
75
|
/** An exact local Method whose Schema requires an implementation. */
|
|
71
76
|
export type ExecutableMethod<Input = unknown, Output = unknown, Static extends boolean = boolean> = ResolvedMethod<Input, Output, Static> & {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CallableInputOf, CallableOutputOf, ResolvedMethod, ResolvedMethodCollection } from '../callable/resolved.js';
|
|
2
|
+
import type { StateTopology } from '../state/index.js';
|
|
2
3
|
import type { ResolvedProperty, ResolvedPropertyCollection } from './resolved.js';
|
|
3
4
|
type MemberName = string | number | symbol;
|
|
4
5
|
type ValueAt<Collection, Key> = Key extends keyof Collection ? Collection[Key] : never;
|
|
@@ -17,7 +18,7 @@ type MethodByKeyOf<Class> = MethodCollectionOf<Class> extends {
|
|
|
17
18
|
readonly byKey: infer ByKey extends Readonly<Record<string, ResolvedMethod>>;
|
|
18
19
|
} ? ByKey : Readonly<Record<never, never>>;
|
|
19
20
|
type MethodByNameOf<Class> = Pick<MethodCollectionOf<Class>, Exclude<keyof MethodCollectionOf<Class>, keyof ResolvedMethodCollection>>;
|
|
20
|
-
export type PropertyOutputOf<Property> = Property extends ResolvedProperty<infer Value, infer Required> ? Required extends true ? Value : Value | undefined : never;
|
|
21
|
+
export type PropertyOutputOf<Property> = Property extends ResolvedProperty<infer Value, infer Required, StateTopology | undefined, unknown> ? Required extends true ? Value : Value | undefined : never;
|
|
21
22
|
/** Collision-safe direct Property values. Client supplies graph/wrapper reserved names. */
|
|
22
23
|
export type PropertyShortcutsOf<Class, Reserved extends MemberName = never> = Readonly<{
|
|
23
24
|
[Name in Exclude<keyof PropertyByNameOf<Class>, keyof MethodByNameOf<Class> | Reserved>]: PropertyOutputOf<ValueAt<PropertyByNameOf<Class>, Name>>;
|
|
@@ -8,7 +8,7 @@ import type { ClassDefinition, ClassKind } from './model/class.js';
|
|
|
8
8
|
import type { DataDefinition } from './model/data.js';
|
|
9
9
|
import type { PropertyDefinition } from './model/property.js';
|
|
10
10
|
import type { PropertyValues } from './property-values.js';
|
|
11
|
-
export interface ResolvedProperty<out Value = PortableValue, out Required extends boolean = boolean, out State extends StateTopology | undefined = StateTopology | undefined> {
|
|
11
|
+
export interface ResolvedProperty<out Value = PortableValue, out Required extends boolean = boolean, out State extends StateTopology | undefined = StateTopology | undefined, out Input = Value> {
|
|
12
12
|
readonly owner: AnyResolvedClass;
|
|
13
13
|
readonly name: string;
|
|
14
14
|
readonly key: PropertyKey;
|
|
@@ -20,6 +20,7 @@ export interface ResolvedProperty<out Value = PortableValue, out Required extend
|
|
|
20
20
|
readonly ordering?: OrderingKind;
|
|
21
21
|
validate(input: unknown): readonly Diagnostic[];
|
|
22
22
|
readonly __value?: Value;
|
|
23
|
+
readonly __input?: Input;
|
|
23
24
|
}
|
|
24
25
|
export interface ResolvedData {
|
|
25
26
|
readonly owner: ResolvedClass<'node'>;
|
|
@@ -68,14 +69,14 @@ export type ClassSatisfactionKeysOf<Class> = ClassSatisfactionKeys<Class, never>
|
|
|
68
69
|
type ClassSatisfactionKeys<Class, Seen> = Class extends Seen ? never : (Class extends {
|
|
69
70
|
readonly key: infer ExactKey extends DefinitionKey<Key.Origin, 'class'>;
|
|
70
71
|
} ? ExactKey : never) | (Class extends ResolvedClass<ClassKind, ResolvedPropertyCollection, ResolvedMethodCollection, ResolvedMethodCollection, ResolvedPropertyCollection, ResolvedMethodCollection, ResolvedMethodCollection, ClassDefinition, infer Parents> ? ClassSatisfactionKeys<Extract<Parents[number], ResolvedClass>, Seen | Class> : never);
|
|
71
|
-
export type PropertyValueOf<Property> = Property extends ResolvedProperty<infer Value> ? Value : never;
|
|
72
|
+
export type PropertyValueOf<Property> = Property extends ResolvedProperty<infer Value, boolean, StateTopology | undefined, unknown> ? Value : never;
|
|
72
73
|
export type PropertiesOf<Class> = Class extends {
|
|
73
74
|
readonly properties: infer Properties extends ResolvedPropertyCollection;
|
|
74
75
|
} ? Properties : ResolvedPropertyCollection<Record<never, never>>;
|
|
75
76
|
export type PropertyValuesOf<Class> = PropertyValues & Readonly<{
|
|
76
77
|
[Key in keyof PropertyByKeyOf<Class>]?: PropertyValueOf<PropertyByKeyOf<Class>[Key]>;
|
|
77
78
|
}>;
|
|
78
|
-
export type PropertyInputOf<Class> =
|
|
79
|
+
export type PropertyInputOf<Class> = PropertyWriteInput<PropertyByKeyOf<Class>, PropertyByNameOf<Class>>;
|
|
79
80
|
export type MethodsOf<Class> = Class extends {
|
|
80
81
|
readonly kind: 'node';
|
|
81
82
|
readonly methods: infer Methods extends ResolvedMethodCollection;
|
|
@@ -110,10 +111,16 @@ type PropertyInput<ByKey extends Readonly<Record<PropertyKey, ResolvedProperty<u
|
|
|
110
111
|
} & {
|
|
111
112
|
[Name in keyof ByName]?: PropertyValueOf<ByName[Name]>;
|
|
112
113
|
}>;
|
|
114
|
+
type PropertyWriteInput<ByKey extends Readonly<Record<PropertyKey, ResolvedProperty<unknown>>>, ByName extends Readonly<Record<string, ResolvedProperty<unknown>>>> = Readonly<{
|
|
115
|
+
[Key in keyof ByKey]?: PropertyWriteValueOf<ByKey[Key]>;
|
|
116
|
+
} & {
|
|
117
|
+
[Name in keyof ByName]?: PropertyWriteValueOf<ByName[Name]>;
|
|
118
|
+
}>;
|
|
119
|
+
type PropertyWriteValueOf<Property> = Property extends ResolvedProperty<unknown, boolean, StateTopology | undefined, infer Input> ? Input : never;
|
|
113
120
|
type PropertyByKeyOf<Class> = PropertiesOf<Class> extends {
|
|
114
121
|
readonly byKey: infer ByKey extends Readonly<Record<PropertyKey, ResolvedProperty<unknown>>>;
|
|
115
122
|
} ? ByKey : Readonly<Record<never, never>>;
|
|
116
123
|
type PropertyByNameOf<Class> = Readonly<{
|
|
117
|
-
[Name in Exclude<keyof PropertiesOf<Class>, keyof ResolvedPropertyCollection>]: Extract<PropertiesOf<Class>[Name], ResolvedProperty
|
|
124
|
+
[Name in Exclude<keyof PropertiesOf<Class>, keyof ResolvedPropertyCollection>]: Extract<PropertiesOf<Class>[Name], ResolvedProperty<unknown, boolean, StateTopology | undefined, unknown>>;
|
|
118
125
|
}>;
|
|
119
126
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { isMethodExecutable } from './callable/executable.js';
|
|
2
|
+
export { isBinaryInput } from './callable/model/callable.js';
|
|
2
3
|
export type { ClassRef, CoreRef, DefinitionBase, DefinitionKey, DefinitionRef, FunctionRef, MethodKey, PolicyRef, PropertyKey, ViewRef, } from '../addressing/index.js';
|
|
3
4
|
export type { Value as PropertyValue } from '@astrale-os/kernel-dsl/value';
|
|
4
5
|
export type { JsonSchema as ValueSchema, JsonSchemaObject as ValueSchemaObject, } from './value/model/schema.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { isMethodExecutable } from './callable/executable.js';
|
|
2
|
+
export { isBinaryInput } from './callable/model/callable.js';
|
|
2
3
|
export { stateMachine } from './state/index.js';
|
|
3
4
|
export { PropertyValues } from './class/property-values.js';
|
|
4
5
|
export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, projectedMemberClass, } from './policy/model/policy.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCanonicalBlobRef } from '../model/blob.js';
|
|
1
2
|
import { isInstantValue } from '../model/instant.js';
|
|
2
3
|
import { isValueObject as isJsonObject } from '../model/object.js';
|
|
3
4
|
import { appendPointer } from '../syntax/pointer.js';
|
|
@@ -131,6 +132,9 @@ class InstanceEvaluator {
|
|
|
131
132
|
if (schema['x-astrale-value-kind'] === 'instant' && !isInstantValue(input)) {
|
|
132
133
|
failures.push(invalid(instancePointer, 'x-astrale-value-kind', 'Value is not an exact UTC millisecond Instant.'));
|
|
133
134
|
}
|
|
135
|
+
if (schema['x-astrale-value-kind'] === 'blob' && !isCanonicalBlobRef(input)) {
|
|
136
|
+
failures.push(invalid(instancePointer, 'x-astrale-value-kind', 'Value is not a canonical blob Ref.'));
|
|
137
|
+
}
|
|
134
138
|
if (typeof schema.type === 'string') {
|
|
135
139
|
if (!matchesType(schema.type, input)) {
|
|
136
140
|
failures.push(invalid(instancePointer, 'type', `Value is not of type ${schema.type}.`));
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { JsonSchemaObject } from './schema.js';
|
|
2
|
+
declare const BLOB_SCHEMA: unique symbol;
|
|
3
|
+
/** The portable value read from a blob-kind Node property. */
|
|
4
|
+
export interface BlobRef {
|
|
5
|
+
readonly digest: `sha256:${string}`;
|
|
6
|
+
readonly mediaType: string;
|
|
7
|
+
readonly size: number;
|
|
8
|
+
}
|
|
9
|
+
/** An uploader-bound receipt is the only ordinary write input for a blob property. */
|
|
10
|
+
export type BlobReceipt = string & {
|
|
11
|
+
readonly __brand: 'BlobReceipt';
|
|
12
|
+
};
|
|
13
|
+
/** Type-only marker; the serialized schema remains ordinary JSON. */
|
|
14
|
+
export interface BlobSchema extends JsonSchemaObject {
|
|
15
|
+
readonly [BLOB_SCHEMA]: true;
|
|
16
|
+
}
|
|
17
|
+
export interface BlobOptions {
|
|
18
|
+
/** Required property-level bound, in bytes. */
|
|
19
|
+
readonly maxBytes: number;
|
|
20
|
+
/** Omission admits any canonical artifact media type. */
|
|
21
|
+
readonly mediaTypes?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export declare const BLOB_VALUE_KIND: 'blob';
|
|
24
|
+
export declare const BLOB_DIGEST_PATTERN = "sha256:[0-9a-f]{64}";
|
|
25
|
+
export declare const BLOB_MEDIA_TYPE_PATTERN = "[a-z0-9!#$%&'*+.^_`|~-]+/[a-z0-9!#$%&'*+.^_`|~-]+(;[a-z0-9!#$%&'*+.^_`|~-]+=[!#$%&'*+.^_`|~0-9A-Za-z-]+)*";
|
|
26
|
+
/** Build the one canonical V1 schema shape for a blob-valued Node property. */
|
|
27
|
+
export declare function blob(options: BlobOptions): BlobSchema;
|
|
28
|
+
/** Marker recognition on an already admitted V1 value schema. */
|
|
29
|
+
export declare function isBlobValueSchema(input: unknown): input is BlobSchema;
|
|
30
|
+
/** Exact canonical artifact media type, including ordered token parameters. */
|
|
31
|
+
export declare function canonicalMediaType(input: string): string;
|
|
32
|
+
export declare function isCanonicalBlobRef(input: unknown): input is BlobRef;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const BLOB_VALUE_KIND = 'blob';
|
|
2
|
+
export const BLOB_DIGEST_PATTERN = 'sha256:[0-9a-f]{64}';
|
|
3
|
+
export const BLOB_MEDIA_TYPE_PATTERN = "[a-z0-9!#$%&'*+.^_`|~-]+/[a-z0-9!#$%&'*+.^_`|~-]+(;[a-z0-9!#$%&'*+.^_`|~-]+=[!#$%&'*+.^_`|~0-9A-Za-z-]+)*";
|
|
4
|
+
const TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u;
|
|
5
|
+
const DIGEST = /^sha256:[0-9a-f]{64}$/u;
|
|
6
|
+
/** Build the one canonical V1 schema shape for a blob-valued Node property. */
|
|
7
|
+
export function blob(options) {
|
|
8
|
+
if (!Number.isSafeInteger(options?.maxBytes) || options.maxBytes < 1) {
|
|
9
|
+
throw new TypeError('Blob maxBytes must be a positive safe integer.');
|
|
10
|
+
}
|
|
11
|
+
let mediaTypes;
|
|
12
|
+
if (options.mediaTypes !== undefined) {
|
|
13
|
+
if (!Array.isArray(options.mediaTypes) || options.mediaTypes.length === 0) {
|
|
14
|
+
throw new TypeError('Blob mediaTypes must be a non-empty list.');
|
|
15
|
+
}
|
|
16
|
+
mediaTypes = [...new Set(options.mediaTypes.map(canonicalMediaType))].sort();
|
|
17
|
+
}
|
|
18
|
+
return Object.freeze({
|
|
19
|
+
type: 'object',
|
|
20
|
+
'x-astrale-value-kind': BLOB_VALUE_KIND,
|
|
21
|
+
properties: {
|
|
22
|
+
digest: { type: 'string', fullMatch: BLOB_DIGEST_PATTERN },
|
|
23
|
+
mediaType: mediaTypes === undefined
|
|
24
|
+
? { type: 'string', fullMatch: BLOB_MEDIA_TYPE_PATTERN }
|
|
25
|
+
: { enum: mediaTypes },
|
|
26
|
+
size: { type: 'integer', minimum: 0, maximum: options.maxBytes },
|
|
27
|
+
},
|
|
28
|
+
required: ['digest', 'mediaType', 'size'],
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Marker recognition on an already admitted V1 value schema. */
|
|
33
|
+
export function isBlobValueSchema(input) {
|
|
34
|
+
return (input !== null &&
|
|
35
|
+
typeof input === 'object' &&
|
|
36
|
+
!Array.isArray(input) &&
|
|
37
|
+
input['x-astrale-value-kind'] === BLOB_VALUE_KIND);
|
|
38
|
+
}
|
|
39
|
+
/** Exact canonical artifact media type, including ordered token parameters. */
|
|
40
|
+
export function canonicalMediaType(input) {
|
|
41
|
+
if (typeof input !== 'string')
|
|
42
|
+
throw new TypeError('Blob media type is invalid.');
|
|
43
|
+
const [essence, ...parametersInput] = input.split(';');
|
|
44
|
+
const [rawType, rawSubtype, ...extra] = essence.trim().split('/');
|
|
45
|
+
if (rawType === undefined ||
|
|
46
|
+
rawSubtype === undefined ||
|
|
47
|
+
extra.length !== 0 ||
|
|
48
|
+
!TOKEN.test(rawType) ||
|
|
49
|
+
!TOKEN.test(rawSubtype)) {
|
|
50
|
+
throw new TypeError('Blob media type is invalid.');
|
|
51
|
+
}
|
|
52
|
+
const parameters = parametersInput.map((part) => {
|
|
53
|
+
const separator = part.indexOf('=');
|
|
54
|
+
if (separator <= 0)
|
|
55
|
+
throw new TypeError('Blob media type parameter is invalid.');
|
|
56
|
+
const name = part.slice(0, separator).trim().toLowerCase();
|
|
57
|
+
const value = part.slice(separator + 1).trim();
|
|
58
|
+
if (!TOKEN.test(name) || !TOKEN.test(value)) {
|
|
59
|
+
throw new TypeError('Blob media type parameter is invalid.');
|
|
60
|
+
}
|
|
61
|
+
return [name, value];
|
|
62
|
+
});
|
|
63
|
+
parameters.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
64
|
+
if (new Set(parameters.map(([name]) => name)).size !== parameters.length) {
|
|
65
|
+
throw new TypeError('Blob media type parameters are duplicated.');
|
|
66
|
+
}
|
|
67
|
+
return parameters.reduce((result, [name, value]) => `${result};${name}=${value}`, `${rawType.toLowerCase()}/${rawSubtype.toLowerCase()}`);
|
|
68
|
+
}
|
|
69
|
+
export function isCanonicalBlobRef(input) {
|
|
70
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input))
|
|
71
|
+
return false;
|
|
72
|
+
const value = input;
|
|
73
|
+
if (Object.keys(value).length !== 3 ||
|
|
74
|
+
!Object.hasOwn(value, 'digest') ||
|
|
75
|
+
!Object.hasOwn(value, 'mediaType') ||
|
|
76
|
+
!Object.hasOwn(value, 'size') ||
|
|
77
|
+
typeof value.digest !== 'string' ||
|
|
78
|
+
!DIGEST.test(value.digest) ||
|
|
79
|
+
typeof value.mediaType !== 'string' ||
|
|
80
|
+
!Number.isSafeInteger(value.size) ||
|
|
81
|
+
value.size < 0) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
return canonicalMediaType(value.mediaType) === value.mediaType;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { json } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { diagnostic } from '../../validation/diagnostic.js';
|
|
3
|
+
import { blob, BLOB_VALUE_KIND } from '../model/blob.js';
|
|
3
4
|
import { isValueObject as isJsonObject } from '../model/object.js';
|
|
4
5
|
import { VALUE_SCHEMA_DIALECT } from '../model/schema.js';
|
|
5
6
|
import { isIRegexp } from '../regexp/syntax.js';
|
|
@@ -28,19 +29,50 @@ export function validateSchemaProfile(schema, context, pointer) {
|
|
|
28
29
|
diagnostics.push(diagnostic('VS_RESOURCE_ID', `${currentPointer}/$id`, '$id is forbidden in an embedded V1 value schema.'));
|
|
29
30
|
}
|
|
30
31
|
validateSemanticSets(location.schema, currentPointer, diagnostics);
|
|
31
|
-
validateValueKind(location.schema, currentPointer, diagnostics);
|
|
32
|
+
validateValueKind(location.schema, context, location.depth, currentPointer, diagnostics);
|
|
32
33
|
validateRegexes(location.schema, currentPointer, diagnostics);
|
|
33
34
|
});
|
|
34
|
-
void context;
|
|
35
35
|
return diagnostics;
|
|
36
36
|
}
|
|
37
|
-
function validateValueKind(schema, pointer, diagnostics) {
|
|
37
|
+
function validateValueKind(schema, context, depth, pointer, diagnostics) {
|
|
38
38
|
if (!Object.hasOwn(schema, 'x-astrale-value-kind'))
|
|
39
39
|
return;
|
|
40
|
-
if (schema['x-astrale-value-kind']
|
|
40
|
+
if (schema['x-astrale-value-kind'] === BLOB_VALUE_KIND) {
|
|
41
|
+
if (context !== 'property-facet' || depth !== 0 || !isCanonicalBlobSchema(schema)) {
|
|
42
|
+
diagnostics.push(diagnostic('VS_VALUE_KIND', `${pointer}/x-astrale-value-kind`, 'blob must be the exact schema.values.blob output at the root of a Node property.'));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (schema['x-astrale-value-kind'] !== 'instant' || schema.type !== 'string') {
|
|
41
46
|
diagnostics.push(diagnostic('VS_VALUE_KIND', `${pointer}/x-astrale-value-kind`, 'x-astrale-value-kind is exactly instant and requires type string at the same schema location.'));
|
|
42
47
|
}
|
|
43
48
|
}
|
|
49
|
+
function isCanonicalBlobSchema(input) {
|
|
50
|
+
const properties = input.properties;
|
|
51
|
+
if (!isJsonObject(properties))
|
|
52
|
+
return false;
|
|
53
|
+
const size = properties.size;
|
|
54
|
+
const mediaType = properties.mediaType;
|
|
55
|
+
if (!isJsonObject(size) || !isJsonObject(mediaType))
|
|
56
|
+
return false;
|
|
57
|
+
const maxBytes = size.maximum;
|
|
58
|
+
if (typeof maxBytes !== 'number' || !Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const mediaTypes = mediaType.enum;
|
|
62
|
+
if (mediaTypes !== undefined && (!Array.isArray(mediaTypes) || !mediaTypes.every(isString))) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return (json.serialize(input) ===
|
|
67
|
+
json.serialize(blob({ maxBytes, ...(mediaTypes === undefined ? {} : { mediaTypes }) })));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function isString(input) {
|
|
74
|
+
return typeof input === 'string';
|
|
75
|
+
}
|
|
44
76
|
function validateSemanticSets(schema, pointer, diagnostics) {
|
|
45
77
|
if (Array.isArray(schema.type)) {
|
|
46
78
|
rejectPrimitiveDuplicates(schema.type, `${pointer}/type`, 'type', diagnostics);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Value } from '@astrale-os/kernel-dsl/value';
|
|
2
|
-
import type { CallableOutput, FunctionDefinition, MethodDefinition } from '../../../language/callable/model/callable.js';
|
|
2
|
+
import type { CallableOutput, CallableInputContract, FunctionDefinition, MethodDefinition } from '../../../language/callable/model/callable.js';
|
|
3
3
|
import type { ResolvedFunction, ResolvedMethod } from '../../../language/callable/resolved.js';
|
|
4
|
-
import type { JsonSchema } from '../../../language/value/model/schema.js';
|
|
5
4
|
import type { EffectiveMethod } from '../../analysis/class.js';
|
|
6
5
|
import type { Fingerprint } from '../model.js';
|
|
7
6
|
export declare function methodExistence(method: EffectiveMethod): Value;
|
|
@@ -20,7 +19,7 @@ export declare function callableFingerprint(callable: ResolvedFunction | Resolve
|
|
|
20
19
|
type CallableSignature = {
|
|
21
20
|
readonly static?: boolean;
|
|
22
21
|
readonly abstract?: boolean;
|
|
23
|
-
readonly input:
|
|
22
|
+
readonly input: CallableInputContract;
|
|
24
23
|
readonly output: CallableOutput;
|
|
25
24
|
};
|
|
26
25
|
/** The `always` fields of CALLABLE_FIELDS: dispatch shape and the semantic input and output. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBinaryInput } from '../../../language/callable/model/callable.js';
|
|
1
2
|
import { methodSignature as inheritedSignature } from '../../analysis/class.js';
|
|
2
3
|
import { deepFreeze } from '../../canonical/freeze.js';
|
|
3
4
|
import { keyForDefinitionRef } from '../coordinate.js';
|
|
@@ -61,7 +62,13 @@ export function callableFingerprint(callable) {
|
|
|
61
62
|
export function callableSignature(declaration) {
|
|
62
63
|
return {
|
|
63
64
|
...fieldsOf({ declaration, roles: CALLABLE_FIELDS }),
|
|
64
|
-
input:
|
|
65
|
+
input: isBinaryInput(declaration.input)
|
|
66
|
+
? {
|
|
67
|
+
mode: 'binary',
|
|
68
|
+
metadata: semanticValueSchema(declaration.input.metadata),
|
|
69
|
+
maximumBytes: declaration.input.maximumBytes,
|
|
70
|
+
}
|
|
71
|
+
: semanticValueSchema(declaration.input),
|
|
65
72
|
output: semanticOutput(declaration.output),
|
|
66
73
|
};
|
|
67
74
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { json } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { compareDefinitionRefs, compareUnicode } from '../../addressing/ordering.js';
|
|
3
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
3
4
|
import { normalizePolicyChecks, normalizePolicyExpression, } from '../../language/policy/normalization/normalize.js';
|
|
4
5
|
import { admitStateTopology } from '../../language/state/topology.js';
|
|
5
6
|
import { canonicalizeValueSchema } from '../../language/value/profile/canonicalize.js';
|
|
@@ -92,7 +93,13 @@ function canonicalizeFunction(value) {
|
|
|
92
93
|
function canonicalizeCallable(value) {
|
|
93
94
|
const base = {
|
|
94
95
|
...withDescription(value),
|
|
95
|
-
input:
|
|
96
|
+
input: isBinaryInput(value.input)
|
|
97
|
+
? {
|
|
98
|
+
mode: 'binary',
|
|
99
|
+
metadata: canonicalizeValueSchema(value.input.metadata, 'callable-input'),
|
|
100
|
+
maximumBytes: value.input.maximumBytes,
|
|
101
|
+
}
|
|
102
|
+
: canonicalizeValueSchema(value.input, 'callable-input'),
|
|
96
103
|
output: canonicalizeCallableOutput(value.output),
|
|
97
104
|
};
|
|
98
105
|
return value.auth === 'authorized'
|
|
@@ -106,6 +113,7 @@ function canonicalizeCallable(value) {
|
|
|
106
113
|
function canonicalizeMethod(value) {
|
|
107
114
|
return {
|
|
108
115
|
...canonicalizeCallable(value),
|
|
116
|
+
input: canonicalizeValueSchema(value.input, 'callable-input'),
|
|
109
117
|
static: value.static,
|
|
110
118
|
abstract: value.abstract,
|
|
111
119
|
};
|
|
@@ -2,6 +2,7 @@ import { Key, MethodKey, PropertyKey } from '../../addressing/index.js';
|
|
|
2
2
|
import { compareUnicode } from '../../addressing/ordering.js';
|
|
3
3
|
import { createDomain, createSourceDomain } from '../../domain/create.js';
|
|
4
4
|
import { createDomainValidation, unknownInputField } from '../../domain/validation/create.js';
|
|
5
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
5
6
|
import { inputFieldNodes } from '../../language/value/compile/fields.js';
|
|
6
7
|
import { prepareValueSchema } from '../../language/value/evaluate/preparation.js';
|
|
7
8
|
import { validateValueProgram } from '../../language/value/evaluate/program.js';
|
|
@@ -78,7 +79,7 @@ function sourceValidation(closure, registries) {
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
for (const definition of Object.values(owner.functions)) {
|
|
81
|
-
callables.set(Key.of(definition.ref), callableValidation(definition.input, definition.output.mode === 'binary'
|
|
82
|
+
callables.set(Key.of(definition.ref), callableValidation(isBinaryInput(definition.input) ? definition.input.metadata : definition.input, definition.output.mode === 'binary'
|
|
82
83
|
? undefined
|
|
83
84
|
: definition.output.mode === 'value'
|
|
84
85
|
? definition.output.schema
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compareDefinitionRefs, definitionRefIndex } from '../../addressing/ordering.js';
|
|
2
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
2
3
|
import { policyVariableClass } from '../../language/policy/model/policy.js';
|
|
3
4
|
import { isValueObject as isJsonObject } from '../../language/value/model/object.js';
|
|
4
5
|
import { walkSchema } from '../../language/value/syntax/walk.js';
|
|
@@ -80,7 +81,7 @@ export function collectCallableRefs(declaration, add) {
|
|
|
80
81
|
}
|
|
81
82
|
/** References inside the contract a caller compiles against: the input and output value schemas. */
|
|
82
83
|
export function collectCallableContractRefs(declaration, add) {
|
|
83
|
-
collectValueDefinitionRefs(declaration.input, add);
|
|
84
|
+
collectValueDefinitionRefs(isBinaryInput(declaration.input) ? declaration.input.metadata : declaration.input, add);
|
|
84
85
|
if (declaration.output.mode === 'value')
|
|
85
86
|
collectValueDefinitionRefs(declaration.output.schema, add);
|
|
86
87
|
if (declaration.output.mode === 'stream')
|
|
@@ -2,6 +2,7 @@ import { Key } from '../../addressing/key.js';
|
|
|
2
2
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
3
|
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
4
4
|
import { admitStateTopology } from '../../language/state/topology.js';
|
|
5
|
+
import { isBlobValueSchema } from '../../language/value/model/blob.js';
|
|
5
6
|
import { classifyOrdering } from '../../language/value/ordering.js';
|
|
6
7
|
import { diagnostic } from '../diagnostic.js';
|
|
7
8
|
import { createValueSchemaRegistry } from '../resolution/value.registry.js';
|
|
@@ -33,6 +34,10 @@ function validateFacet(environment, declaration, pointer, diagnostics) {
|
|
|
33
34
|
const valueRegistry = createValueSchemaRegistry(environment);
|
|
34
35
|
for (const [name, property] of Object.entries(declaration.properties)) {
|
|
35
36
|
const propertyPointer = `${pointer}/properties/${escapePointer(name)}`;
|
|
37
|
+
if (isBlobValueSchema(property.schema) &&
|
|
38
|
+
(declaration.kind !== 'node' || property.auto !== undefined || property.state !== undefined)) {
|
|
39
|
+
diagnostics.push(diagnostic('DV_VALUE_SCHEMA', `${propertyPointer}/schema/x-astrale-value-kind`, 'Blob values are allowed only on non-automatic, non-state Node properties.'));
|
|
40
|
+
}
|
|
36
41
|
if (property.state !== undefined) {
|
|
37
42
|
if (declaration.kind !== 'node') {
|
|
38
43
|
diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, 'A State Property may be declared only on a Node Class.'));
|
|
@@ -183,6 +183,12 @@ const callableOutputSchema = discriminatedUnion('mode', [
|
|
|
183
183
|
mode: literal('binary'),
|
|
184
184
|
}),
|
|
185
185
|
]);
|
|
186
|
+
const binaryInputSchema = strictObject({
|
|
187
|
+
mode: literal('binary'),
|
|
188
|
+
metadata: jsonSchemaSchema,
|
|
189
|
+
maximumBytes: number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
190
|
+
});
|
|
191
|
+
const valueFunctionInputSchema = jsonSchemaSchema.refine((value) => typeof value !== 'object' || value === null || value.mode !== 'binary', 'Binary input must declare metadata and maximumBytes.');
|
|
186
192
|
const callableShape = {
|
|
187
193
|
description: descriptionSchema.optional(),
|
|
188
194
|
input: jsonSchemaSchema,
|
|
@@ -254,6 +260,7 @@ function validateEdgeOrientationShape(value, context) {
|
|
|
254
260
|
const functionDefinitionSchema = strictObject({
|
|
255
261
|
ref: functionRefSchema,
|
|
256
262
|
...callableShape,
|
|
263
|
+
input: union([binaryInputSchema, valueFunctionInputSchema]),
|
|
257
264
|
}).superRefine((callable, context) => {
|
|
258
265
|
if (callable.auth !== 'authorized' && callable.policy !== undefined) {
|
|
259
266
|
context.addIssue({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Key } from '../../../addressing/index.js';
|
|
2
2
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
3
|
+
import { isBinaryInput } from '../../../language/callable/model/callable.js';
|
|
3
4
|
import { normalizePolicyChecks } from '../../../language/policy/normalization/normalize.js';
|
|
4
5
|
import { GRAPH_NODE_PATH_SCHEMA_ID } from '../../../language/value/syntax/node-path/schema.js';
|
|
5
6
|
import { MAX_BRANCHES, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, measureChecks } from './budgets.js';
|
|
@@ -48,7 +49,7 @@ export function validateCallableUses(context, typing) {
|
|
|
48
49
|
continue;
|
|
49
50
|
validateChecks(context, typing, declaration.policy, {
|
|
50
51
|
pointer: `/functions/${escapePointer(name)}/policy`,
|
|
51
|
-
input: declaration.input,
|
|
52
|
+
input: isBinaryInput(declaration.input) ? declaration.input.metadata : declaration.input,
|
|
52
53
|
instanceMethod: false,
|
|
53
54
|
});
|
|
54
55
|
}
|
|
@@ -4,6 +4,8 @@ import type { JsonSchema } from '../../language/value/model/schema.js';
|
|
|
4
4
|
import type { OrderingKind } from '../../language/value/ordering.js';
|
|
5
5
|
import type { DomainSchema } from '../model/schema.js';
|
|
6
6
|
export { VALUE_SCHEMA_DIALECT as DIALECT, VALUE_SCHEMA_VOCABULARY as VOCABULARY, } from '../../language/value/model/schema.js';
|
|
7
|
+
export { blob, isBlobValueSchema as isBlob } from '../../language/value/model/blob.js';
|
|
8
|
+
export type { BlobOptions, BlobReceipt, BlobRef, BlobSchema, } from '../../language/value/model/blob.js';
|
|
7
9
|
export type { JsonSchema as Schema, JsonSchemaObject as SchemaObject, PathAnnotation, PropertyObjectSchema as PropertySchema, ValueSchemaContext as Context, } from '../../language/value/model/schema.js';
|
|
8
10
|
export { instant } from '../../language/value/model/instant.js';
|
|
9
11
|
export type { OrderingKind } from '../../language/value/ordering.js';
|
|
@@ -4,6 +4,7 @@ import { classifyOrdering as classifyOrderingWithRegistry } from '../../language
|
|
|
4
4
|
import { createDomainValueSchemaRegistry } from '../resolution/value.registry.js';
|
|
5
5
|
const registries = new WeakMap();
|
|
6
6
|
export { VALUE_SCHEMA_DIALECT as DIALECT, VALUE_SCHEMA_VOCABULARY as VOCABULARY, } from '../../language/value/model/schema.js';
|
|
7
|
+
export { blob, isBlobValueSchema as isBlob } from '../../language/value/model/blob.js';
|
|
7
8
|
export { instant } from '../../language/value/model/instant.js';
|
|
8
9
|
/** Validate one complete JSON value under the exact accepted schema that owns the contract. */
|
|
9
10
|
export function validate(owner, contract, input, pointer = '') {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
1
2
|
import { validateValueSchema } from '../../language/value/profile/validate.js';
|
|
2
3
|
import { diagnostic } from '../diagnostic.js';
|
|
3
4
|
export function validateEmbeddedValueSchemas(schema, registry) {
|
|
@@ -21,7 +22,12 @@ function validateDefinition(declaration, pointer, registry, diagnostics) {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
function validateCallable(declaration, pointer, registry, diagnostics) {
|
|
24
|
-
|
|
25
|
+
if (isBinaryInput(declaration.input)) {
|
|
26
|
+
validate(declaration.input.metadata, 'callable-input', `${pointer}/input/metadata`, registry, diagnostics);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
validate(declaration.input, 'callable-input', `${pointer}/input`, registry, diagnostics);
|
|
30
|
+
}
|
|
25
31
|
if (declaration.output.mode === 'value') {
|
|
26
32
|
validate(declaration.output.schema, 'callable-output', `${pointer}/output/schema`, registry, diagnostics);
|
|
27
33
|
}
|
package/dist/value/canonical.js
CHANGED
|
@@ -14,7 +14,8 @@ export function serializeAdmitted(input) {
|
|
|
14
14
|
}
|
|
15
15
|
function serializeSnapshot(input, maxBytes) {
|
|
16
16
|
const output = serializeValue(input);
|
|
17
|
-
|
|
17
|
+
// Scalar text uses at most three UTF-8 bytes per UTF-16 code unit, including JSON escapes.
|
|
18
|
+
if (output.length > maxBytes / 3 && utf8Length(output, maxBytes) > maxBytes) {
|
|
18
19
|
throw new BoundaryError('VALUE_LIMIT', `Canonical JSON exceeds the ${maxBytes}-byte limit`);
|
|
19
20
|
}
|
|
20
21
|
return output;
|