@astrale-os/kernel-core 0.9.0-beta.22 → 0.9.0-beta.24
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/CHANGELOG.md +14 -0
- package/dist/graph/query/reference/evaluate.d.ts +1 -0
- package/dist/graph/query/reference/evaluate.js +11 -0
- package/dist/schema/callables/view.d.ts +8 -0
- package/dist/schema/kernel/schema.d.ts +21 -9
- package/dist/schema/kernel/syscalls/contracts/view-resolve.d.ts +4 -0
- package/dist/schema/kernel/syscalls/contracts/view-resolve.js +5 -0
- package/dist/schema/kernel/syscalls/declarations/index.d.ts +4 -0
- package/dist/schema/kernel/syscalls/declarations/view-resolve.d.ts +4 -0
- package/dist/schema/kernel/syscalls/descriptors/results/view-resolution.d.ts +5 -0
- package/dist/schema/kernel/syscalls/descriptors/results/view-resolution.js +81 -0
- package/dist/schema/kernel/syscalls/descriptors/view.d.ts +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@
|
|
|
6
6
|
|
|
7
7
|
* remove endpoint, route, serving issuer, Publication ETag, and View placement properties from the
|
|
8
8
|
Function and UI schema; graph projection now contains declaration meaning only
|
|
9
|
+
## [0.9.0-beta.24](https://github.com/astrale-os/kernel/compare/kernel-core-v0.9.0-beta.23...kernel-core-v0.9.0-beta.24) (2026-08-29)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Performance Improvements
|
|
13
|
+
|
|
14
|
+
* **runtime:** optimize Query execution without regressions ([#507](https://github.com/astrale-os/kernel/issues/507)) ([6101c8f](https://github.com/astrale-os/kernel/commit/6101c8f9d5deae99a821b3b373b50ee953510600))
|
|
15
|
+
|
|
16
|
+
## [0.9.0-beta.23](https://github.com/astrale-os/kernel/compare/kernel-core-v0.9.0-beta.22...kernel-core-v0.9.0-beta.23) (2026-08-29)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* **api:** carry view iframe requirements ([#531](https://github.com/astrale-os/kernel/issues/531)) ([4eedb0b](https://github.com/astrale-os/kernel/commit/4eedb0b3430f5f642942e913cf1c5806e09b7cf1))
|
|
22
|
+
|
|
9
23
|
## [0.9.0-beta.22](https://github.com/astrale-os/kernel/compare/kernel-core-v0.9.0-beta.21...kernel-core-v0.9.0-beta.22) (2026-08-29)
|
|
10
24
|
|
|
11
25
|
|
|
@@ -29,6 +29,7 @@ export interface QueryReferenceContext {
|
|
|
29
29
|
closeClass(classRef: ClassRef): QueryReferenceClassClosure | undefined;
|
|
30
30
|
closeProperty(property: PropertyKeyValue): QueryReferenceProperty | undefined;
|
|
31
31
|
orientation(edge: ClassKey): EdgeOrientation | undefined;
|
|
32
|
+
admitEdge(edge: Edge, source: Node, target: Node): boolean;
|
|
32
33
|
traverseNode(node: Node): boolean;
|
|
33
34
|
traverseEdge(edge: Edge): boolean;
|
|
34
35
|
readNode(node: Node): boolean;
|
|
@@ -611,6 +611,15 @@ class Admission {
|
|
|
611
611
|
const cached = this.#edges.get(key);
|
|
612
612
|
if (cached !== undefined)
|
|
613
613
|
return cached;
|
|
614
|
+
const source = requireNode(this.context, edge.source, path);
|
|
615
|
+
const target = requireNode(this.context, edge.target, path);
|
|
616
|
+
const admitted = call(path, 'Logical Edge fact admission failed', () => this.context.admitEdge(edge, source, target));
|
|
617
|
+
if (typeof admitted !== 'boolean')
|
|
618
|
+
invalid(path, 'Logical Edge fact admission must return boolean');
|
|
619
|
+
if (!admitted) {
|
|
620
|
+
this.#edges.set(key, false);
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
614
623
|
const explicit = call(path, 'Edge traversal admission failed', () => this.context.traverseEdge(edge));
|
|
615
624
|
if (typeof explicit !== 'boolean')
|
|
616
625
|
invalid(path, 'Edge traversal admission must return boolean');
|
|
@@ -648,6 +657,7 @@ function acceptContext(input) {
|
|
|
648
657
|
'closeClass',
|
|
649
658
|
'closeProperty',
|
|
650
659
|
'orientation',
|
|
660
|
+
'admitEdge',
|
|
651
661
|
'traverseNode',
|
|
652
662
|
'traverseEdge',
|
|
653
663
|
'readNode',
|
|
@@ -671,6 +681,7 @@ function acceptContext(input) {
|
|
|
671
681
|
closeClass: input.closeClass.bind(input),
|
|
672
682
|
closeProperty: input.closeProperty.bind(input),
|
|
673
683
|
orientation: input.orientation.bind(input),
|
|
684
|
+
admitEdge: input.admitEdge.bind(input),
|
|
674
685
|
traverseNode: input.traverseNode.bind(input),
|
|
675
686
|
traverseEdge: input.traverseEdge.bind(input),
|
|
676
687
|
readNode: input.readNode.bind(input),
|
|
@@ -42,6 +42,10 @@ export declare const View: builder.NodeClass<{
|
|
|
42
42
|
};
|
|
43
43
|
href: string;
|
|
44
44
|
handshake: "none" | "shell";
|
|
45
|
+
iframe?: {
|
|
46
|
+
sandbox?: string[] | undefined;
|
|
47
|
+
allow?: string[] | undefined;
|
|
48
|
+
} | undefined;
|
|
45
49
|
issuer: string;
|
|
46
50
|
etag: string;
|
|
47
51
|
revision: string;
|
|
@@ -81,6 +85,10 @@ export declare const View: builder.NodeClass<{
|
|
|
81
85
|
};
|
|
82
86
|
href: string;
|
|
83
87
|
handshake: "none" | "shell";
|
|
88
|
+
iframe?: {
|
|
89
|
+
sandbox?: string[] | undefined;
|
|
90
|
+
allow?: string[] | undefined;
|
|
91
|
+
} | undefined;
|
|
84
92
|
issuer: string;
|
|
85
93
|
etag: string;
|
|
86
94
|
revision: string;
|
|
@@ -4269,6 +4269,10 @@ declare const KernelDefinitions: {
|
|
|
4269
4269
|
};
|
|
4270
4270
|
href: string;
|
|
4271
4271
|
handshake: "none" | "shell";
|
|
4272
|
+
iframe?: {
|
|
4273
|
+
sandbox?: string[] | undefined;
|
|
4274
|
+
allow?: string[] | undefined;
|
|
4275
|
+
} | undefined;
|
|
4272
4276
|
issuer: string;
|
|
4273
4277
|
etag: string;
|
|
4274
4278
|
revision: string;
|
|
@@ -4308,6 +4312,10 @@ declare const KernelDefinitions: {
|
|
|
4308
4312
|
};
|
|
4309
4313
|
href: string;
|
|
4310
4314
|
handshake: "none" | "shell";
|
|
4315
|
+
iframe?: {
|
|
4316
|
+
sandbox?: string[] | undefined;
|
|
4317
|
+
allow?: string[] | undefined;
|
|
4318
|
+
} | undefined;
|
|
4311
4319
|
issuer: string;
|
|
4312
4320
|
etag: string;
|
|
4313
4321
|
revision: string;
|
|
@@ -6451,15 +6459,6 @@ export declare const KernelRootFunctions: readonly ((import("@astrale-os/kernel-
|
|
|
6451
6459
|
readonly origin: "kernel.astrale.ai";
|
|
6452
6460
|
};
|
|
6453
6461
|
readonly key: "kernel.astrale.ai:function.uninstall";
|
|
6454
|
-
}) | (import("@astrale-os/kernel-dsl/v1").ResolvedMethod<{
|
|
6455
|
-
audience?: string | undefined;
|
|
6456
|
-
ttlSeconds: number;
|
|
6457
|
-
grant?: unknown;
|
|
6458
|
-
}, {
|
|
6459
|
-
readonly mode: 'value';
|
|
6460
|
-
readonly value: string;
|
|
6461
|
-
}, true, "default", "authorized", import("@astrale-os/kernel-dsl/v1").PolicyCheckExpression<import("@astrale-os/kernel-dsl/v1").PolicyRef, import("@astrale-os/kernel-dsl/v1/language").PolicyCheckObject>, "kernel.astrale.ai:class.Identity.method.mint"> & {
|
|
6462
|
-
readonly name: "mint";
|
|
6463
6462
|
}) | (import("@astrale-os/kernel-dsl/v1").ResolvedMethod<{
|
|
6464
6463
|
iss: string;
|
|
6465
6464
|
sub: string;
|
|
@@ -6508,6 +6507,10 @@ export declare const KernelRootFunctions: readonly ((import("@astrale-os/kernel-
|
|
|
6508
6507
|
};
|
|
6509
6508
|
href: string;
|
|
6510
6509
|
handshake: "none" | "shell";
|
|
6510
|
+
iframe?: {
|
|
6511
|
+
sandbox?: string[] | undefined;
|
|
6512
|
+
allow?: string[] | undefined;
|
|
6513
|
+
} | undefined;
|
|
6511
6514
|
issuer: string;
|
|
6512
6515
|
etag: string;
|
|
6513
6516
|
revision: string;
|
|
@@ -6515,6 +6518,15 @@ export declare const KernelRootFunctions: readonly ((import("@astrale-os/kernel-
|
|
|
6515
6518
|
};
|
|
6516
6519
|
}, true, "sealed", "authorized", import("@astrale-os/kernel-dsl/v1").PolicyCheckExpression<import("@astrale-os/kernel-dsl/v1").PolicyRef, import("@astrale-os/kernel-dsl/v1/language").PolicyCheckObject>, "kernel.astrale.ai:class.View.method.resolve"> & {
|
|
6517
6520
|
readonly name: "resolve";
|
|
6521
|
+
}) | (import("@astrale-os/kernel-dsl/v1").ResolvedMethod<{
|
|
6522
|
+
audience?: string | undefined;
|
|
6523
|
+
ttlSeconds: number;
|
|
6524
|
+
grant?: unknown;
|
|
6525
|
+
}, {
|
|
6526
|
+
readonly mode: 'value';
|
|
6527
|
+
readonly value: string;
|
|
6528
|
+
}, true, "default", "authorized", import("@astrale-os/kernel-dsl/v1").PolicyCheckExpression<import("@astrale-os/kernel-dsl/v1").PolicyRef, import("@astrale-os/kernel-dsl/v1/language").PolicyCheckObject>, "kernel.astrale.ai:class.Identity.method.mint"> & {
|
|
6529
|
+
readonly name: "mint";
|
|
6518
6530
|
}))[];
|
|
6519
6531
|
export { AuthorityOperationOrder, AuthorityOperations, operationOf } from '../authority/index.js';
|
|
6520
6532
|
export type { AuthorityOperation, AuthorityRelation } from '../authority/index.js';
|
|
@@ -24,6 +24,10 @@ export declare const viewResolveOutput: z.ZodObject<{
|
|
|
24
24
|
none: "none";
|
|
25
25
|
shell: "shell";
|
|
26
26
|
}>;
|
|
27
|
+
iframe: z.ZodOptional<z.ZodObject<{
|
|
28
|
+
sandbox: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
29
|
+
allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
30
|
+
}, z.core.$strict>>;
|
|
27
31
|
issuer: z.ZodString;
|
|
28
32
|
etag: z.ZodString;
|
|
29
33
|
revision: z.ZodString;
|
|
@@ -13,6 +13,10 @@ const declaration = z.strictObject({
|
|
|
13
13
|
z.strictObject({ kind: z.literal('definition'), definitions: z.array(definition).min(1) }),
|
|
14
14
|
]),
|
|
15
15
|
});
|
|
16
|
+
const iframeRequirements = z.strictObject({
|
|
17
|
+
sandbox: z.array(z.string()).optional(),
|
|
18
|
+
allow: z.array(z.string()).optional(),
|
|
19
|
+
});
|
|
16
20
|
export const viewResolveInput = z.strictObject({ target: z.string().min(1) });
|
|
17
21
|
export const viewResolveOutput = z.strictObject({
|
|
18
22
|
snapshot: z.string().min(1),
|
|
@@ -21,6 +25,7 @@ export const viewResolveOutput = z.strictObject({
|
|
|
21
25
|
declaration,
|
|
22
26
|
href: z.string().min(1),
|
|
23
27
|
handshake: z.enum(['shell', 'none']),
|
|
28
|
+
iframe: iframeRequirements.optional(),
|
|
24
29
|
issuer: z.string().min(1),
|
|
25
30
|
etag: z.string().min(1),
|
|
26
31
|
revision: z.string().min(1),
|
|
@@ -922,6 +922,10 @@ export declare const ViewMethods: Readonly<{
|
|
|
922
922
|
};
|
|
923
923
|
href: string;
|
|
924
924
|
handshake: "none" | "shell";
|
|
925
|
+
iframe?: {
|
|
926
|
+
sandbox?: string[] | undefined;
|
|
927
|
+
allow?: string[] | undefined;
|
|
928
|
+
} | undefined;
|
|
925
929
|
issuer: string;
|
|
926
930
|
etag: string;
|
|
927
931
|
revision: string;
|
|
@@ -22,6 +22,10 @@ export declare const ViewResolve: builder.Method<builder.CallableProjection<{
|
|
|
22
22
|
};
|
|
23
23
|
href: string;
|
|
24
24
|
handshake: "none" | "shell";
|
|
25
|
+
iframe?: {
|
|
26
|
+
sandbox?: string[] | undefined;
|
|
27
|
+
allow?: string[] | undefined;
|
|
28
|
+
} | undefined;
|
|
25
29
|
issuer: string;
|
|
26
30
|
etag: string;
|
|
27
31
|
revision: string;
|
|
@@ -6,10 +6,15 @@ export interface ResolvedView {
|
|
|
6
6
|
readonly declaration: ViewDeclaration;
|
|
7
7
|
readonly href: string;
|
|
8
8
|
readonly handshake: 'shell' | 'none';
|
|
9
|
+
readonly iframe?: IframeRequirements;
|
|
9
10
|
readonly issuer: IssuerId;
|
|
10
11
|
readonly etag: `sha256:${string}`;
|
|
11
12
|
readonly revision: Revision;
|
|
12
13
|
}
|
|
14
|
+
export interface IframeRequirements {
|
|
15
|
+
readonly sandbox?: readonly string[];
|
|
16
|
+
readonly allow?: readonly string[];
|
|
17
|
+
}
|
|
13
18
|
type ViewDeclaration = Omit<ViewDefinition, 'ref'>;
|
|
14
19
|
export interface ViewResolution {
|
|
15
20
|
readonly snapshot: `sha256:${string}`;
|
|
@@ -23,11 +23,13 @@ export function acceptViewResolution(input) {
|
|
|
23
23
|
if (!issuer.is(view.issuer))
|
|
24
24
|
invalid(`Resolved View ${index} issuer is not canonical.`);
|
|
25
25
|
const declaration = acceptDeclaration(view.declaration, index);
|
|
26
|
+
const iframe = acceptIframeRequirements(view.iframe, view.handshake, index);
|
|
26
27
|
return Object.freeze({
|
|
27
28
|
key,
|
|
28
29
|
declaration,
|
|
29
30
|
href: view.href,
|
|
30
31
|
handshake: view.handshake,
|
|
32
|
+
...(iframe === undefined ? {} : { iframe }),
|
|
31
33
|
issuer: view.issuer,
|
|
32
34
|
etag: digest(view.etag, `Resolved View ${index} ETag`),
|
|
33
35
|
revision: digest(view.revision, `Resolved View ${index} revision`),
|
|
@@ -43,6 +45,85 @@ export function acceptViewResolution(input) {
|
|
|
43
45
|
views: Object.freeze(views),
|
|
44
46
|
});
|
|
45
47
|
}
|
|
48
|
+
const IFRAME_TOKEN = /^[a-z][a-z0-9-]*$/u;
|
|
49
|
+
function acceptIframeRequirements(input, handshake, viewIndex) {
|
|
50
|
+
if (input === undefined)
|
|
51
|
+
return undefined;
|
|
52
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
53
|
+
invalid(`Resolved View ${viewIndex} iframe requirements are invalid.`);
|
|
54
|
+
}
|
|
55
|
+
const prototype = Object.getPrototypeOf(input);
|
|
56
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
57
|
+
invalid(`Resolved View ${viewIndex} iframe requirements are invalid.`);
|
|
58
|
+
}
|
|
59
|
+
const value = input;
|
|
60
|
+
if (Reflect.ownKeys(value).some((key) => key !== 'sandbox' && key !== 'allow')) {
|
|
61
|
+
invalid(`Resolved View ${viewIndex} iframe requirements contain unknown fields.`);
|
|
62
|
+
}
|
|
63
|
+
const sandbox = acceptTokens(dataValue(value, 'sandbox', viewIndex), viewIndex, 'sandbox');
|
|
64
|
+
const allow = acceptTokens(dataValue(value, 'allow', viewIndex), viewIndex, 'allow');
|
|
65
|
+
const baselineSandbox = new Set(handshake === 'shell' ? ['allow-same-origin', 'allow-scripts'] : ['allow-scripts']);
|
|
66
|
+
const baselineAllow = new Set(handshake === 'shell' ? ['clipboard-write'] : []);
|
|
67
|
+
if (sandbox.some((token) => baselineSandbox.has(token)) ||
|
|
68
|
+
allow.some((token) => baselineAllow.has(token))) {
|
|
69
|
+
invalid(`Resolved View ${viewIndex} iframe requirements repeat a fixed handshake baseline.`);
|
|
70
|
+
}
|
|
71
|
+
const tokens = new Set(sandbox);
|
|
72
|
+
if (tokens.has('allow-popups-to-escape-sandbox') && !tokens.has('allow-popups')) {
|
|
73
|
+
invalid(`Resolved View ${viewIndex} popup escape requires popup authority.`);
|
|
74
|
+
}
|
|
75
|
+
if (tokens.has('allow-top-navigation') && tokens.has('allow-top-navigation-by-user-activation')) {
|
|
76
|
+
invalid(`Resolved View ${viewIndex} iframe navigation requirements are redundant.`);
|
|
77
|
+
}
|
|
78
|
+
if (tokens.has('allow-top-navigation-to-custom-protocols') &&
|
|
79
|
+
(tokens.has('allow-top-navigation') || tokens.has('allow-popups'))) {
|
|
80
|
+
invalid(`Resolved View ${viewIndex} custom-protocol requirements are redundant.`);
|
|
81
|
+
}
|
|
82
|
+
if (sandbox.length === 0 && allow.length === 0) {
|
|
83
|
+
invalid(`Resolved View ${viewIndex} empty iframe requirements must be omitted.`);
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze({ sandbox: Object.freeze(sandbox), allow: Object.freeze(allow) });
|
|
86
|
+
}
|
|
87
|
+
function dataValue(input, key, viewIndex) {
|
|
88
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
89
|
+
if (descriptor === undefined)
|
|
90
|
+
return undefined;
|
|
91
|
+
if (!('value' in descriptor)) {
|
|
92
|
+
invalid(`Resolved View ${viewIndex} iframe requirements are invalid.`);
|
|
93
|
+
}
|
|
94
|
+
return descriptor.value;
|
|
95
|
+
}
|
|
96
|
+
function acceptTokens(input, viewIndex, field) {
|
|
97
|
+
if (input === undefined)
|
|
98
|
+
return [];
|
|
99
|
+
if (!Array.isArray(input))
|
|
100
|
+
invalid(`Resolved View ${viewIndex} iframe ${field} is invalid.`);
|
|
101
|
+
const descriptors = Object.getOwnPropertyDescriptors(input);
|
|
102
|
+
const values = [];
|
|
103
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
104
|
+
const descriptor = descriptors[String(index)];
|
|
105
|
+
if (descriptor === undefined ||
|
|
106
|
+
!('value' in descriptor) ||
|
|
107
|
+
typeof descriptor.value !== 'string' ||
|
|
108
|
+
!IFRAME_TOKEN.test(descriptor.value)) {
|
|
109
|
+
invalid(`Resolved View ${viewIndex} iframe ${field} contains an invalid token.`);
|
|
110
|
+
}
|
|
111
|
+
values.push(descriptor.value);
|
|
112
|
+
}
|
|
113
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
114
|
+
if (key === 'length')
|
|
115
|
+
continue;
|
|
116
|
+
if (typeof key !== 'string' || !/^(0|[1-9][0-9]*)$/u.test(key) || Number(key) >= input.length) {
|
|
117
|
+
invalid(`Resolved View ${viewIndex} iframe ${field} is invalid.`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (let index = 1; index < values.length; index += 1) {
|
|
121
|
+
if (values[index - 1] >= values[index]) {
|
|
122
|
+
invalid(`Resolved View ${viewIndex} iframe ${field} is not in strict canonical order.`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return values;
|
|
126
|
+
}
|
|
46
127
|
function acceptDeclaration(input, viewIndex) {
|
|
47
128
|
if (input.target.kind === 'domain') {
|
|
48
129
|
return Object.freeze({
|
|
@@ -26,6 +26,10 @@ export declare const resolve: import("./model.js").MethodSyscall<Readonly<{
|
|
|
26
26
|
};
|
|
27
27
|
href: string;
|
|
28
28
|
handshake: "none" | "shell";
|
|
29
|
+
iframe?: {
|
|
30
|
+
sandbox?: string[] | undefined;
|
|
31
|
+
allow?: string[] | undefined;
|
|
32
|
+
} | undefined;
|
|
29
33
|
issuer: string;
|
|
30
34
|
etag: string;
|
|
31
35
|
revision: string;
|