@kkuffour/solid-moderation-plugin 0.2.2 → 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.
Files changed (74) hide show
  1. package/.data/.internal/idp/keys/cookie-secret$.json +1 -0
  2. package/.data/.internal/idp/keys/jwks$.json +1 -0
  3. package/.data/.internal/setup/current-base-url$.json +1 -0
  4. package/PLUGIN_DEVELOPER_GUIDE.md +213 -0
  5. package/README.md +25 -28
  6. package/components/context.jsonld +6 -245
  7. package/config/default.json +14 -28
  8. package/dist/ModerationHandler.d.ts +21 -0
  9. package/dist/ModerationHandler.d.ts.map +1 -0
  10. package/dist/ModerationHandler.js +158 -0
  11. package/dist/ModerationHandler.js.map +1 -0
  12. package/dist/ModerationHandler.jsonld +126 -0
  13. package/dist/components/components.jsonld +13 -0
  14. package/dist/components/context.jsonld +11 -0
  15. package/dist/index.d.ts +1 -6
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -6
  18. package/dist/index.js.map +1 -1
  19. package/dist/providers/SightEngineProvider.jsonld +2 -2
  20. package/package.json +11 -11
  21. package/src/ModerationHandler.ts +189 -0
  22. package/src/index.ts +1 -6
  23. package/ARCHITECTURE.md +0 -52
  24. package/CONFIG-GUIDE.md +0 -49
  25. package/DEVELOPMENT.md +0 -129
  26. package/ENV-VARIABLES.md +0 -137
  27. package/INSTALLATION.md +0 -90
  28. package/MIGRATION.md +0 -81
  29. package/PRODUCTION.md +0 -186
  30. package/PUBLISHING.md +0 -104
  31. package/TESTING.md +0 -93
  32. package/components/components.jsonld +0 -18
  33. package/dist/ModerationConfig.d.ts +0 -16
  34. package/dist/ModerationConfig.d.ts.map +0 -1
  35. package/dist/ModerationConfig.js +0 -18
  36. package/dist/ModerationConfig.js.map +0 -1
  37. package/dist/ModerationConfig.jsonld +0 -66
  38. package/dist/ModerationMixin.d.ts +0 -13
  39. package/dist/ModerationMixin.d.ts.map +0 -1
  40. package/dist/ModerationMixin.js +0 -136
  41. package/dist/ModerationMixin.js.map +0 -1
  42. package/dist/ModerationMixin.jsonld +0 -180
  43. package/dist/ModerationOperationHandler.d.ts +0 -16
  44. package/dist/ModerationOperationHandler.d.ts.map +0 -1
  45. package/dist/ModerationOperationHandler.js +0 -45
  46. package/dist/ModerationOperationHandler.js.map +0 -1
  47. package/dist/ModerationOperationHandler.jsonld +0 -140
  48. package/dist/ModerationRecord.d.ts +0 -20
  49. package/dist/ModerationRecord.d.ts.map +0 -1
  50. package/dist/ModerationRecord.js +0 -3
  51. package/dist/ModerationRecord.js.map +0 -1
  52. package/dist/ModerationRecord.jsonld +0 -59
  53. package/dist/ModerationResourceStore.d.ts +0 -30
  54. package/dist/ModerationResourceStore.d.ts.map +0 -1
  55. package/dist/ModerationResourceStore.js +0 -167
  56. package/dist/ModerationResourceStore.js.map +0 -1
  57. package/dist/ModerationResourceStore.jsonld +0 -157
  58. package/dist/ModerationStore.d.ts +0 -12
  59. package/dist/ModerationStore.d.ts.map +0 -1
  60. package/dist/ModerationStore.js +0 -37
  61. package/dist/ModerationStore.js.map +0 -1
  62. package/dist/ModerationStore.jsonld +0 -59
  63. package/dist/util/GuardedStream.d.ts +0 -33
  64. package/dist/util/GuardedStream.d.ts.map +0 -1
  65. package/dist/util/GuardedStream.js +0 -89
  66. package/dist/util/GuardedStream.js.map +0 -1
  67. package/simple-test.json +0 -7
  68. package/src/ModerationConfig.ts +0 -29
  69. package/src/ModerationMixin.ts +0 -153
  70. package/src/ModerationOperationHandler.ts +0 -64
  71. package/src/ModerationRecord.ts +0 -19
  72. package/src/ModerationResourceStore.ts +0 -227
  73. package/src/ModerationStore.ts +0 -41
  74. package/src/util/GuardedStream.ts +0 -101
