@hanamesh/dsh-app-host 0.6.18 → 0.6.21

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.
@@ -1,5 +1,21 @@
1
1
  # 客户端市场安装目标入口
2
2
 
3
+ ## 0.6.21 候选 · 固定 GitHub 安装目标
4
+
5
+ 目标新增 `installTarget`,采用 C-INDEXER-CATALOG 已确认的两个形状:
6
+
7
+ ```ts
8
+ type PackageInstallTarget =
9
+ | {source:'npm';name:string;version:string;allowBuild:string[]}
10
+ | {source:'github';repo:string;ref:string;path:string|null;packageName:string;allowBuild:string[]};
11
+ ```
12
+
13
+ GitHub ref 必须是收录时固定的完整 40 位 SHA,不在安装时解析分支。结构化目标必须带 itemId;App-host 从自己的启用目录 installMethods 解析并逐字段核对,整个条目 oneClickInstall.allowed=false 时拒绝,不能换用同名 npm 包。条目带 installMethods 而未选中匹配目标时,返回 NOT_INSTALLABLE / details.reason=fixed-install-target-required,不得退回 package 展示名去装 npm latest;只有未提供 installMethods 的条目保留原标准 npm 路径。HanaMesh 视图拒绝退休的 latestVersion/license,确认页不显示版本行,升级按钮不拼目录版本;npm 升级按 installTarget.version 与已装实际版本比较。GET target/导航片段将 installTarget JSON 编码;POST install/网站 handoff 使用对象。响应 item.installTarget 是客户端确认回传的预期目标。目录 SHA、路径或构建许可变化会拒绝 CATALOG_CHANGED,必须重新查看;不能在确认之后自动换目标。
14
+
15
+ 确认沿现有市场表面,展示完整仓库、commit、子目录;allowBuild 非空时单列「会在本机执行构建脚本」和名单,并说明 pnpm 会保存许可。取消或预览不执行 CLI。本人确认后,仅调用原受控 `dsh plugin --profile <profile> add --save-exact [--allow-build=<项>…] github:owner/repo#<SHA>[&path:<目录>]`,每段都是独立 argv,不执行来源 command。npm 目标直接使用收录时固定的精确版本,不在安装时再解析版本。
16
+
17
+ GitHub CLI exit 0 后还须核对 profile 精确保存的 Git spec、模块包名/版本、dsh.bundle 和 profile 启用列表,随后报告 restart-required;重开后由原生 DSH 加载。不自行 clone/build,不改上游,不用进程内安装器。失败补偿沿原 CLI;pnpm-workspace.yaml 若发生变化,恢复报告保留 build-permissions 残留及原文件,不擅自撤销或静默宣称恢复。handoff 事件按完整目标匹配,不能只靠同名包把另一个 SHA 报为成功。
18
+
3
19
  网站发现:DSH 本地路由与交接监听的 `/hanamesh/library/install-target` 都按当前 `library.handoff.allowedOrigins` 回答跨来源 GET / OPTIONS;只回显获准 Origin(Vary: Origin),不使用通配 CORS。未获准来源为 403 ORIGIN_DENIED,正文无客户端能力。正常工作区同源读取、无 Origin 的本机工具读取保留。其余安装/状态路由继续需要各自认证与确认。
4
20
 
5
21
  轮询设置:`pollMs` 写入应用库真实 storage domain;保存、卸载再加载后保持。旧记录没有该字段时使用既有配置/默认 1500 ms,不重写其它存储数据。
