@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.
Files changed (40) hide show
  1. package/dist/v1/builder/callable/authoring.d.ts +22 -6
  2. package/dist/v1/builder/callable/authoring.js +13 -0
  3. package/dist/v1/builder/class/authoring.d.ts +5 -3
  4. package/dist/v1/builder/index.d.ts +2 -2
  5. package/dist/v1/builder/index.js +1 -1
  6. package/dist/v1/builder/lowering/callable.js +18 -5
  7. package/dist/v1/builder/schema/handle.d.ts +1 -1
  8. package/dist/v1/builder/schema/projection.d.ts +11 -8
  9. package/dist/v1/compiled/admission/accept.js +15 -1
  10. package/dist/v1/compiled/admission/revision.js +7 -1
  11. package/dist/v1/compiled/admission/semantics.js +2 -2
  12. package/dist/v1/compiled/compiler/compile.js +13 -2
  13. package/dist/v1/compiled/loader/load.js +8 -2
  14. package/dist/v1/compiled/model/schema.d.ts +5 -1
  15. package/dist/v1/index.d.ts +3 -2
  16. package/dist/v1/index.js +2 -1
  17. package/dist/v1/language/callable/model/callable.d.ts +18 -4
  18. package/dist/v1/language/callable/model/callable.js +3 -1
  19. package/dist/v1/language/callable/resolved.d.ts +7 -2
  20. package/dist/v1/language/class/facets.d.ts +2 -1
  21. package/dist/v1/language/class/resolved.d.ts +11 -4
  22. package/dist/v1/language/index.d.ts +1 -0
  23. package/dist/v1/language/index.js +1 -0
  24. package/dist/v1/language/value/evaluate/evaluator.js +4 -0
  25. package/dist/v1/language/value/model/blob.d.ts +33 -0
  26. package/dist/v1/language/value/model/blob.js +90 -0
  27. package/dist/v1/language/value/profile/rules.js +36 -4
  28. package/dist/v1/schema/compatibility/comparators/callables.d.ts +2 -3
  29. package/dist/v1/schema/compatibility/comparators/callables.js +8 -1
  30. package/dist/v1/schema/normalization/domain.js +9 -1
  31. package/dist/v1/schema/resolution/domain.js +2 -1
  32. package/dist/v1/schema/resolution/origins.js +2 -1
  33. package/dist/v1/schema/validation/class.js +5 -0
  34. package/dist/v1/schema/validation/domain.structure.js +7 -0
  35. package/dist/v1/schema/validation/policy/uses.js +2 -1
  36. package/dist/v1/schema/validation/value-api.d.ts +2 -0
  37. package/dist/v1/schema/validation/value-api.js +1 -0
  38. package/dist/v1/schema/validation/value.js +7 -1
  39. package/dist/value/canonical.js +2 -1
  40. 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 CallableInputBase {
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: ValueSchemaInput;
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 = ValueInputOf<Config['input']>, Output = CallableOutputOf<Config['output']>, Auth extends FunctionAuth = Config['auth']>(config: Config): Function<CallableProjection<Input, Output, Auth, false, false>>;
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';
@@ -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 input = this.values.schema(config.input, 'callable-input', `${placement.pointer}/input`);
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(input, placement, isStatic ?? false)));
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 { ref: placement.ref, ...contract };
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>]: AuthoredProjectionInput<Extract<CoreAuthoredProjections<Entries>, {
229
+ [Name in RequiredAuthoredPropertyNames<Entries>]: CoreProjectionInput<Extract<CoreAuthoredProjections<Entries>, {
227
230
  readonly name: Name;
228
231
  }>>;
229
232
  } & {
230
- [Name in OptionalAuthoredPropertyNames<Entries>]?: AuthoredProjectionInput<Extract<CoreAuthoredProjections<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<unknown, infer Output, infer Required, string, unknown, infer State> ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, Name, PropertyName>, State> : never : never : never;
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<unknown, 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> : never : never;
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
- const inputIndex = index(value.input, values.length, 'Callable input', `${path}/input`);
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: schemaOf(entry, 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 input = add(definition.input, `/functions/${definition.ref.name}/input`);
100
- const fields = inputFieldNodes(values[input]);
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: schemaOf(entry, 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
  }
@@ -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
- export interface CallableDefinitionBase {
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: JsonSchema;
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 {};
@@ -1 +1,3 @@
1
- export {};
1
+ export function isBinaryInput(input) {
2
+ return typeof input === 'object' && input !== null && input.mode === 'binary';
3
+ }
@@ -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
- export type CallableInputOf<Callable> = Callable extends ResolvedMethod<infer Input, unknown, boolean> ? Input : Callable extends ResolvedFunction<infer Input, unknown> ? Input : never;
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> = PropertyInput<PropertyByKeyOf<Class>, PropertyByNameOf<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'] !== 'instant' || schema.type !== 'string') {
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: JsonSchema;
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: semanticValueSchema(declaration.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: canonicalizeValueSchema(value.input, 'callable-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
- validate(declaration.input, 'callable-input', `${pointer}/input`, registry, diagnostics);
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
  }
@@ -14,7 +14,8 @@ export function serializeAdmitted(input) {
14
14
  }
15
15
  function serializeSnapshot(input, maxBytes) {
16
16
  const output = serializeValue(input);
17
- if (utf8Length(output, maxBytes) > maxBytes) {
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/kernel-dsl",
3
- "version": "0.2.0-beta.39",
3
+ "version": "0.2.0-beta.40",
4
4
  "description": "Astrale Kernel DSL - Schema authoring, inference, and IR serialization",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {