@astrale-os/sdk 0.6.0-beta.1 → 0.6.0-beta.3

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/README.md CHANGED
@@ -213,6 +213,21 @@ Disabled rules are skipped before evaluation and remain visible in lint coverage
213
213
  project rule disable does not bypass generic Oxlint, project admission, type-universe checks, or
214
214
  linter tool failures.
215
215
 
216
+ A committed tree that is not Domain source, such as client mockups or a preview harness, can be
217
+ excluded from `astrale-domain lint` with root-relative globs:
218
+
219
+ ```json
220
+ {
221
+ "ignore": ["mockups/**", "prototypes/**"]
222
+ }
223
+ ```
224
+
225
+ Ignored paths are pruned before discovery: they are never read, parsed, counted against source
226
+ limits, included in the source snapshot digest, or passed to generic Oxlint. Each glob starts with a
227
+ literal root entry and may use `*` and `?` within a segment and `**` as a whole segment; a matched
228
+ directory excludes everything below it. A glob that would cover a declared layer (including a
229
+ remapped `sourcePath`) or a governed root file is rejected, so `ignore` cannot bypass the layout.
230
+
216
231
  Structured review [issues](issues/README.md) retain observation-first evidence and later governance
217
232
  attachments without becoming current contract authority.
218
233
 
@@ -246,6 +261,54 @@ URL, size, and ETag checks. Concurrent publication and snapshot observations sha
246
261
  cancelling one observer does not cancel another. `session.snapshot()` remains the complete,
247
262
  coherent Publication, bundle, and View catalog observation.
248
263
 
264
+ ## Headless scripts and Domain callables
265
+
266
+ Function admission requires the principal itself to be able to use the Function. A credential
267
+ minted for a user or key, such as `astrale token`, carries that identity as principal: it passes
268
+ Kernel callables, but a Domain callable that the identity reaches only through a Policy fails with
269
+ `2004`. The Session `exchange` option presents each Domain callable with a credential its declaring
270
+ Domain exchanged for the caller instead. The Domain becomes the principal, and the Policy is still
271
+ evaluated against the caller. Kernel callables, including graph reads and writes, keep the source
272
+ credential.
273
+
274
+ ```ts
275
+ import { connect, createSessionCredentialProvider } from '@astrale-os/sdk/client/session'
276
+
277
+ const session = connect({
278
+ url: 'https://instance.example/api',
279
+ auth: createSessionCredentialProvider({
280
+ ttlSeconds: 60,
281
+ // Return { credential, expiresAt } with expiresAt in Unix milliseconds.
282
+ mint: (signal) => mintSourceCredential(signal),
283
+ }),
284
+ exchange: {},
285
+ })
286
+
287
+ await session.call({ target: '/:orders.example:class.Order:create', input }) // Domain callable
288
+ await session.graph.get('@order-id') // Kernel callable: the source credential
289
+ ```
290
+
291
+ - **Hold the source in a provider.** Domain credentials are cached per source credential, so a
292
+ `resolve` that returns a new token on every call also exchanges on every call. The provider also
293
+ lets the Session renew a source that is too close to expiry to feed a Domain credential.
294
+ - **Lifetimes.** `exchange.ttlSeconds` (default 300) must exceed the provider's `ttlSeconds` plus a
295
+ 5-second settlement skew. A Domain credential never outlives its source.
296
+ - **Reading as a Domain.** To call Kernel callables as a Domain, for example to read Shell-owned
297
+ Classes, feed a second Session from an explicit exchange:
298
+ `createSessionCredentialProvider({ ttlSeconds: 60, mint: (signal) => session.exchange(shellIssuer, { signal }) })`.
299
+ `session.exchange(issuer)` caches nothing.
300
+ - **Current identity.** Use `session.auth.whoami()`; `@self` is a CLI shorthand.
301
+ - **Failures.** A failed exchange raises `ExchangeError` from `@astrale-os/sdk/client`. Its
302
+ `failure` names the reason (`discovery`, `unsupported`, `unavailable`, `rejected`,
303
+ `invalid-response` or `source-exhausted`); a `rejected` error carries the Domain's public error
304
+ as its cause. Branch on `failure`, not on the message.
305
+
306
+ | Credential presented | Principal | Kernel callable | Domain callable reached by Policy |
307
+ | --- | --- | --- | --- |
308
+ | Source credential (minted or key) | the identity | ✅ | ❌ `2004`, unless the identity holds `can_use` on it through a Group |
309
+ | Session with `exchange` | the declaring Domain, for Domain callables | ✅ with the source credential | ✅ Policy evaluated against the identity |
310
+ | `session.exchange(issuer)` held by a second Session | that Domain | ✅ as that Domain | only what that Domain may use |
311
+
249
312
  ## License