@@ -14,7 +30,7 @@ AppHost `0.2.0-rc.10`(安装目标入口自 rc7;合约声明与随包套件
14
30
 
15
31
  在 DSH 的正常客户端模块系统中取得 `@hanamesh/dsh-app-host` 的公开客户端模块,调用 `openInstallTarget({itemId?, packageName?})`。已有客户端 `market` service 也提供同名方法:`market.openInstallTarget(target)`;原 `market.render({preferredSubsectionId})` 与 `setSettingsVisible()` 保持原协议。
16
32
 
17
- 至少一个标识;两者都给时必须匹配同一条目录项。拒绝所有其他字段,包括 version、url、downloadUrl。itemId 最长 160 字符;packageName 按 npm 包名语法校验、最长 214 字符。壳不得解析目录、代填版本/下载地址、点击私有 DOM、注入脚本、代按确认或访问组件状态。
33
+ 至少一个标识;两者都给时必须匹配同一条目录项。可选 installTarget 仅为上述目录目标的预期值;其它字段(包括顶层 version、url、downloadUrl)拒绝。itemId 最长 160 字符;packageName 按 npm 包名语法校验、最长 214 字符。壳不得解析目录、代填版本/下载地址、点击私有 DOM、注入脚本、代按确认或访问组件状态。
18
34
 
19
35
  入口先显现 AppHost 自己的侧栏市场覆盖层。若宿主已用 market 席位拥有市场表面(setSettingsVisible(false)),调用方需选中/呈现现有 market.render() 表面,AppHost 不叠加第二个覆盖层。即使尚未挂载,目标确认也保存在本客户端模块内,正常挂载后读回;不跨 profile 保存。
20
36
 
@@ -22,7 +38,7 @@ Promise 在目录解析后返回 `{status,itemId?,packageName?}`:
22
38
 
23
39
  | status | 意义 |
24
40
  | --- | --- |
25
- | confirmation-required | 市场已按当前目录显示名称、包名、版本和目录来源;尚未安装 |
41
+ | confirmation-required | 市场已按当前目录显示名称、包名和目录来源;结构化 GitHub 目标另显示完整 SHA/子目录;尚未安装 |
26
42
  | installing | 相同目录项已有安装进行中,复用该状态 |
27
43
  | already-installed | 当前 profile 已安装且目录没有升级,不重复安装 |
28
44
  | superseded | 解析过程中收到更新目标或取消,旧输入不再打开确认 |
@@ -31,9 +47,9 @@ Promise 在目录解析后返回 `{status,itemId?,packageName?}`:
31
47
 
32
48
  ## HTTP 契约
33
49
 
34
- 新增只读 `GET /hanamesh/library/target?itemId=...&packageName=...`,查询字段仍只接受上述两个标识。宿主用当前市场目录逐页解析,返回 `{item,source,traceId}`;item 含 kind、installed、upgradeAvailable 和原目录元数据,source 含市场自己的 manifestUrl;fixture 来源明确标「测试目录」。查询不会安装。
50
+ 只读 `GET /hanamesh/library/target?itemId=...&packageName=...` 接受两个标识及可选 JSON 编码 installTarget。宿主用当前市场目录逐页解析,返回 `{item,source,traceId}`;item 含 kind、installed、upgradeAvailable、选定 installTarget 和原目录元数据,source 含市场自己的 manifestUrl;fixture 来源明确标「测试目录」。查询不会安装。
35
51
 
36
- 同实例同端口的精确 `127.0.0.1:<port>` 与 `localhost:<port>` Host 同时可用(同一 parentOrigin 配置,无切换)。Origin 若出现必须与本次请求 Host 的 http origin 精确一致;两个别名仍是不同的浏览器 origin,不允许跨别名请求。未知 Host、其他端口、IPv6/尾点别名、外来或 opaque Origin 明确拒绝;非 iframe、authenticate、authorize 检查保持。GET 允许同源浏览器默认不带 Origin;不接受外来 Origin。实际安装只用原 `POST /hanamesh/library/install`,要求精确同源 Origin、`X-HanaMesh-Client: workspace-v1`、资源端身份及授权;重新解析当前目录,不信任请求内版本或地址。进行中返回原 `202 {operationId,status:'started'}`;相同包共享该 operationId。已经安装且没有目录升级时返回 `200 {status:'already-installed',itemId,packageName}`。安装事件/结果与既有安装器不改。目录版本是原目录 latestVersion,既有安装器仍自行核 registry 的 latest 并固定精确版本;最终显示的已安装版本来自 profile 扫描,并与操作结果版本一致才报告读回成功。
52
+ 同实例同端口的精确 `127.0.0.1:<port>` 与 `localhost:<port>` Host 同时可用(同一 parentOrigin 配置,无切换)。Origin 若出现必须与本次请求 Host 的 http origin 精确一致;两个别名仍是不同的浏览器 origin,不允许跨别名请求。未知 Host、其他端口、IPv6/尾点别名、外来或 opaque Origin 明确拒绝;非 iframe、authenticate、authorize 检查保持。GET 允许同源浏览器默认不带 Origin;不接受外来 Origin。实际安装只用原 `POST /hanamesh/library/install`,要求精确同源 Origin、`X-HanaMesh-Client: workspace-v1`、资源端身份及授权;重新解析当前目录,不信任请求内版本或地址。进行中返回原 `202 {operationId,status:'started'}`;相同包且相同结构化目标共享该 operationId,目标不同拒绝 CATALOG_CHANGED。已经安装且没有目录升级时返回 `200 {status:'already-installed',itemId,packageName}`。安装事件/结果与既有安装器不改。结构化 npm 来源只执行收录时固定的精确版本;GitHub 只执行已确认的 SHA。最终已安装版本来自 profile 扫描,GitHub 还须读回精确来源与启用项,均与操作结果一致才报告读回成功。
37
53
 
38
54
  ## 合约版本与一致性套件
39
55
 
package/docs/LIBRARY.md CHANGED
@@ -43,7 +43,7 @@ rc.10:add 之后的读回、定义校验或 provision 失败按基线补偿(
43
43
  ## rc.28 · 市场浏览语义
44
44
 
45
45
  - 市场页默认 `category=`(全部);筛选:全部 / 应用(`hanamesh-app`)/ 插件(客户端视图:本页非应用的 npm 条目)/ 目录页里出现过的类别(累积自 `categories`)。路由 `/hanamesh/library` 的缺省 `category=hanamesh-app` 不变(向后兼容)。
46
- - 卡片:`kind · 发布者 · latestVersion · 类别`;已装行显示状态与版本;「升级到 x.y.z」出现在 `upgradeAvailable` 时;插件「卸载」走 `plugins/uninstall`。页面底部「已安装」列出应用与插件(含 bundle 未启用为 profile 层的提示)。
46
+ - 卡片:`kind · 发布者 · 类别`;已装行显示实际状态与版本;「升级」出现在 `upgradeAvailable` 时,npm 仅按 Indexer 固定 target.version 比较;确认页不显示目录版本;插件「卸载」走 `plugins/uninstall`。页面底部「已安装」列出应用与插件(含 bundle 未启用为 profile 层的提示)。
47
47
  - 「需重新打开客户端」横幅:任一装卸操作完成后,或列表 `restartRequired` 为真时显示;所有渠道均提示完全退出 HanaMesh 客户端或 DSH 后重新打开,关闭窗口不等于退出。不提供旧壳深链或 postMessage 重启桥;只有正式宿主重启 API 供给后才另行接入。
48
48
 
49
49
  ### 0.3.0 · catalog major compatibility
@@ -94,3 +94,5 @@ HanaMesh 视图原样保留可选 `official:boolean`(包括 false)与 C-INDE
94
94
  原生 lookup 异常包为 `REGISTRY_LOOKUP_FAILED`,原 Error 保留于 cause;已知具名码保留。`library.*-failed.details.diagnostic` 最多4001字符,含脱敏异常类型/消息/cause.code 与实际 registry configuration/fetch/readback、CLI run、profile readback 阶段;CLI 非零另含 exit、signal 与 stderr/输出摘要。同一摘要及 operationId 写宿主 logger.warn(logger失效时安全console),UI已有可展开技术详情显示,并提示检查 DSH 源设置/网络后手动重试。不记录请求头、正文、环境、stack 或任意 details;不猜历史丢失的原错。
95
95
 
96
96
  规则模块只由宿主公开exports提供;普通DSH用与manager版本查询相同createRequire(anchor),Desktop限已证明的runtimeDir与匹配版本。没有新增manager依赖/peer、没有生产规则副本;无法定位/加载规则或端口不完整均REGISTRY_CONFIG_UNAVAILABLE。钉SHA的rc.2规则仅位于tests/fixtures,不进入发布包。
97
+
98
+ D1: DSH suite installation and upgrades use only @hanamesh/hanamesh. Core owns the bundle metadata and exact three dependency targets. A confirmed strict CLI add changes the bundle once; readback checks its saved version, activation and locked physical children. The suite display version is the bundle version. Ordinary market install/remove denies the bundle.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "package": {
3
3
  "name": "@hanamesh/dsh-app-host",
4
- "version": "0.6.18",
4
+ "version": "0.6.21",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "source": "git+https://github.com/yzsnstotz/hanamesh-plugin-app-host.git",
7
7
  "purpose": "Application ownership, view leases, Router forwarding, and application library for official DSH"
package/docs/SECURITY.md CHANGED
@@ -8,6 +8,8 @@ D-214: verification is trusted producer/client-view configuration, never a Targe
8
8
 
9
9
  # 安全与运行边界
10
10
 
11
+ 0.6.21 GitHub 安装候选(R25 修复):仅消费 Indexer 的完整 SHA/包名/子目录/构建许可,且与 App-host 当前启用目录逐字段核对。条目存在 installMethods 时必须选中其中的固定目标;没有匹配目标即 NOT_INSTALLABLE,不从 npm 展示名回退解析 latest。HanaMesh 视图拒绝退休的 latestVersion/license,确认页和升级按钮不显示目录版本;npm 升级只比较固定目标 version 与已装实际版本。网站或客户端的 installTarget 是预期值,不是任意执行源;未知字段、浮动 ref、参数注入/越界目录拒绝,套件保护名单同样适用于 Git 包。既有确认回传完整目标,目录变更不得偷换 SHA 或放行额外脚本。官方 CLI 用 argv,不执行采集来源的 shell command;受控独立 Node、Git helper 与监测边界不变。脚本许可由 pnpm 管理并可能持久化,安装失败保留具体 build-permissions 残留,不手改策略、不冒充恢复。仍不是 OS 沙箱。
12
+
11
13
  ## 可信边界
12
14
 
13
15
  注册描述符、DSH bridge 与宿主代码可信;浏览器请求、应用 HTTP 内容、旧租约和磁盘错误不可信。浏览器不能传命令、argv、env、cwd、dataDir 或任意上游 URL。实际 HTTP 拒绝和负向测试见 acceptance。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanamesh/dsh-app-host",
3
- "version": "0.6.18",
3
+ "version": "0.6.21",
4
4
  "description": "HanaMesh application ownership, durable view leases, and application library for official DSH 0.2.x",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -585,16 +585,6 @@
585
585
  "homepage": {
586
586
  "$ref": "#/$defs/hana_httpsUri"
587
587
  },
588
- "latestVersion": {
589
- "type": "string",
590
- "minLength": 1,
591
- "maxLength": 64
592
- },
593
- "license": {
594
- "type": "string",
595
- "minLength": 1,
596
- "maxLength": 80
597
- },
598
588
  "categories": {
599
589
  "type": "array",
600
590
  "maxItems": 32,
@@ -658,6 +648,32 @@
658
648
  },
659
649
  "suite": {
660
650
  "$ref": "#/$defs/hana_suite"
651
+ },
652
+ "installMethods": {
653
+ "type": "array",
654
+ "items": {
655
+ "$ref": "#/$defs/hana_installMethod"
656
+ }
657
+ },
658
+ "oneClickInstall": {
659
+ "type": "object",
660
+ "additionalProperties": false,
661
+ "required": [
662
+ "allowed",
663
+ "reason"
664
+ ],
665
+ "properties": {
666
+ "allowed": {
667
+ "type": "boolean"
668
+ },
669
+ "reason": {
670
+ "type": [
671
+ "string",
672
+ "null"
673
+ ],
674
+ "maxLength": 160
675
+ }
676
+ }
661
677
  }
662
678
  },
663
679
  "allOf": [
@@ -1231,6 +1247,77 @@
1231
1247
  "$ref": "#/$defs/hana_page"
1232
1248
  }
1233
1249
  }
1250
+ },
1251
+ "hana_installMethod": {
1252
+ "type": "object",
1253
+ "additionalProperties": false,
1254
+ "required": [
1255
+ "channel",
1256
+ "kind",
1257
+ "spec",
1258
+ "command",
1259
+ "allowBuild",
1260
+ "sourceId",
1261
+ "sourceRef"
1262
+ ],
1263
+ "properties": {
1264
+ "channel": {
1265
+ "enum": [
1266
+ "hanamesh",
1267
+ "dsh",
1268
+ "claude",
1269
+ "codex"
1270
+ ]
1271
+ },
1272
+ "kind": {
1273
+ "enum": [
1274
+ "npm",
1275
+ "github",
1276
+ "agent"
1277
+ ]
1278
+ },
1279
+ "spec": {
1280
+ "type": "string",
1281
+ "minLength": 1,
1282
+ "maxLength": 4096
1283
+ },
1284
+ "command": {
1285
+ "type": [
1286
+ "string",
1287
+ "null"
1288
+ ],
1289
+ "maxLength": 4096
1290
+ },
1291
+ "allowBuild": {
1292
+ "type": "array",
1293
+ "items": {
1294
+ "type": "string",
1295
+ "minLength": 1,
1296
+ "maxLength": 2048
1297
+ }
1298
+ },
1299
+ "sourceId": {
1300
+ "type": "string",
1301
+ "minLength": 1,
1302
+ "maxLength": 120
1303
+ },
1304
+ "sourceRef": {
1305
+ "type": "string",
1306
+ "minLength": 1,
1307
+ "maxLength": 512
1308
+ },
1309
+ "npmOwnership": {
1310
+ "type": "object"
1311
+ },
1312
+ "target": {
1313
+ "$ref": "https://hanamesh.com/schemas/app-host/install-target.schema.json#/$defs/packageInstallTarget"
1314
+ },
1315
+ "targetUnavailableReason": {
1316
+ "type": "string",
1317
+ "minLength": 1,
1318
+ "maxLength": 160
1319
+ }
1320
+ }
1234
1321
  }
