@astrale-domains/shell

中文文档
0.2.0发布于 2026/11/07Apache-2.0TypeScriptES Module近 30 天下载 4514

Astrale Shell Domain schema and remote product implementation

原始使用文档
文档目录9 节
  1. Contracts
  2. Settings
  3. Invitation
  4. Release
  5. View access
  6. Namespaces and aliases
  7. Versions
  8. Source and qualification
  9. Publication boundary

Shell Domain

Shell owns the account of each person (User), their groups (Group), its Roles (Role: the profiles workspace.member ⊂ workspace.admin and the atomic user.reader, user.writer, group.reader, group.writer, directory.provisioner), the Views an account without a profile lands on (view_access), the instance Namespaces and their aliases, and one application View, its entrypoint. All authority comes from Kernel Roles, held directly or through groups by Kernel extends_with; a directory may provide accounts and groups. The design, its laws and its amendments are in docs/design/accounts-and-roles.md; each law's enforcement and test are in docs/accounts/laws.tsv, each scenario's evidence in docs/accounts/scenarios.tsv.

The model before Roles is kept for its callers under legacy/ folders, listed in legacy/LEDGER.md by the method of docs/legacy.md; it is described in docs/legacy/shell-domain-before-roles.md.

Contracts

MethodCalled onAdmittedInputOutput
User.createstaticuser.writer{ email, name, givenName?, familyName?, attributes? }{ user, created }
User.invitestaticuser.writer{ user, profile?: 'member' | 'admin' }{ invitationId, user, state }
User.updatethe accountuser.writer{ name?, email?, givenName?, familyName?, icon?, attributes? }{}
User.updateProfilethe accountits holder{ name?, icon? }{}
User.saveSettingsthe accountthe account itself only{ set?, unset? }{ settings }
User.deactivate, User.reactivate, User.deletethe accountuser.writer{}{}
User.provisionstaticdirectory.provisioner{ directory, externalId, email, name, givenName?, familyName?, active }{ user, created, adopted }
User.deprovisionstaticdirectory.provisioner{ directory, externalId }{}
Group.createstaticgroup.writer{ name, description?, icon?, attributes? }{ group }
Group.update, Group.deletethe groupgroup.writer{ name?, description?, icon?, attributes? }, {}{}
Group.assignMember, Group.unassignMemberstaticgroup.writer, directory.provisioner{ member, group } (@NodeId paths){}
Group.provisionstaticdirectory.provisioner{ directory, externalId, name }{ group, created }
Group.deprovisionstaticdirectory.provisioner{ directory, externalId }{}
disconnectDirectoryfunctiondirectory.provisioner{ directory }{ users, groups }
WorkspaceSettings.save/:shell.astrale.ai:core.settingsworkspace.admin{ set?, unset? }{ settings }

Refusals (reason.code, family): USER_EMAIL_INVALID (VALIDATION_ERROR); USER_NOT_FOUND, GROUP_NOT_FOUND (NOT_FOUND); USER_EMAIL_TAKEN, USER_DIRECTORY_MANAGED, USER_ADMINISTRATOR_PROTECTED, USER_LAST_ADMINISTRATOR, USER_ACTIVE, USER_SUSPENDED, PROFILE_NOT_HELD, GROUP_DIRECTORY_MANAGED, GROUP_NOT_DIRECTORY_MANAGED, GROUP_ROLE_PROTECTED (details { role }), GROUP_MEMBERSHIP_CYCLE, DIRECTORY_CONFLICT (details { user }), ACCOUNT_CHANGED, GROUP_CHANGED (CONFLICT); the membership methods keep INVALID_GROUP_MEMBERSHIP_REFERENCE, GROUP_MEMBERSHIP_ENDPOINTS_UNAVAILABLE, GROUP_MEMBERSHIP_CONFLICT, GROUP_MEMBERSHIP_UNCONFIRMED, and invite INVITATION_CONFLICT, INVITATION_REJECTED, and the settings methods SETTINGS_TOO_MANY, SETTINGS_NAME_REPEATED (VALIDATION_ERROR), SETTINGS_NOT_FOUND (NOT_FOUND), SETTINGS_CHANGED (CONFLICT). The SDK has no FORBIDDEN business family: a law that forbids a change for the state of an account, a group or its caller answers CONFLICT.