package/PRODUCTION.md DELETED
@@ -1,186 +0,0 @@
1
- # Production Deployment Guide
2
-
3
- ## Installation
4
-
5
- 1. **Install the plugin:**
6
- ```bash
7
- npm install @solid/moderation-plugin
8
- ```
9
-
10
- 2. **Create config file** in your CSS project (e.g., `config-with-moderation.json`):
11
- ```json
12
- {
13
- "@context": [
14
- "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld",
15
- "https://linkedsoftwaredependencies.org/bundles/npm/@solid/moderation-plugin/^1.0.0/components/context.jsonld"
16
- ],
17
- "import": [
18
- "css:config/file.json",
19
- "@solid/moderation-plugin:config/default.json"
20
- ]
21
- }
22
- ```
23
-
24
- 3. **Set environment variables** (choose one method):
25
-
26
- ## Environment Variable Setup
27
-
28
- ### Option 1: Shell Profile (Simple)
29
- Add to `~/.bashrc` or `~/.zshrc`:
30
- ```bash
31
- export SIGHTENGINE_API_USER=your_api_user
32
- export SIGHTENGINE_API_SECRET=your_api_secret
33
- ```
34
-
35
- ### Option 2: Systemd Service (Recommended for Production)
36
- Create `/etc/systemd/system/solid-server.service`:
37
- ```ini
38
- [Unit]
39
- Description=Community Solid Server with Moderation
40
- After=network.target
41
-
42
- [Service]
43
- Type=simple
44
- User=solid
45
- WorkingDirectory=/opt/solid-server
46
- Environment="SIGHTENGINE_API_USER=your_api_user"
47
- Environment="SIGHTENGINE_API_SECRET=your_api_secret"
48
- ExecStart=/usr/bin/npx @solid/community-server -c config-with-moderation.json
49
- Restart=always
50
-
51
- [Install]
52
- WantedBy=multi-user.target
53
- ```
54
-
55
- Enable and start:
56
- ```bash
57
- sudo systemctl enable solid-server
58
- sudo systemctl start solid-server
59
- ```
60
-
61
- ### Option 3: Docker
62
- Create `docker-compose.yml`:
63
- ```yaml
64
- version: '3'
65
- services:
66
- solid-server:
67
- image: node:20
68
- working_dir: /app
69
- volumes:
70
- - ./:/app
71
- environment:
72
- - SIGHTENGINE_API_USER=your_api_user
73
- - SIGHTENGINE_API_SECRET=your_api_secret
74
- command: npx @solid/community-server -c config-with-moderation.json
75
- ports:
76
- - "3000:3000"
77
- ```
78
-
79
- Run:
80
- ```bash
81
- docker-compose up -d
82
- ```
83
-
84
- ### Option 4: PM2 Process Manager
85
- Create `ecosystem.config.js`:
86
- ```javascript
87
- module.exports = {
88
- apps: [{
89
- name: 'solid-server',
90
- script: 'npx',
91
- args: '@solid/community-server -c config-with-moderation.json',
92
- env: {
93
- SIGHTENGINE_API_USER: 'your_api_user',
94
- SIGHTENGINE_API_SECRET: 'your_api_secret'
95
- }
96
- }]
97
- };
98
- ```
99
-
100
- Run:
101
- ```bash
102
- pm2 start ecosystem.config.js
103
- pm2 save
104
- pm2 startup
105
- ```
106
-
107
- ## How It Works in Production
108
-
109
- ### Local Testing vs Production
110
-
111
- | Aspect | Local Testing | Production |
112
- |--------|--------------|------------|
113
- | Plugin Location | `/Users/opendata/solid-moderation` (source) | `node_modules/@solid/moderation-plugin` (npm) |
114
- | Installation | `npm link` | `npm install @solid/moderation-plugin` |
115
- | Config Import | Full path to local file | `@solid/moderation-plugin:config/default.json` |
116
- | Components | Loaded from local `dist/` | Loaded from `node_modules/@solid/moderation-plugin/dist/` |
117
-
118
- ### What Happens When CSS Starts
119
-
120
- 1. **CSS reads your config file**
121
- 2. **Sees import:** `@solid/moderation-plugin:config/default.json`
122
- 3. **Resolves to:** `node_modules/@solid/moderation-plugin/config/default.json`
123
- 4. **Loads components from:** `node_modules/@solid/moderation-plugin/dist/components/`
124
- 5. **Instantiates:** ModerationOperationHandler wrapping PUT/POST/PATCH
125
- 6. **Reads env vars:** `${SIGHTENGINE_API_USER}` → actual value
126
- 7. **Server starts** with moderation active
127
-
128
- ### File Locations in Production
129
-
130
- ```
131
- your-css-project/
132
- ├── node_modules/
133
- │ └── @solid/
134
- │ └── moderation-plugin/ ← Installed here
135
- │ ├── dist/
136
- │ │ ├── components/
137
- │ │ ├── *.js
138
- │ │ └── *.jsonld
139
- │ ├── config/
140
- │ │ └── default.json ← Imported by your config
141
- │ └── package.json
142
-
143
- ├── config-with-moderation.json ← Your config file
144
- ├── data/
145
- │ └── moderation-logs/ ← Runtime logs
146
- └── package.json
147
- ```
148
-
149
- ## Customizing Thresholds in Production
150
-
151
- Override specific settings in your config:
152
- ```json
153
- {
154
- "import": [
155
- "css:config/file.json",
156
- "@solid/moderation-plugin:config/default.json"
157
- ],
158
- "@graph": [
159
- {
160
- "@id": "urn:solid-moderation:default:Config",
161
- "ModerationConfig:_images_thresholds": {
162
- "ModerationConfig:_images_thresholds_nudity": 0.3
163
- }
164
- }
165
- ]
166
- }
167
- ```
168
-
169
- ## Monitoring
170
-
171
- Check logs:
172
- ```bash
173
- # Systemd
174
- sudo journalctl -u solid-server -f
175
-
176
- # PM2
177
- pm2 logs solid-server
178
-
179
- # Docker
180
- docker-compose logs -f
181
- ```
182
-
183
- View moderation violations:
184
- ```bash
185
- cat data/moderation-logs/$(date +%Y-%m-%d).jsonl
186
- ```
package/PUBLISHING.md DELETED
@@ -1,104 +0,0 @@
1
- # Publishing Guide
2
-
3
- ## Before Publishing
4
-
5
- Replace `@kkuffour` with your actual npm username/organization in these files:
6
- - `package.json` (name, lsd:module, lsd:contexts)
7
- - `components/context.jsonld` (smp prefix)
8
- - `components/components.jsonld` (@context, @id, requireName)
9
- - `config-with-moderation.json` (@context)
10
-
11
- ## Steps to Publish
12
-
13
- ### 1. Login to npm
14
- ```bash
15
- npm login
16
- ```
17
-
18
- ### 2. Build the package
19
- ```bash
20
- cd /Users/opendata/solid-moderation
21
- npm run build
22
- ```
23
-
24
- ### 3. Test locally first (optional)
25
- ```bash
26
- npm pack
27
- # This creates a .tgz file you can test with
28
- ```
29
-
30
- ### 4. Publish to npm
31
- ```bash
32
- # For scoped package (recommended for testing)
33
- npm publish --access public
34
-
35
- # Or for private testing
36
- npm publish --access restricted
37
- ```
38
-
39
- ### 5. Install in CSS
40
- ```bash
41
- cd /Users/opendata/CommunitySolidServer
42
- npm install @kkuffour/solid-moderation-plugin@latest
43
- ```
44
-
45
- ### 6. Update config reference
46
- The config file path stays the same:
47
- ```bash
48
- npm start -- -c /Users/opendata/solid-moderation/config-with-moderation.json -f data/ -p 3009 -l debug
49
- ```
50
-
51
- ## Version Updates
52
-
53
- After making changes:
54
- ```bash
55
- # Update version
56
- npm version patch # 0.1.0 -> 0.1.1
57
- # or
58
- npm version minor # 0.1.0 -> 0.2.0
59
-
60
- # Rebuild and republish
61
- npm run build
62
- npm publish
63
- ```
64
-
65
- ## Moving to @solid Namespace
66
-
67
- Once tested and ready for official release:
68
-
69
- 1. Request access to @solid npm organization
70
- 2. Update all references from `@kkuffour/solid-moderation-plugin` to `@solid/moderation-plugin`
71
- 3. Update version to `1.0.0`
72
- 4. Publish to @solid namespace
73
-
74
- ## Troubleshooting
75
-
76
- **If publish fails with 403:**
77
- - Check you're logged in: `npm whoami`
78
- - Verify package name is available: `npm view @kkuffour/solid-moderation-plugin`
79
- - Ensure `--access public` for scoped packages
80
-
81
- **If Components.js can't find module after install:**
82
- - Verify `lsd:module`, `lsd:components`, and `lsd:contexts` paths in package.json
83
- - Check that `components/` directory exists with `.jsonld` files
84
- - Rebuild: `npm run build`
85
-
86
- ## Current Configuration
87
-
88
- **Package Name**: `@kkuffour/solid-moderation-plugin`
89
- **Version**: `0.1.0`
90
- **Entry Point**: `dist/index.js`
91
- **Components**: `components/components.jsonld`
92
- **Context**: `components/context.jsonld`
93
-
94
- **Environment Variables Required**:
95
- ```bash
96
- export SIGHTENGINE_API_USER="1060049443"
97
- export SIGHTENGINE_API_SECRET="QRQ8HUmh4hyvhZjksBJq5ZaNYPLPEKXu"
98
- ```
99
-
100
- **Thresholds** (configurable in config-with-moderation.json):
101
- - Image Nudity: 0.1 (10%)
102
- - Text Sexual: 0.1 (10%)
103
- - Text Toxic: 0.1 (10%)
104
- - Video Nudity: 0.1 (10%)
package/TESTING.md DELETED
@@ -1,93 +0,0 @@
1
- # Testing ResourceStore Approach Locally
2
-
3
- ## Setup
4
-
5
- 1. Build the plugin:
6
- ```bash
7
- npm run build
8
- ```
9
-
10
- 2. Link locally for testing:
11
- ```bash
12
- npm link
13
- ```
14
-
15
- 3. In your CSS directory:
16
- ```bash
17
- npm link @kkuffour/solid-moderation-plugin
18
- ```
19
-
20
- 4. Set environment variables:
21
- ```bash
22
- export SIGHTENGINE_API_USER=1060049443
23
- export SIGHTENGINE_API_SECRET=QRQ8HUmh4hyvhZjksBJq5ZaNYPLPEKXu
24
- ```
25
-
26
- 5. Create test config in CSS directory (`config-moderation-test.json`):
27
- ```json
28
- {
29
- "@context": [
30
- "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld",
31
- "https://linkedsoftwaredependencies.org/bundles/npm/@kkuffour/solid-moderation-plugin/^0.2.0/components/context.jsonld"
32
- ],
33
- "import": [
34
- "css:config/file.json"
35
- ],
36
- "@graph": [
37
- {
38
- "@id": "urn:solid-moderation:SightEngineProvider",
39
- "@type": "ksmp:dist/providers/SightEngineProvider.jsonld#SightEngineProvider",
40
- "ksmp:dist/providers/SightEngineProvider.jsonld#SightEngineProvider_apiUser": "1060049443",
41
- "ksmp:dist/providers/SightEngineProvider.jsonld#SightEngineProvider_apiSecret": "QRQ8HUmh4hyvhZjksBJq5ZaNYPLPEKXu"
42
- },
43
- {
44
- "@id": "urn:solid-server:default:ResourceStore_Original",
45
- "@type": "DataAccessorBasedStore",
46
- "identifierStrategy": { "@id": "urn:solid-server:default:IdentifierStrategy" },
47
- "auxiliaryStrategy": { "@id": "urn:solid-server:default:AuxiliaryStrategy" },
48
- "accessor": { "@id": "urn:solid-server:default:DataAccessor" },
49
- "metadataStrategy": { "@id": "urn:solid-server:default:MetadataStrategy" }
50
- },
51
- {
52
- "@id": "urn:solid-server:default:ResourceStore",
53
- "@type": "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore",
54
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_source": {
55
- "@id": "urn:solid-server:default:ResourceStore_Original"
56
- },
57
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_client": {
58
- "@id": "urn:solid-moderation:SightEngineProvider"
59
- },
60
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_enabled": true,
61
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_imageNudityThreshold": 0.1,
62
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_textSexualThreshold": 0.1,
63
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_textToxicThreshold": 0.1,
64
- "ksmp:dist/ModerationResourceStore.jsonld#ModerationResourceStore_videoNudityThreshold": 0.1
65
- }
66
- ]
67
- }
68
- ```
69
-
70
- 6. Start CSS:
71
- ```bash
72
- npx @solid/community-server -c config-moderation-test.json
73
- ```
74
-
75
- ## Expected Behavior
76
-
77
- - Server should start without errors
78
- - Log should show: "ModerationResourceStore initialized"
79
- - Uploading images/videos/text should trigger moderation
80
- - Content exceeding thresholds should be blocked with 403 Forbidden
81
-
82
- ## Testing
83
-
84
- Upload a test image:
85
- ```bash
86
- curl -X PUT http://localhost:3000/test.jpg \
87
- -H "Content-Type: image/jpeg" \
88
- --data-binary @test-image.jpg
89
- ```
90
-
91
- Check logs for:
92
- - "Moderating image/jpeg upload to /test.jpg"
93
- - "Image APPROVED" or "Image BLOCKED"
@@ -1,18 +0,0 @@
1
- {
2
- "@context": [
3
- "https://linkedsoftwaredependencies.org/bundles/npm/@kkuffour/solid-moderation-plugin/^0.2.0/components/context.jsonld",
4
- "https://linkedsoftwaredependencies.org/bundles/npm/@kkuffour/solid-moderation-plugin/^0.2.0/config/context.jsonld"
5
- ],
6
- "@id": "npmd:@kkuffour/solid-moderation-plugin",
7
- "@type": "Module",
8
- "requireName": "@kkuffour/solid-moderation-plugin",
9
- "import": [
10
- "ksmp:dist/ModerationOperationHandler.jsonld",
11
- "ksmp:dist/ModerationResourceStore.jsonld",
12
- "ksmp:dist/ModerationConfig.jsonld",
13
- "ksmp:dist/ModerationStore.jsonld",
14
- "ksmp:dist/ModerationRecord.jsonld",
15
- "ksmp:dist/ModerationMixin.jsonld",
16
- "ksmp:dist/providers/SightEngineProvider.jsonld"
17
- ]
18
- }
@@ -1,16 +0,0 @@
1
- export interface ModerationConfig {
2
- enabled: boolean;
3
- auditLoggingEnabled: boolean;
4
- auditLoggingStorePath: string;
5
- sightEngineApiUser: string;
6
- sightEngineApiSecret: string;
7
- imagesEnabled: boolean;
8
- textEnabled: boolean;
9
- videoEnabled: boolean;
10
- imageNudityThreshold: number;
11
- textSexualThreshold: number;
12
- textToxicThreshold: number;
13
- videoNudityThreshold: number;
14
- }
15
- export declare const DEFAULT_MODERATION_CONFIG: ModerationConfig;
16
- //# sourceMappingURL=ModerationConfig.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ModerationConfig.d.ts","sourceRoot":"","sources":["../src/ModerationConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,yBAAyB,EAAE,gBAavC,CAAC"}
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_MODERATION_CONFIG = void 0;
4
- exports.DEFAULT_MODERATION_CONFIG = {
5
- enabled: true,
6
- auditLoggingEnabled: true,
7
- auditLoggingStorePath: './data/moderation-logs',
8
- sightEngineApiUser: '',
9
- sightEngineApiSecret: '',
10
- imagesEnabled: true,
11
- textEnabled: true,
12
- videoEnabled: true,
13
- imageNudityThreshold: 0.5,
14
- textSexualThreshold: 0.5,
15
- textToxicThreshold: 0.5,
16
- videoNudityThreshold: 0.5,
17
- };
18
- //# sourceMappingURL=ModerationConfig.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ModerationConfig.js","sourceRoot":"","sources":["../src/ModerationConfig.ts"],"names":[],"mappings":";;;AAea,QAAA,yBAAyB,GAAqB;IACzD,OAAO,EAAE,IAAI;IACb,mBAAmB,EAAE,IAAI;IACzB,qBAAqB,EAAE,wBAAwB;IAC/C,kBAAkB,EAAE,EAAE;IACtB,oBAAoB,EAAE,EAAE;IACxB,aAAa,EAAE,IAAI;IACnB,WAAW,EAAE,IAAI;IACjB,YAAY,EAAE,IAAI;IAClB,oBAAoB,EAAE,GAAG;IACzB,mBAAmB,EAAE,GAAG;IACxB,kBAAkB,EAAE,GAAG;IACvB,oBAAoB,EAAE,GAAG;CAC1B,CAAC"}
@@ -1,66 +0,0 @@
1
- {
2
- "@context": [
3
- "https://linkedsoftwaredependencies.org/bundles/npm/@kkuffour/solid-moderation-plugin/^0.2.0/components/context.jsonld",
4
- "https://linkedsoftwaredependencies.org/bundles/npm/@kkuffour/solid-moderation-plugin/^0.2.0/config/context.jsonld"
5
- ],
6
- "@id": "npmd:@kkuffour/solid-moderation-plugin",
7
- "components": [
8
- {
9
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig",
10
- "@type": "AbstractClass",
11
- "requireElement": "ModerationConfig",
12
- "parameters": [],
13
- "memberFields": [
14
- {
15
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_enabled",
16
- "memberFieldName": "enabled"
17
- },
18
- {
19
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_auditLoggingEnabled",
20
- "memberFieldName": "auditLoggingEnabled"
21
- },
22
- {
23
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_auditLoggingStorePath",
24
- "memberFieldName": "auditLoggingStorePath"
25
- },
26
- {
27
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_sightEngineApiUser",
28
- "memberFieldName": "sightEngineApiUser"
29
- },
30
- {
31
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_sightEngineApiSecret",
32
- "memberFieldName": "sightEngineApiSecret"
33
- },
34
- {
35
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_imagesEnabled",
36
- "memberFieldName": "imagesEnabled"
37
- },
38
- {
39
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_textEnabled",
40
- "memberFieldName": "textEnabled"
41
- },
42
- {
43
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_videoEnabled",
44
- "memberFieldName": "videoEnabled"
45
- },
46
- {
47
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_imageNudityThreshold",
48
- "memberFieldName": "imageNudityThreshold"
49
- },
50
- {
51
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_textSexualThreshold",
52
- "memberFieldName": "textSexualThreshold"
53
- },
54
- {
55
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_textToxicThreshold",
56
- "memberFieldName": "textToxicThreshold"
57
- },
58
- {
59
- "@id": "ksmp:dist/ModerationConfig.jsonld#ModerationConfig__member_videoNudityThreshold",
60
- "memberFieldName": "videoNudityThreshold"
61
- }
62
- ],
63
- "constructorArguments": []
64
- }
65
- ]
66
- }
@@ -1,13 +0,0 @@
1
- import type { Operation } from '@solid/community-server';
2
- import type { ModerationConfig } from './ModerationConfig';
3
- export declare class ModerationMixin {
4
- protected readonly logger: import("@solid/community-server").Logger;
5
- private readonly moderationConfig;
6
- private readonly moderationStore?;
7
- constructor(moderationConfig: ModerationConfig);
8
- moderateContent(operation: Operation): Promise<void>;
9
- private moderateImageContent;
10
- private moderateTextContent;
11
- private moderateVideoContent;
12
- }
13
- //# sourceMappingURL=ModerationMixin.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ModerationMixin.d.ts","sourceRoot":"","sources":["../src/ModerationMixin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,qBAAa,eAAe;IAC1B,SAAS,CAAC,QAAQ,CAAC,MAAM,2CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAkB;gBAEhC,gBAAgB,EAAE,gBAAgB;IAOxC,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;YAenD,oBAAoB;YAwCpB,mBAAmB;YAuCnB,oBAAoB;CAsCnC"}
@@ -1,136 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ModerationMixin = void 0;
4
- const node_stream_1 = require("node:stream");
5
- const node_fs_1 = require("node:fs");
6
- const community_server_1 = require("@solid/community-server");
7
- const SightEngineProvider_1 = require("./providers/SightEngineProvider");
8
- const ModerationStore_1 = require("./ModerationStore");
9
- class ModerationMixin {
10
- constructor(moderationConfig) {
11
- this.logger = (0, community_server_1.getLoggerFor)(this);
12
- this.moderationConfig = moderationConfig;
13
- this.moderationStore = moderationConfig.auditLoggingEnabled ?
14
- new ModerationStore_1.ModerationStore(moderationConfig.auditLoggingStorePath) :
15
- undefined;
16
- }
17
- async moderateContent(operation) {
18
- if (!this.moderationConfig.enabled || !operation.body?.data) {
19
- return;
20
- }
21
- const contentType = operation.body.metadata.contentType;
22
- if (contentType?.startsWith('image/') && this.moderationConfig.imagesEnabled) {
23
- await this.moderateImageContent(operation);
24
- }
25
- else if (contentType?.startsWith('text/') && this.moderationConfig.textEnabled) {
26
- await this.moderateTextContent(operation);
27
- }
28
- else if (contentType?.startsWith('video/') && this.moderationConfig.videoEnabled) {
29
- await this.moderateVideoContent(operation);
30
- }
31
- }
32
- async moderateImageContent(operation) {
33
- const chunks = [];
34
- for await (const chunk of operation.body.data) {
35
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
36
- }
37
- const buffer = Buffer.concat(chunks);
38
- operation.body.data = (0, community_server_1.guardStream)(node_stream_1.Readable.from(buffer));
39
- const tempFile = `/tmp/moderation_${Date.now()}.jpg`;
40
- await node_fs_1.promises.writeFile(tempFile, buffer);
41
- try {
42
- const client = new SightEngineProvider_1.SightEngineProvider(this.moderationConfig.sightEngineApiUser, this.moderationConfig.sightEngineApiSecret);
43
- const result = await client.analyzeImage(tempFile);
44
- this.logger.info(`MODERATION: Image analysis result - nudity score: ${result.nudity?.raw}, threshold: ${this.moderationConfig.imageNudityThreshold}`);
45
- if (result.nudity?.raw && result.nudity.raw > this.moderationConfig.imageNudityThreshold) {
46
- if (this.moderationStore) {
47
- await this.moderationStore.recordViolation({
48
- contentType: 'image',
49
- resourcePath: operation.target.path,
50
- violations: [{ model: 'nudity', score: result.nudity.raw, threshold: this.moderationConfig.imageNudityThreshold }],
51
- contentSize: buffer.length,
52
- });
53
- }
54
- throw new community_server_1.ForbiddenHttpError('Upload blocked: Content violates community guidelines');
55
- }
56
- }
57
- catch (error) {
58
- if (error instanceof community_server_1.ForbiddenHttpError) {
59
- throw error;
60
- }
61
- this.logger.warn(`MODERATION: Image check failed (fail-open): ${error}`);
62
- }
63
- finally {
64
- await node_fs_1.promises.unlink(tempFile).catch(() => { });
65
- }
66
- }
67
- async moderateTextContent(operation) {
68
- const chunks = [];
69
- for await (const chunk of operation.body.data) {
70
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
71
- }
72
- const buffer = Buffer.concat(chunks);
73
- const text = buffer.toString('utf8');
74
- operation.body.data = (0, community_server_1.guardStream)(node_stream_1.Readable.from(buffer));
75
- if (!text?.trim()) {
76
- return;
77
- }
78
- try {
79
- const client = new SightEngineProvider_1.SightEngineProvider(this.moderationConfig.sightEngineApiUser, this.moderationConfig.sightEngineApiSecret);
80
- const result = await client.analyzeText(text);
81
- if (result.sexual > this.moderationConfig.textSexualThreshold || result.toxic > this.moderationConfig.textToxicThreshold) {
82
- if (this.moderationStore) {
83
- await this.moderationStore.recordViolation({
84
- contentType: 'text',
85
- resourcePath: operation.target.path,
86
- violations: [{ model: 'text', score: Math.max(result.sexual, result.toxic), threshold: Math.min(this.moderationConfig.textSexualThreshold, this.moderationConfig.textToxicThreshold) }],
87
- contentSize: buffer.length,
88
- });
89
- }
90
- throw new community_server_1.ForbiddenHttpError('Upload blocked: Content violates community guidelines');
91
- }
92
- }
93
- catch (error) {
94
- if (error instanceof community_server_1.ForbiddenHttpError) {
95
- throw error;
96
- }
97
- this.logger.warn(`MODERATION: Text check failed (fail-open): ${error}`);
98
- }
99
- }
100
- async moderateVideoContent(operation) {
101
- const chunks = [];
102
- for await (const chunk of operation.body.data) {
103
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
104
- }
105
- const buffer = Buffer.concat(chunks);
106
- operation.body.data = (0, community_server_1.guardStream)(node_stream_1.Readable.from(buffer));
107
- const tempFile = `/tmp/moderation_${Date.now()}.mp4`;
108
- await node_fs_1.promises.writeFile(tempFile, buffer);
109
- try {
110
- const client = new SightEngineProvider_1.SightEngineProvider(this.moderationConfig.sightEngineApiUser, this.moderationConfig.sightEngineApiSecret);
111
- const result = await client.analyzeVideo(tempFile);
112
- if (result.nudity?.raw && result.nudity.raw > this.moderationConfig.videoNudityThreshold) {
113
- if (this.moderationStore) {
114
- await this.moderationStore.recordViolation({
115
- contentType: 'video',
116
- resourcePath: operation.target.path,
117
- violations: [{ model: 'nudity', score: result.nudity.raw, threshold: this.moderationConfig.videoNudityThreshold }],
118
- contentSize: buffer.length,
119
- });
120
- }
121
- throw new community_server_1.ForbiddenHttpError('Upload blocked: Content violates community guidelines');
122
- }
123
- }
124
- catch (error) {
125
- if (error instanceof community_server_1.ForbiddenHttpError) {
126
- throw error;
127
- }
128
- this.logger.warn(`MODERATION: Video check failed (fail-open): ${error}`);
129
- }
130
- finally {
131
- await node_fs_1.promises.unlink(tempFile).catch(() => { });
132
- }
133
- }
134
- }
135
- exports.ModerationMixin = ModerationMixin;
136
- //# sourceMappingURL=ModerationMixin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ModerationMixin.js","sourceRoot":"","sources":["../src/ModerationMixin.ts"],"names":[],"mappings":"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"}