1235
1322
  },
1236
1323
  "allOf": [
@@ -2,11 +2,13 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://hanamesh.com/schemas/app-host/install-target.schema.json",
4
4
  "title": "HanaMesh AppHost install target",
5
- "description": "Public identifiers a caller may hand to the AppHost market. The market resolves its own catalog, shows its own confirmation and performs the install; callers never supply versions, download locations or confirmation. Lengths are JavaScript string lengths.",
5
+ "description": "Catalog identity and reviewed structured npm/GitHub target. AppHost resolves its own catalog, binds the source/SHA/build permissions shown in its confirmation, and installs only on explicit client confirmation.",
6
6
  "x-hanamesh-contract": {
7
7
  "name": "hanamesh.install-target",
8
8
  "version": "1",
9
- "supported": ["1"],
9
+ "supported": [
10
+ "1"
11
+ ],
10
12
  "package": "@hanamesh/dsh-app-host",
11
13
  "since": "0.2.0-rc.8",
12
14
  "fragmentPrefix": "#hanamesh-install?",
@@ -38,6 +40,12 @@
38
40
  "compensation": "New install: dsh plugin remove (or dsh plugin install when only residue remains); runtime items newly claimed by this operation are removed by lib-provision ownership, unowned files and dataRoot are never deleted. Upgrade: dsh plugin add of the original spec (--save-exact when exact); a replaced runtime item is provisioned again from the restored definition. Concurrent writes by other profile writers are never undone. No automatic retry; no manual profile/store/metadata edit.",
39
41
  "readback": "restored and not-needed are reported only when every check row equals the baseline. Anything else is failed with residue rows, the recovery error (if the compensation itself failed) and originals: the pre-operation package.json/pnpm-lock.yaml/runtime ledger kept under <dataRoot>/library-recovery/<operationId>/.",
40
42
  "presentation": "A failed install is never presented as installed. failed is never presented as restored or rolled back. An event without recovery (provider before rc.10) is not presented as restored."
43
+ },
44
+ "github": {
45
+ "target": "C-INDEXER-CATALOG CatalogPackageInstallTarget",
46
+ "ref": "full immutable 40-character commit SHA, pinned at collection",
47
+ "confirmation": "show repository, full commit, path and build script permission; submit the same installTarget",
48
+ "execution": "official dsh plugin add --save-exact; native pnpm Git source and --allow-build arguments"
41
49
  }
42
50
  },