User and Group declare no write rule: only their methods write them, with Shell's authority, after the laws the Kernel cannot state (U1–U6, G2–G4). A Domain that needs accounts asks user.writer (and user.reader) in its release for itself, requirements({ roles: [{ role: S.core.nodes['user.writer'], members: [requirements.domain] }] }), links its record to the account by an Edge of its own, and tests its own Roles with its own hasRole Policy. Every write keeps frozen = suspended or directoryActive === false (U2): the Kernel refuses to authenticate a frozen account.

Settings

Settings are one JSON object of at most 64 names, which the applications choose and validate themselves (the GUI stores dock, wallpaper, appearance, locale…): a new setting needs no Shell release. UserSettings holds one person's own, linked to its account by user_settings and created at its first change; only the account itself reads and writes them, no Role reads another person's, and they are deleted with the account. WorkspaceSettings, the one Core Node /:shell.astrale.ai:core.settings, holds the workspace's defaults and customization: everyone reads it, an administrator saves it. A change merges into the stored object: set writes names, unset takes them off, on the revision it was read at; when another window wrote first, Shell reads and merges again, so neither erases the other.

Invitation

User.invite grants the profile (extends_with to profile.<name>), then asks Admin to send the invitation through Shell's enrollment Integration, which carries { user, email, profile, requestId, requestedBy }: the email is the account's own. Its Provider mints an invocation-bound Shell proof for its configured HTTPS ingress audience. A returned pending invitation does not prove email delivery or completed registration. Admin binds the first sign-in of the verified email to the account (U8).

Release

domain.ts declares Roles and scopes. workspace.admin grants every Shell Role and the grantable Kernel Roles (R2); the bundle member ⊂ admin and the atomic Roles are release members (AM1); member holds Kernel writer, admin Kernel admin; no profile holds Kernel reader, which admin grants to whoever only opens its Views (AM10); Shell itself holds Kernel authority.reader, graph.reader and graph.writer. Installing it requires an installer that grants every Role it binds: Root.

View access

A View given to an Identity decides where it lands, never what it reads. view_access runs from any Identity — an account, a group, a Role — to one Kernel View; each end detaches with its Node. An admin writes it by a Mutation; an admin, or the Edge's audience and its members, read it. A visitor's landing is its own Query (@astrale-os/shell): workspace.member opens the workspace; anyone else, reading with Kernel reader, the Views it holds.

Namespaces and aliases

An alias names a Node. It grants nothing. A name designates at most one Node in its Namespace, for every author: alias declares the Kernel key unique: [['source', 'slug']] in its first release, so the Kernel refuses a taken name on the final state of any Mutation, Shell's or an administrator's own mutate. Edge identity gives a Node at most one alias per Namespace. An alias is a Path, /:shell.astrale.ai:core.views~"shell.astrale.ai:class.alias"(roadmap), and reaches its Node only for a reader who may read that Node. Its target endpoint accepts any Node, a Class Shell does not own, so the alias detaches when its Node is deleted; the Namespace stays.

The Core Namespace views holds the names opened at /v/<name>. Namespace and alias declare read: true and traverse: true: a reader lists and follows the aliases whose Node it may read, and an alias toward any other Node does not exist for it. Shell, through its own alias Edges, finds the Node of every name, even one it does not read.

link names any Node its target Path reaches, whatever Domain owns it: an alias grants nothing, and each reader sees only the aliases toward Nodes it may read. Offering only Nodes the administrator sees is the interface's courtesy, not a server guarantee; any writer already learns from a Mutation's locator whether a Path reaches a Node.

MethodCallsRefusals
linkOne Mutation with Shell's authority; its locator resolves targetINVALID_NAME, TARGET_NOT_FOUND, NAME_TAKEN, TARGET_ALREADY_ALIASED
unlinkOne read of the alias Path with Shell's authority, then one MutationINVALID_NAME, NAME_NOT_FOUND
renameSame; renaming a name to itself writes nothingINVALID_NAME, NAME_NOT_FOUND, NAME_TAKEN

A name is an Edge slug in lower case (INVALID_NAME). That rule is Shell's: an administrator writing through mutate bypasses it, never the key. Nothing guards a name's uniqueness but the key. unlink and rename change the alias only while it still carries the name they read, so a concurrent rename answers NAME_NOT_FOUND instead of changing another name. Shell maps the Kernel's sealed refusals:

Kernel refusal of the Mutationlinkunlinkrename
MUTATION_POST_STATE_INVALID, rule duplicate-keyNAME_TAKENpropagatesNAME_TAKEN
MUTATION_PRECONDITION_FAILED (the alias Edge exists, is gone, or carries another name)TARGET_ALREADY_ALIASEDNAME_NOT_FOUNDNAME_NOT_FOUND
MUTATION_LOCATOR_INVALID (the target Path reaches no Node, or the target was deleted)TARGET_NOT_FOUNDNAME_NOT_FOUNDNAME_NOT_FOUND

Every other failure propagates. workspace.admin holders call the three methods, and write alias Edges by their own Mutations too.

Versions

The Domain's version is the version of domain/package.json, which Release Please writes; it also writes it to the root package.json, the Project's, which astrale-domain publish reads. One number names the npm package @astrale-domains/shell and the registry Publication shell.astrale.ai@<version>, so an instance installs a published release by number:

astrale domain install shell.astrale.ai@<version> -i <instance> --as <instance>-root

shell.astrale.ai@<major>.<minor> installs the highest stable version of that line. The Domain releases stable versions from 0.1.1 on; 0.1.0, the first Publication, names the 0.1.0-beta.51 release.

Source and qualification

Each declaration, Query and Mutation has its own semantic file. Layer roots are facades; functions own orchestration, integrations/providers own external effects, views/ui own the directory surface. Runtime has one default export and binds every handler. The Dataset is referenced lazily by the root astrale.config.ts.

Domain authors import Schema from @astrale-domains/shell; platform workers use the explicit /domain and /runtime exports. Creation/registration, installation authority, invitation delivery, runtime replay and browser rendering are separate qualification boundaries. The redesigned Admin composition, published Register cohort and real invitation/instance-create journeys remain release gates; this source README is not evidence that those gates passed.

Publication boundary

@astrale-domains/shell is an executable platform package and a deliberate exception to the normal Domain publication product. It publishes the remote Shell Domain definition and runtime needed by platform Worker deployments through the explicit ./domain and ./runtime subpaths, while its root remains Schema-only. Its build therefore compiles the explicit roots in tsconfig.package.json and applies Shell-owned normalization and checks to the emitted platform closure. Source-only # aliases are rewritten to relative JS and declaration references so consumer path mappings cannot capture private Shell types. Tarball qualification then verifies the exact exports, isolated subpaths, absence of source maps, and an install using only public npm dependencies.

The generic astrale-domain package command remains Schema-only and exposes only the Domain root plus package metadata. This Shell exception must not be copied to ordinary product Domains or used to weaken that SDK contract. Deployment consumers must use the explicit executable subpaths so a linked schema import cannot traverse Shell's private application or runtime implementation.

Source, package, and deterministic test qualification remain distinct from installed-instance, released-package, browser, and live-credential evidence. Shell does not broker authentication tokens; standard Domain token exchange is owned by Protocol, Server, and SDK.

版本与发布记录

@astrale-domains/shell 共发布 57 个版本,首次发布于 2026/08/22;过去 12 个月发布了 57 个版本。

版本发布日期距今
0.2.0latest2026/11/07今天
0.1.112026/11/07今天
0.1.102026/11/07今天
0.1.92026/11/071 天前
0.1.82026/11/071 天前
0.1.72026/11/061 天前

其他发布通道:beta → 0.1.0-beta.51。

关于 @astrale-domains/shell 的常见问题

@astrale-domains/shell 是什么?

Astrale Shell Domain schema and remote product implementation

如何安装 @astrale-domains/shell?

在项目目录运行 npm install @astrale-domains/shell,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@astrale-os/sdk(>=0.6.0-beta.60 <1.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@astrale-domains/shell 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@astrale-domains/shell 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@astrale-domains/shell 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@astrale-domains/shell 可以商用吗?

@astrale-domains/shell 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@astrale-domains/shell 的下载量有多少?

根据 npm 官方下载统计,@astrale-domains/shell 在 2026/10/07 – 2026/11/05 这 30 天内被下载 4,514 次,日均约 150 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@astrale-domains/shell 还在维护吗?

最新版本 0.2.0 发布于 2026/11/07(今天);至今共发布 57 个版本,其中过去 12 个月发布了 57 个;首次发布于 2026/08/22。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。