250
313
 
251
314
  Apache License 2.0 — see [LICENSE](LICENSE) for details.
@@ -13,6 +13,7 @@ export { error } from './error.js';
13
13
  export type { DeclaredErrorDefinition, DeclaredErrorFamily } from './error.js';
14
14
  export { classIcon } from './class-icon.js';
15
15
  export type { ClassIcon } from './class-icon.js';
16
+ export type { StoredPropertyInputOf } from './property-input.js';
16
17
  export type { CallablePolicyBuilder, CallablePolicyContext, CallableProjection, AuthoredMethodProjection, AuthoredPropertyProjection, ClassIdentityProjection, ClassOwnerProjection, CoreEdge, CoreEndpoint, CoreNode, DefinedSchema, DirectedEdgeClass, ClassReferenceProjection, ClassProjection, FunctionProjection, EdgeClass, Function, Method, MethodProjection, Lazy, NodeClass, Policy, PolicyExistsContext, PolicyNodeBinder, PolicyPatternContext, Property, PropertyProjection, ResolvedDomainOfInput, View, } from '@astrale-os/kernel-dsl/v1/builder';
17
18
  export type { Array, Object, Value } from '@astrale-os/kernel-dsl/value';
18
19
  export type { ClassKind, DirectedEdgeContract, EdgeClassPolicies, NodeClassDefinition, PolicyCheckObject, PolicyObjectRef, PropertyFacet, StateTopology, UndirectedEdgeContract, } from '@astrale-os/kernel-dsl/v1/language';
@@ -0,0 +1,15 @@
1
+ import type { ResolvedPropertyCollection } from '@astrale-os/kernel-dsl/v1/language';
2
+ type StoredValueOf<Property> = Property extends {
3
+ readonly __value?: infer Value;
4
+ } ? Value : never;
5
+ /** Values already held by graph Properties, including a blob's Ref rather than its write receipt. */
6
+ export type StoredPropertyInputOf<Class> = Class extends {
7
+ readonly properties: infer Collection;
8
+ } ? Collection extends {
9
+ readonly byKey: infer ByKey;
10
+ } ? Readonly<{
11
+ [Key in keyof ByKey]?: StoredValueOf<ByKey[Key]>;
12
+ } & {
13
+ [Name in Exclude<keyof Collection, keyof ResolvedPropertyCollection>]?: StoredValueOf<Collection[Name]>;
14
+ }> : never : never;
15
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
1
  import type { Edge } from '../../platform/graph/edge/index.js';
2
2
  import type { Node, NodeId } from '../../platform/graph/node/index.js';
3
- import type { PropertyInputOf, ResolvedClass, schema } from '../../platform/schema/index.js';
3
+ import type { ResolvedClass, schema, StoredPropertyInputOf } from '../../platform/schema/index.js';
4
4
  import type { DatasetNode, DatasetReferences } from './dataset.js';
5
5
  import { type DatasetReferenceInput } from './references.js';
6
6
  /** Resolved Classes of the exact authored Schema, keyed by their authored names. */