43
51
  "$ref": "#/$defs/target",
@@ -57,65 +65,152 @@
57
65
  "contractVersion": {
58
66
  "description": "Optional declaration of the contract version the caller speaks.",
59
67
  "type": "string",
60
- "enum": ["1"]
68
+ "enum": [
69
+ "1"
70
+ ]
61
71
  },
62
72
  "target": {
63
- "description": "openInstallTarget input, GET /hanamesh/library/target query and #hanamesh-install? fragment fields. At least one identifier; both must name the same catalog item. Every other field is refused.",
73
+ "description": "Catalog identifiers and optional reviewed I1 package installation target. Structured targets require itemId and must match the current catalog; callers cannot supply commands or arbitrary sources.",
64
74
  "type": "object",
65
75
  "properties": {
66
- "itemId": { "$ref": "#/$defs/itemId" },
67
- "packageName": { "$ref": "#/$defs/packageName" },
68
- "contractVersion": { "$ref": "#/$defs/contractVersion" }
76
+ "itemId": {
77
+ "$ref": "#/$defs/itemId"
78
+ },
79
+ "packageName": {
80
+ "$ref": "#/$defs/packageName"
81
+ },
82
+ "contractVersion": {
83
+ "$ref": "#/$defs/contractVersion"
84
+ },
85
+ "installTarget": {
86
+ "$ref": "#/$defs/packageInstallTarget"
87
+ }
69
88
  },
70
89
  "additionalProperties": false,
71
90
  "anyOf": [
72
- { "required": ["itemId"] },
73
- { "required": ["packageName"] }
74
- ]
91
+ {
92
+ "required": [
93
+ "itemId"
94
+ ]
95
+ },
96
+ {
97
+ "required": [
98
+ "packageName"
99
+ ]
100
+ }
101
+ ],
102
+ "dependentRequired": {
103
+ "installTarget": [
104
+ "itemId"
105
+ ]
106
+ }
75
107
  },
