@coralai/sps-plugin-storage-sync 0.2.0 → 0.3.0
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/dist/index.d.ts +1 -1
- package/dist/index.js +9 -3
- package/dist/syncable.d.ts +35 -20
- package/dist/syncable.js +5 -23
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare const name = "storage-sync";
|
|
|
24
24
|
export declare const category = "\u5B58\u50A8";
|
|
25
25
|
export declare const description = "\u5DE5\u4F5C\u533A \u2192 \u5BF9\u8C61\u5B58\u50A8\u540C\u6B65:\u6309\u4EA7\u54C1\u58F0\u660E\u7684\u8303\u56F4,\u628A\u7528\u6237\u4EA7\u7269\u589E\u91CF\u642C\u5230 S3 \u517C\u5BB9\u6876\u3002";
|
|
26
26
|
interface ApplyCtx {
|
|
27
|
-
effect(fn: () => void): void;
|
|
27
|
+
effect(fn: () => (() => void) | void): void;
|
|
28
28
|
logger?: {
|
|
29
29
|
info(msg: string): void;
|
|
30
30
|
warn(msg: string): void;
|
package/dist/index.js
CHANGED
|
@@ -65,13 +65,19 @@ export function apply(ctx, config) {
|
|
|
65
65
|
// 没查线上装着的插件 ⇒ gameforge-art 永远 PENDING、六个 art.* 能力全缺席。
|
|
66
66
|
// ⇒ 契约留在 `@coralai/sps-plugin-api`,**实现跟着持有桶凭据的这个插件走**。
|
|
67
67
|
const backend = new MinioBackend(config);
|
|
68
|
-
|
|
68
|
+
// 🔴 `ctx.effect(fn)` **立即执行 fn**,并把 fn 的返回值当卸载时的 disposer。
|
|
69
|
+
// 第一版写成 `const d = provide(...); ctx.effect(() => d())` ——
|
|
70
|
+
// 那当场就把刚 provide 的服务撤销了,而且**没有任何报错**:
|
|
71
|
+
// apply 照常跑完、日志照常打,只有 inject 它的插件永远 PENDING。
|
|
72
|
+
// (2026-08-28 实测:线上 `reflect.get('sps.storage')` 拿不到,
|
|
73
|
+
// 而同一次装配里 `[sps-sync] 常驻` 已经打出来了。)
|
|
74
|
+
// ⇒ 本仓先例是 `ctx.effect(() => ctx[AGENTS].register(f))` —— register 返回 unregister。
|
|
75
|
+
ctx.effect(() => ctx.reflect.provide('sps.storage', {
|
|
69
76
|
configured: () => Boolean(config.endpoint && config.bucket && config.enabled !== false),
|
|
70
77
|
get: (key) => backend.get(key),
|
|
71
78
|
list: (prefix) => backend.list(prefix),
|
|
72
79
|
put: (key, bytes, contentType) => backend.put(key, bytes, contentType),
|
|
73
|
-
});
|
|
74
|
-
ctx.effect(() => disposeStorage());
|
|
80
|
+
}));
|
|
75
81
|
log(`[sps-sync] 常驻:间隔=${intervalMs}ms 范围=近 ${sinceDays || '∞'} 天`);
|
|
76
82
|
void tick().finally(schedule);
|
|
77
83
|
// 插件卸载/重挂时停掉循环 —— 否则改一次配置就多一个循环在跑。
|
package/dist/syncable.d.ts
CHANGED
|
@@ -1,26 +1,41 @@
|
|
|
1
|
-
export type SyncRejection = {
|
|
2
|
-
code: 'ABSOLUTE';
|
|
3
|
-
rel: string;
|
|
4
|
-
} | {
|
|
5
|
-
code: 'DOT_SEGMENT';
|
|
6
|
-
rel: string;
|
|
7
|
-
} | {
|
|
8
|
-
code: 'PARENT_SEGMENT';
|
|
9
|
-
rel: string;
|
|
10
|
-
} | {
|
|
11
|
-
code: 'EMPTY_SEGMENT';
|
|
12
|
-
rel: string;
|
|
13
|
-
} | {
|
|
14
|
-
code: 'ESCAPES_PROJECT';
|
|
15
|
-
rel: string;
|
|
16
|
-
};
|
|
17
1
|
/**
|
|
18
|
-
*
|
|
2
|
+
* @module providers/storage/syncable
|
|
3
|
+
* @description **同步**这条路的安全下限。设计见 `object-storage-and-workspace-sync.md` §2.1 第五条。
|
|
4
|
+
*
|
|
5
|
+
* @layer providers
|
|
6
|
+
*
|
|
7
|
+
* 🔴🔴 **它与发布的下限方向相反,别互相抄。**
|
|
8
|
+
* ```
|
|
9
|
+
* 发布 publishable() 怕**多发** —— 树里会长出什么由 agent 决定,黑名单追不上 ⇒ **后缀白名单**
|
|
10
|
+
* 同步 syncable() 怕**少发** —— 用户会放 .blend / .psd / .aseprite ⇒ **不能用后缀白名单**
|
|
11
|
+
* ```
|
|
12
|
+
* 抄错方向的表现是:**用户的源文件不见了,而且不报错**。
|
|
13
|
+
* (「照搬一份现成的安全规则」恰恰是最容易顺手抄整份的时候。)
|
|
14
|
+
*
|
|
15
|
+
* 🔴 **声明决定"要什么",本模块决定"绝不给什么"** —— 后者不是产品知识,是主体安全,
|
|
16
|
+
* 且**不可被声明或配置放宽**。它防的是一件具体的事:项目树里有带活 token 的
|
|
17
|
+
* `.claude/settings.local.json`(实测:coral 那侧 `publishable('src/main.js')` 放行,
|
|
18
|
+
* 而 `readFile` 实际拿到 `ANTHROPIC_AUTH_TOKEN=sk-live-…`,落点还是公开可取的前缀)。
|
|
19
|
+
*
|
|
20
|
+
* 🔴 **真正拦住凭据的是"任一路径段以 `.` 开头"这一条**,不是别的:
|
|
21
|
+
* `settings.local.json` 本身后缀无害,是 `.claude/` 这个点开头段拦住的。
|
|
22
|
+
* ⇒ 将来谁"为了支持 `.well-known/` 放宽点开头",会在不知情的情况下把底线整个打开。
|
|
23
|
+
* > 判据:**守卫要标注它靠哪一条在生效** —— 否则放宽的人以为自己在动一条无关的规则。
|
|
24
|
+
*/
|
|
25
|
+
import { type SyncRejection as ShapeRejection, syncableShape } from '@coralai/sps-plugin-api';
|
|
26
|
+
export { syncableShape };
|
|
27
|
+
/**
|
|
28
|
+
* 完整的拒绝理由 = **形状**(契约包那 4 个)+ **围栏**(这一个)。
|
|
19
29
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
30
|
+
* ⚠️ 两者不该合并进契约包:形状是纯字符串判断,任何地方都能算;
|
|
31
|
+
* `ESCAPES_PROJECT` 要 realpath、要项目根,是**运行时**的结果。
|
|
32
|
+
* 合进去会让"只调形状那一半"看起来像完整判据 —— 而那正是漏掉软链的写法。
|
|
22
33
|
*/
|
|
23
|
-
export
|
|
34
|
+
export type SyncRejection = ShapeRejection | {
|
|
35
|
+
code: 'ESCAPES_PROJECT';
|
|
36
|
+
rel: string;
|
|
37
|
+
};
|
|
38
|
+
export type SyncRejectCode = SyncRejection['code'];
|
|
24
39
|
/**
|
|
25
40
|
* 完整判据 = 形状 + **realpath 围栏**。
|
|
26
41
|
*
|
package/dist/syncable.js
CHANGED
|
@@ -22,29 +22,11 @@
|
|
|
22
22
|
* ⇒ 将来谁"为了支持 `.well-known/` 放宽点开头",会在不知情的情况下把底线整个打开。
|
|
23
23
|
* > 判据:**守卫要标注它靠哪一条在生效** —— 否则放宽的人以为自己在动一条无关的规则。
|
|
24
24
|
*/
|
|
25
|
-
import { isRealUnderRoot } from '@coralai/sps-plugin-api';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
* 只调这一半的实现会"看起来对",而它恰恰漏掉了唯一挡得住 agent 自造软链的那道。
|
|
31
|
-
*/
|
|
32
|
-
export function syncableShape(rel) {
|
|
33
|
-
if (!rel)
|
|
34
|
-
return { code: 'EMPTY_SEGMENT', rel };
|
|
35
|
-
if (rel.startsWith('/'))
|
|
36
|
-
return { code: 'ABSOLUTE', rel };
|
|
37
|
-
for (const seg of rel.split('/')) {
|
|
38
|
-
if (!seg)
|
|
39
|
-
return { code: 'EMPTY_SEGMENT', rel };
|
|
40
|
-
if (seg === '..')
|
|
41
|
-
return { code: 'PARENT_SEGMENT', rel };
|
|
42
|
-
// ← 承重的是这条:`.claude/`、`.git/`、`.sps/` 全靠它
|
|
43
|
-
if (seg.startsWith('.'))
|
|
44
|
-
return { code: 'DOT_SEGMENT', rel };
|
|
45
|
-
}
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
25
|
+
import { isRealUnderRoot, syncableShape, } from '@coralai/sps-plugin-api';
|
|
26
|
+
// 🔴 形状判据的真源在 `@coralai/sps-plugin-api` —— **两个地方要用同一份**:
|
|
27
|
+
// 这里(同步时判每个文件)与宿主(写 sync-scope 声明时判每条 include)。
|
|
28
|
+
// 各写一份的话,写入口放行的声明会在同步时被静默挡掉,而配置的人看不到。
|
|
29
|
+
export { syncableShape };
|
|
48
30
|
/**
|
|
49
31
|
* 完整判据 = 形状 + **realpath 围栏**。
|
|
50
32
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coralai/sps-plugin-storage-sync",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "工作区 → 对象存储同步:把节点本地盘上的用户产物搬到共享面(S3 兼容桶)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@coralai/sps-plugin-api": "^0.
|
|
31
|
+
"@coralai/sps-plugin-api": "^0.16.0"
|
|
32
32
|
},
|
|
33
33
|
"optionalDependencies": {
|
|
34
34
|
"minio": "^8.0.7"
|