@@ -10,11 +10,11 @@ export type DatasetEndpoint = Node | NodeId | string;
10
10
  export interface DatasetNodeInput<Class extends ResolvedClass<'node'>> {
11
11
  /** Stable identity within the Dataset; derived from the Class name and insertion order when omitted. */
12
12
  readonly id?: string;
13
- readonly props?: PropertyInputOf<Class>;
13
+ readonly props?: StoredPropertyInputOf<Class>;
14
14
  }
15
15
  export interface DatasetEdgeInput<Class extends ResolvedClass<'edge'>> {
16
16
  readonly slug?: string;
17
- readonly props?: PropertyInputOf<Class>;
17
+ readonly props?: StoredPropertyInputOf<Class>;
18
18
  }
19
19
  /** Graph authoring surface handed to one Dataset definition. Facts are canonical Kernel values. */
20
20
  export interface DatasetGraph<Schema extends schema.DomainSchema> {
@@ -1,3 +1,3 @@
1
- import type { DomainPolicy } from '../../policy/index.js';
1
+ import type { DomainLintIgnore, DomainPolicy } from '../../policy/index.js';
2
2
  import type { SourceProject } from './index.js';
3
- export declare function discoverProject(root: string, policy: DomainPolicy, signal?: AbortSignal): Promise<SourceProject>;
3
+ export declare function discoverProject(root: string, policy: DomainPolicy, signal?: AbortSignal, ignore?: DomainLintIgnore): Promise<SourceProject>;
@@ -25,7 +25,7 @@ const MAX_FILE_BYTES = 2 * 1024 * 1024;
25
25
  const MAX_TOTAL_BYTES = 128 * 1024 * 1024;
26
26
  const READ_CONCURRENCY = 32;
27
27
  const MAX_CONFIG_BYTES = 1024 * 1024;
28
- export async function discoverProject(root, policy, signal) {
28
+ export async function discoverProject(root, policy, signal, ignore) {
29
29
  ensureActive(signal);
30
30
  const requestedRoot = resolve(root);
31
31
  let projectRoot;
@@ -46,7 +46,7 @@ export async function discoverProject(root, policy, signal) {
46
46
  const layerPaths = policy.layers.map(({ sourcePath }) => sourcePath.replace(/\/$/, ''));
47
47
  const paths = [];
48
48
  try {
49
- await collect(projectRoot, projectRoot, paths, configuration.workspacePatterns, layerPaths, toolingPaths, 0, signal);
49
+ await collect(projectRoot, projectRoot, paths, configuration.workspacePatterns, layerPaths, toolingPaths, ignore, 0, signal);
50
50
  }
51
51
  catch (cause) {
52
52
  if (cause instanceof LinterToolError)
@@ -128,12 +128,19 @@ function digestField(hash, value) {
128
128
  hash.update(length);
129
129
  hash.update(value);
130
130
  }
131
- async function collect(root, directory, output, workspacePatterns, layerPaths, toolingPaths, depth, signal) {
131
+ async function collect(root, directory, output, workspacePatterns, layerPaths, toolingPaths, ignore, depth, signal) {
132
132
  ensureActive(signal);
133
133
  const entries = await readdir(directory, { withFileTypes: true });
134
134
  for (const entry of entries) {
135
135
  const path = join(directory, entry.name);
136
136
  const projectPath = normalize(relative(root, path));
137
+ if (entry.isDirectory() && entry.name === '.spec') {
138
+ invalidProject(`Domain projects cannot own .spec directories; Kernel is the specification owner (${projectPath}).`);
139
+ }
140
+ // Project-ignored paths are pruned before any read, so their contents are
141
+ // neither parsed, counted against admission limits, nor digested.
142
+ if (ignore?.matches(projectPath))
143
+ continue;
137
144
  if (entry.isSymbolicLink()) {
138
145
  if (!IGNORED.has(entry.name)) {
139
146
  invalidProject(`Domain compilation scope contains symbolic link ${relative(root, path)}.`);
@@ -141,16 +148,13 @@ async function collect(root, directory, output, workspacePatterns, layerPaths, t
141
148
  continue;
142
149
  }
143
150
  if (entry.isDirectory()) {
144
- if (entry.name === '.spec') {
145
- invalidProject(`Domain projects cannot own .spec directories; Kernel is the specification owner (${projectPath}).`);
146
- }
147
151
  if (!IGNORED.has(entry.name)) {
148
152
  if (await isWorkspaceMember(path, projectPath, workspacePatterns, layerPaths, signal))
149
153
  continue;
150
154
  if (depth >= MAX_DEPTH) {
151
155
  invalidProject(`Domain source tree exceeds maximum depth ${MAX_DEPTH} at ${path}.`);
152
156
  }
153
- await collect(root, path, output, workspacePatterns, layerPaths, toolingPaths, depth + 1, signal);
157
+ await collect(root, path, output, workspacePatterns, layerPaths, toolingPaths, ignore, depth + 1, signal);
154
158
  }
155
159
  continue;
156
160
  }
@@ -86,7 +86,7 @@ export const globalRules = [
86
86
  return production(project).flatMap((file) => {
87
87
  if (file.layer || governedRoots.has(file.path))
88
88
  return [];
89
- const evidence = `Production source ${file.path} is outside every declared layer and governed root.`;
89
+ const evidence = `Production source ${file.path} is outside every declared layer and governed root. Move Domain source into a declared layer; exclude a directory that is not Domain source, such as mockups, with an "ignore" glob in astrale.lint.json.`;
90
90
  const anchor = file.source.statements[0];
91
91
  return anchor ? [violation(file, anchor, evidence)] : [{ kind: 'violation', evidence }];
92
92
  });
@@ -21,11 +21,11 @@ async function lintAstraleDomain(options) {
21
21
  }), { disabledRuleIds: configured.disabled.map(({ ruleId }) => ruleId) });
22
22
  evaluation.assertAvailable(options.requiredRuleIds ?? []);
23
23
  await assertSingleTypeUniverse(root, options.signal);
24
- const project = await discoverProject(root, policy, options.signal);
24
+ const project = await discoverProject(root, policy, options.signal, configured.ignore);
25
25
  const evaluated = await evaluation.evaluate(project, options.signal);
26
26
  const suppression = applySuppressions(collectSuppressionDirectives(project), evaluated.diagnostics);
27
27
  const diagnostics = sortDiagnostics(suppression.diagnostics);
28
- return {
28
+ const result = {
29
29
  root: project.root,
30
30
  policyDigest: policy.digest,
31
31
  sourceSnapshotDigest: project.sourceSnapshotDigest,
@@ -41,6 +41,7 @@ async function lintAstraleDomain(options) {
41
41
  ? 1
42
42
  : 0,
43
43
  };
44
+ return { result, ignorePatterns: configured.ignore.patterns };
44
45
  }
45
46
  function ensureActive(signal) {
46
47
  if (signal?.aborted) {
@@ -52,10 +53,10 @@ function ensureActive(signal) {
52
53
  }
53
54
  export async function lintDomain(options = {}) {
54
55
  const started = performance.now();
55
- const domain = await lintAstraleDomain(options);
56
+ const { result: domain, ignorePatterns } = await lintAstraleDomain(options);
56
57
  if (options.generic === false)
57
58
  return domain;
58
- const generic = await runOxlint(domain.root, options.fix ?? false, { signal: options.signal });
59
+ const generic = await runOxlint(domain.root, options.fix ?? false, { signal: options.signal }, ignorePatterns);
59
60
  const diagnostics = sortDiagnostics([...domain.diagnostics, ...generic.diagnostics]);
60
61
  return {
61
62
  ...domain,
@@ -4,4 +4,4 @@ export interface OxlintResult {
4
4
  readonly diagnostics: readonly LintDiagnostic[];
5
5
  readonly files: number;
6
6
  }
7
- export declare function runOxlint(root: string, fix: boolean, options?: OxlintProcessOptions): Promise<OxlintResult>;
7
+ export declare function runOxlint(root: string, fix: boolean, options?: OxlintProcessOptions, projectIgnorePatterns?: readonly string[]): Promise<OxlintResult>;
@@ -7,7 +7,7 @@ import { DOMAIN_OXLINT_IGNORE_PATTERNS } from '../oxlint-config/index.js';
7
7
  import { runOxlintProcess } from './process.js';
8
8
  const MAX_DIAGNOSTICS = 100_000;
9
9
  const MAX_LABELS = 256;
10
- export async function runOxlint(root, fix, options = {}) {
10
+ export async function runOxlint(root, fix, options = {}, projectIgnorePatterns = []) {
11
11
  const packageJson = join(root, 'package.json');
12
12
  const projectRequire = createRequire(packageJson);
13
13
  const sdkRequire = createRequire(import.meta.url);
@@ -20,6 +20,10 @@ export async function runOxlint(root, fix, options = {}) {
20
20
  // fallback config and imported presets cannot discover dependency/build trees.
21
21
  for (const pattern of DOMAIN_OXLINT_IGNORE_PATTERNS)
22
22
  args.push('--ignore-pattern', pattern);
23
+ // Domain `ignore` globs are root-relative; the leading slash anchors them the
24
+ // same way under Oxlint's gitignore semantics.
25
+ for (const pattern of projectIgnorePatterns)
26
+ args.push('--ignore-pattern', `/${pattern}`);
23
27
  if (fix)
24
28
  args.push('--fix');
25
29
  const { status, signal, stdout, stderr } = await runOxlintProcess(bin, args, root, options);
@@ -1,4 +1,5 @@
1
1
  import type { DomainPolicy, DomainPolicySource } from './index.js';
2
+ import { type DomainLintIgnore } from './ignore.js';
2
3
  export declare const DOMAIN_LINT_CONFIG = "astrale.lint.json";
3
4
  export interface DomainLintLayerConfiguration {
4
5
  readonly sourcePath?: string;
@@ -7,6 +8,7 @@ export interface DomainLintLayerConfiguration {
7
8
  export interface DomainLintConfiguration {
8
9
  readonly layers?: Readonly<Record<string, DomainLintLayerConfiguration>>;
9
10
  readonly disabledRules?: Readonly<Record<string, string>>;
11
+ readonly ignore?: readonly string[];
10
12
  }
11
13
  export interface DisabledRule {
12
14
  readonly ruleId: string;
@@ -15,6 +17,7 @@ export interface DisabledRule {
15
17
  export interface ProjectDomainLint {
16
18
  readonly policy: DomainPolicy;
17
19
  readonly disabled: readonly DisabledRule[];
20
+ readonly ignore: DomainLintIgnore;
18
21
  }
19
22
  export declare function compileProjectDomainPolicy(root: string, signal?: AbortSignal): Promise<DomainPolicy>;
20
23
  export declare function compileProjectDomainLint(root: string, signal?: AbortSignal): Promise<ProjectDomainLint>;
@@ -3,6 +3,7 @@ import { join } from 'node:path';
3
3
  import { LinterToolError } from '../diagnostics/index.js';
4
4
  import { compileDomainPolicy } from './compile.js';
5
5
  import { domainPolicySource } from './generated.js';
6
+ import { admitIgnorePatterns } from './ignore.js';
6
7
  export const DOMAIN_LINT_CONFIG = 'astrale.lint.json';
7
8
  const MAX_CONFIG_BYTES = 64 * 1024;
8
9
  const MAX_REASON_BYTES = 240;
@@ -17,6 +18,7 @@ export async function compileProjectDomainLint(root, signal) {
17
18
  return Object.freeze({
18
19
  policy,
19
20
  disabled: admitDisabledRules(policy, configuration.disabledRules ?? {}),
21
+ ignore: admitIgnorePatterns(policy, configuration.ignore),
20
22
  });
21
23
  }
22
24
  export function configureDomainPolicySource(source, configuration) {
@@ -101,7 +103,7 @@ async function readDomainLintConfiguration(root, signal) {
101
103
  }
102
104
  if (!record(value))
103
105
  invalid('Domain lint configuration must be an object.');
104
- const unknown = Object.keys(value).filter((field) => field !== 'layers' && field !== 'disabledRules');
106
+ const unknown = Object.keys(value).filter((field) => field !== 'layers' && field !== 'disabledRules' && field !== 'ignore');
105
107
  if (unknown.length > 0) {
106
108
  invalid(`Domain lint configuration has unknown fields: ${unknown.join(', ')}.`);
107
109
  }
@@ -0,0 +1,11 @@
1
+ import type { DomainPolicy } from './index.js';
2
+ /**
3
+ * Project-relative paths excluded from Domain source admission. A matched directory is never
4
+ * traversed, so nothing below it is read, parsed, counted, or digested.
5
+ */
6
+ export interface DomainLintIgnore {
7
+ readonly patterns: readonly string[];
8
+ matches(path: string): boolean;
9
+ }
10
+ export declare const noDomainLintIgnore: DomainLintIgnore;
11
+ export declare function admitIgnorePatterns(policy: DomainPolicy, input: unknown): DomainLintIgnore;
@@ -0,0 +1,101 @@
1
+ import { LinterToolError } from '../diagnostics/index.js';
2
+ const MAX_PATTERNS = 64;
3
+ const MAX_PATTERN_LENGTH = 512;
4
+ const UNSUPPORTED = /[\\[\]{}!]/;
5
+ export const noDomainLintIgnore = Object.freeze({
6
+ patterns: Object.freeze([]),
7
+ matches: () => false,
8
+ });
9
+ export function admitIgnorePatterns(policy, input) {
10
+ if (input === undefined)
11
+ return noDomainLintIgnore;
12
+ if (!Array.isArray(input))
13
+ invalid('Domain lint configuration ignore must be an array.');
14
+ if (input.length > MAX_PATTERNS) {
15
+ invalid(`Domain lint configuration ignore has more than ${MAX_PATTERNS} patterns.`);
16
+ }
17
+ const governed = new Map([
18
+ ...policy.layers.map(({ id, sourcePath }) => [
19
+ sourcePath.replace(/\/$/, ''),
20
+ `declared layer ${id} (${sourcePath})`,
21
+ ]),
22
+ ...policy.rootFiles.map(({ sourcePath }) => [
23
+ sourcePath,
24
+ `governed root file ${sourcePath}`,
25
+ ]),
26
+ ]);
27
+ const patterns = [];
28
+ const expressions = [];
29
+ for (const value of input) {
30
+ if (typeof value !== 'string')
31
+ invalid('Domain lint ignore patterns must be strings.');
32
+ const segments = segmentsOf(value);
33
+ const owner = governed.get(segments[0]);
34
+ if (owner) {
35
+ invalid(`Domain lint ignore pattern ${JSON.stringify(value)} would exclude ${owner}; ignore only paths outside the Domain layout.`);
36
+ }
37
+ if (!patterns.includes(value)) {
38
+ patterns.push(value);
39
+ expressions.push(compile(segments));
40
+ }
41
+ }
42
+ if (patterns.length === 0)
43
+ return noDomainLintIgnore;
44
+ return Object.freeze({
45
+ patterns: Object.freeze(patterns),
46
+ matches: (path) => {
47
+ // A matched directory excludes everything below it.
48
+ const segments = path.split('/');
49
+ return segments.some((_, index) => {
50
+ const prefix = segments.slice(0, index + 1).join('/');
51
+ return expressions.some((expression) => expression.test(prefix));
52
+ });
53
+ },
54
+ });
55
+ }
56
+ function segmentsOf(pattern) {
57
+ const reject = (reason) => invalid(`Domain lint ignore pattern ${JSON.stringify(pattern)} ${reason}.`);
58
+ if (pattern.length === 0 || pattern.length > MAX_PATTERN_LENGTH) {
59
+ reject(`must contain 1-${MAX_PATTERN_LENGTH} characters`);
60
+ }
61
+ if (pattern.trim() !== pattern)
62
+ reject('must not start or end with whitespace');
63
+ if (pattern.startsWith('/'))
64
+ reject('must be relative to the Domain root');
65
+ if (UNSUPPORTED.test(pattern))
66
+ reject("may only use '*', '**', and '?' wildcards");
67
+ const segments = pattern.replace(/\/$/, '').split('/');
68
+ if (segments.some((segment) => segment === '' || segment === '.' || segment === '..')) {
69
+ reject("must not contain empty, '.', or '..' segments");
70
+ }
71
+ if (segments.some((segment) => segment.includes('**') && segment !== '**')) {
72
+ reject("must use '**' as a whole path segment");
73
+ }
74
+ if (/[*?]/.test(segments[0])) {
75
+ reject('must start with a literal root entry, such as mockups/**');
76
+ }
77
+ return segments;
78
+ }
79
+ /** `*` and `?` stay within one segment; `**` spans zero or more segments. */
80
+ function compile(segments) {
81
+ let source = '';
82
+ for (const [index, segment] of segments.entries()) {
83
+ if (segment === '**') {
84
+ source += '(?:/[^/]+)*';
85
+ continue;
86
+ }
87
+ const literal = segment
88
+ .split('')
89
+ .map((character) => character === '*'
90
+ ? '[^/]*'
91
+ : character === '?'
92
+ ? '[^/]'
93
+ : character.replace(/[|\\{}()[\]^$+.]/g, '\\$&'))
94
+ .join('');
95
+ source += index === 0 ? literal : `/${literal}`;
96
+ }
97
+ return new RegExp(`^${source}$`);
98
+ }
99
+ function invalid(message) {
100
+ throw new LinterToolError(message, { code: 'LINTER_PROJECT_INVALID' });
101
+ }
@@ -1,6 +1,7 @@
1
1
  export { compileDomainPolicy } from './compile.js';
2
2
  export { compileProjectDomainLint, compileProjectDomainPolicy, configureDomainPolicySource, DOMAIN_LINT_CONFIG, } from './configuration.js';
3
3
  export { domainPolicyDigest, domainPolicySource } from './generated.js';
4
+ export type { DomainLintIgnore } from './ignore.js';
4
5
  import type { RuleCatalog } from '../catalog/index.js';
5
6
  export type { DisabledRule, DomainLintConfiguration, DomainLintLayerConfiguration, ProjectDomainLint, } from './configuration.js';
6
7
  export interface DomainLayerPolicy {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.6.0-beta.1",
3
+ "version": "0.6.0-beta.3",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",
@@ -237,11 +237,11 @@
237
237
  "registry": "https://registry.npmjs.org/"
238
238
  },
239
239
  "dependencies": {
240
- "@astrale-os/kernel-client": "0.6.0-beta.71",
241
- "@astrale-os/kernel-core": "0.9.0-beta.54",
242
- "@astrale-os/kernel-dsl": "0.2.0-beta.39",
243
- "@astrale-os/kernel-protocol": "0.5.0-beta.60",
244
- "@astrale-os/kernel-server": "0.5.0-beta.62",
240
+ "@astrale-os/kernel-client": "0.6.0-beta.77",
241
+ "@astrale-os/kernel-core": "0.9.0-beta.57",
242
+ "@astrale-os/kernel-dsl": "0.2.0-beta.41",
243
+ "@astrale-os/kernel-protocol": "0.5.0-beta.63",
244
+ "@astrale-os/kernel-server": "0.5.0-beta.65",
245
245
  "@lucide/icons": "1.34.0",
246
246
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
247
247
  "cross-spawn": "7.0.6",