76
108
  "receipt": {
77
109
  "description": "openInstallTarget resolution receipt; not an install result.",
78
110
  "type": "object",
79
111
  "properties": {
80
- "status": { "type": "string", "enum": ["confirmation-required", "installing", "already-installed", "superseded"] },
81
- "itemId": { "type": "string" },
82
- "packageName": { "type": "string" }
112
+ "status": {
113
+ "type": "string",
114
+ "enum": [
115
+ "confirmation-required",
116
+ "installing",
117
+ "already-installed",
118
+ "superseded"
119
+ ]
120
+ },
121
+ "itemId": {
122
+ "type": "string"
123
+ },
124
+ "packageName": {
125
+ "type": "string"
126
+ }
83
127
  },
84
- "required": ["status"],
128
+ "required": [
129
+ "status"
130
+ ],
85
131
  "additionalProperties": false
86
132
  },
87
133
  "resolution": {
88
134
  "description": "GET /hanamesh/library/target 200 body. contractVersion is the provider's declaration (added in 0.2.0-rc.8).",
89
135
  "type": "object",
90
136
  "properties": {
91
- "contractVersion": { "type": "string", "enum": ["1"] },
137
+ "contractVersion": {
138
+ "type": "string",
139
+ "enum": [
140
+ "1"
141
+ ]
142
+ },
92
143
  "item": {
93
144
  "type": "object",
94
145
  "properties": {
95
- "id": { "$ref": "#/$defs/itemId" },
96
- "displayName": { "type": "string" },
97
- "latestVersion": { "type": "string" },
98
- "kind": { "type": "string", "enum": ["application", "plugin", "listing"] },
99
- "upgradeAvailable": { "type": "boolean" },
146
+ "id": {
147
+ "$ref": "#/$defs/itemId"
148
+ },
149
+ "displayName": {
150
+ "type": "string"
151
+ },
152
+ "kind": {
153
+ "type": "string",
154
+ "enum": [
155
+ "application",
156
+ "plugin",
157
+ "listing"
158
+ ]
159
+ },
160
+ "upgradeAvailable": {
161
+ "type": "boolean"
162
+ },
100
163
  "package": {
101
164
  "type": "object",
102
165
  "properties": {
103
- "registry": { "type": "string", "const": "npm" },
104
- "name": { "$ref": "#/$defs/packageName" }
166
+ "registry": {
167
+ "type": "string",
168
+ "enum": [
169
+ "npm",
170
+ "github"
171
+ ]
172
+ },
173
+ "name": {
174
+ "$ref": "#/$defs/packageName"
175
+ }
105
176
  },
106
- "required": ["registry", "name"]
177
+ "required": [
178
+ "registry",
179
+ "name"
180
+ ]
181
+ },
182
+ "installTarget": {
183
+ "$ref": "#/$defs/packageInstallTarget"
107
184
  }
108
185
  },
109
- "required": ["id", "kind", "package", "upgradeAvailable"]
186
+ "required": [
187
+ "id",
188
+ "kind",
189
+ "package",
190
+ "upgradeAvailable"
191
+ ]
110
192
  },
111
193
  "source": {
112
194
  "type": "object",
113
- "properties": { "kind": { "type": "string" } },
114
- "required": ["kind"]
195
+ "properties": {
196
+ "kind": {
197
+ "type": "string"
198
+ }
199
+ },
200
+ "required": [
201
+ "kind"
202
+ ]
115
203
  },
116
- "traceId": { "type": "string" }
204
+ "traceId": {
205
+ "type": "string"
206
+ }
117
207
  },
118
- "required": ["contractVersion", "item", "source", "traceId"]
208
+ "required": [
209
+ "contractVersion",
210
+ "item",
211
+ "source",
212
+ "traceId"
213
+ ]
119
214
  },
120
215
  "error": {
121
216
  "description": "Refusal body of the HTTP routes; the client rejects with the same code.",
@@ -126,26 +221,64 @@
126
221
  "properties": {
127
222
  "code": {
128
223
  "type": "string",
129
- "enum": ["INVALID_INPUT", "CONTRACT_VERSION_UNSUPPORTED", "CATALOG_ITEM_MISSING", "NOT_INSTALLABLE", "PACKAGE_DENIED", "HOST_DENIED", "ORIGIN_DENIED", "FRAME_CONTROL_DENIED", "CSRF_DENIED", "UNAUTHENTICATED", "FORBIDDEN", "METHOD_NOT_ALLOWED", "LIBRARY_INSTALL_UNAVAILABLE"]
224
+ "enum": [
225
+ "INVALID_INPUT",
226
+ "CONTRACT_VERSION_UNSUPPORTED",
227
+ "CATALOG_ITEM_MISSING",
228
+ "NOT_INSTALLABLE",
229
+ "PACKAGE_DENIED",
230
+ "HOST_DENIED",
231
+ "ORIGIN_DENIED",
232
+ "FRAME_CONTROL_DENIED",
233
+ "CSRF_DENIED",
234
+ "UNAUTHENTICATED",
235
+ "FORBIDDEN",
236
+ "METHOD_NOT_ALLOWED",
237
+ "LIBRARY_INSTALL_UNAVAILABLE"
238
+ ]
130
239
  },
131
- "message": { "type": "string" }
240
+ "message": {
241
+ "type": "string"
242
+ }
132
243
  },
133
- "required": ["code"]
244
+ "required": [
245
+ "code"
246
+ ]
134
247
  },
135
- "traceId": { "type": "string" }
248
+ "traceId": {
249
+ "type": "string"
250
+ }
136
251
  },
137
- "required": ["error"]
252
+ "required": [
253
+ "error"
254
+ ]
138
255
  },
139
256
  "providerDeclaration": {
140
257
  "description": "package.json hanamesh.installTarget of a provider package.",
141
258
  "type": "object",
142
259
  "properties": {
143
- "contract": { "type": "string", "const": "hanamesh.install-target" },
144
- "contractVersion": { "type": "string" },
145
- "supported": { "type": "array", "items": { "type": "string" } },
146
- "schema": { "type": "string" }
260
+ "contract": {
261
+ "type": "string",
262
+ "const": "hanamesh.install-target"
263
+ },
264
+ "contractVersion": {
265
+ "type": "string"
266
+ },
267
+ "supported": {
268
+ "type": "array",
269
+ "items": {
270
+ "type": "string"
271
+ }
272
+ },
273
+ "schema": {
274
+ "type": "string"
275
+ }
147
276
  },
148
- "required": ["contract", "contractVersion", "supported"]
277
+ "required": [
278
+ "contract",
279
+ "contractVersion",
280
+ "supported"
281
+ ]
149
282
  },
150
283
  "recovery": {
151
284
  "description": "library.install-failed recovery result (added in 0.2.0-rc.10).",
@@ -293,6 +426,87 @@
293
426
  "type",
294
427
  "code"
295
428
  ]
429
+ },
430
+ "packageInstallTarget": {
431
+ "anyOf": [
432
+ {
433
+ "type": "object",
434
+ "properties": {
435
+ "source": {
436
+ "const": "npm"
437
+ },
438
+ "allowBuild": {
439
+ "type": "array",
440
+ "items": {
441
+ "type": "string",
442
+ "minLength": 1,
443
+ "maxLength": 2048,
444
+ "pattern": "^[^\\s\\u0000-\\u001f\\u007f-\\u009f]+$"
445
+ }
446
+ },
447
+ "name": {
448
+ "$ref": "#/$defs/packageName"
449
+ },
450
+ "version": {
451
+ "type": "string",
452
+ "maxLength": 128,
453
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(?:-(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$"
454
+ }
455
+ },
456
+ "required": [
457
+ "source",
458
+ "name",
459
+ "version",
460
+ "allowBuild"
461
+ ],
462
+ "additionalProperties": false
463
+ },
464
+ {
465
+ "type": "object",
466
+ "properties": {
467
+ "source": {
468
+ "const": "github"
469
+ },
470
+ "allowBuild": {
471
+ "type": "array",
472
+ "items": {
473
+ "type": "string",
474
+ "minLength": 1,
475
+ "maxLength": 2048,
476
+ "pattern": "^[^\\s\\u0000-\\u001f\\u007f-\\u009f]+$"
477
+ }
478
+ },
479
+ "repo": {
480
+ "type": "string",
481
+ "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?/[A-Za-z0-9_][A-Za-z0-9._-]*$"
482
+ },
483
+ "ref": {
484
+ "type": "string",
485
+ "pattern": "^[0-9a-fA-F]{40}$"
486
+ },
487
+ "path": {
488
+ "type": [
489
+ "string",
490
+ "null"
491
+ ],
492
+ "minLength": 1,
493
+ "pattern": "^(?!\\.{1,2}(?:/|$))[A-Za-z0-9_@+.-]+(?:/(?!\\.{1,2}(?:/|$))[A-Za-z0-9_@+.-]+)*$"
494
+ },
495
+ "packageName": {
496
+ "$ref": "#/$defs/packageName"
497
+ }
498
+ },
499
+ "required": [
500
+ "source",
501
+ "repo",
502
+ "ref",
503
+ "path",
504
+ "packageName",
505
+ "allowBuild"
506
+ ],
507
+ "additionalProperties": false
508
+ }
509
+ ]
296
510
  }
297
511
  }
298
512
  }