palaryn 0.4.17 → 0.4.18
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/src/dlp/index.d.ts +1 -0
- package/dist/src/dlp/index.d.ts.map +1 -1
- package/dist/src/dlp/index.js +3 -1
- package/dist/src/dlp/index.js.map +1 -1
- package/dist/src/dlp/nemo-backend.d.ts +28 -0
- package/dist/src/dlp/nemo-backend.d.ts.map +1 -0
- package/dist/src/dlp/nemo-backend.js +103 -0
- package/dist/src/dlp/nemo-backend.js.map +1 -0
- package/dist/src/saas/routes.d.ts.map +1 -1
- package/dist/src/saas/routes.js +23 -0
- package/dist/src/saas/routes.js.map +1 -1
- package/dist/src/server/gateway.d.ts.map +1 -1
- package/dist/src/server/gateway.js +7 -0
- package/dist/src/server/gateway.js.map +1 -1
- package/dist/src/types/config.d.ts +6 -0
- package/dist/src/types/config.d.ts.map +1 -1
- package/dist/tests/unit/nemo-backend.test.d.ts +2 -0
- package/dist/tests/unit/nemo-backend.test.d.ts.map +1 -0
- package/dist/tests/unit/nemo-backend.test.js +81 -0
- package/dist/tests/unit/nemo-backend.test.js.map +1 -0
- package/package.json +1 -1
- package/src/dlp/index.ts +1 -0
- package/src/dlp/nemo-backend.ts +117 -0
- package/src/saas/routes.ts +27 -0
- package/src/server/gateway.ts +7 -0
- package/src/types/config.ts +6 -0
package/dist/src/dlp/index.d.ts
CHANGED
|
@@ -7,5 +7,6 @@ export { CompositeDLPScanner } from './composite-scanner';
|
|
|
7
7
|
export { PROMPT_INJECTION_PATTERNS, OUTPUT_INJECTION_PATTERNS } from './prompt-injection-patterns';
|
|
8
8
|
export { PromptInjectionBackend, PromptInjectionConfig } from './prompt-injection-backend';
|
|
9
9
|
export { ExfiltrationDetectionBackend } from './exfiltration-backend';
|
|
10
|
+
export { NemoGuardrailsBackend, NemoGuardrailsConfig } from './nemo-backend';
|
|
10
11
|
export { normalizeText, normalizeLeetspeak, decodeROT13, tryDecodeROT13, ZERO_WIDTH_REGEX, HOMOGLYPH_MAP, LEETSPEAK_MAP } from './text-normalizer';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dlp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dlp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/src/dlp/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LEETSPEAK_MAP = exports.HOMOGLYPH_MAP = exports.ZERO_WIDTH_REGEX = exports.tryDecodeROT13 = exports.decodeROT13 = exports.normalizeLeetspeak = exports.normalizeText = exports.ExfiltrationDetectionBackend = exports.PromptInjectionBackend = exports.OUTPUT_INJECTION_PATTERNS = exports.PROMPT_INJECTION_PATTERNS = exports.CompositeDLPScanner = exports.TruffleHogBackend = exports.RegexDLPBackend = exports.PII_PATTERNS = exports.SECRET_PATTERNS = exports.DLPScanner = void 0;
|
|
3
|
+
exports.LEETSPEAK_MAP = exports.HOMOGLYPH_MAP = exports.ZERO_WIDTH_REGEX = exports.tryDecodeROT13 = exports.decodeROT13 = exports.normalizeLeetspeak = exports.normalizeText = exports.NemoGuardrailsBackend = exports.ExfiltrationDetectionBackend = exports.PromptInjectionBackend = exports.OUTPUT_INJECTION_PATTERNS = exports.PROMPT_INJECTION_PATTERNS = exports.CompositeDLPScanner = exports.TruffleHogBackend = exports.RegexDLPBackend = exports.PII_PATTERNS = exports.SECRET_PATTERNS = exports.DLPScanner = void 0;
|
|
4
4
|
var scanner_1 = require("./scanner");
|
|
5
5
|
Object.defineProperty(exports, "DLPScanner", { enumerable: true, get: function () { return scanner_1.DLPScanner; } });
|
|
6
6
|
var patterns_1 = require("./patterns");
|
|
@@ -19,6 +19,8 @@ var prompt_injection_backend_1 = require("./prompt-injection-backend");
|
|
|
19
19
|
Object.defineProperty(exports, "PromptInjectionBackend", { enumerable: true, get: function () { return prompt_injection_backend_1.PromptInjectionBackend; } });
|
|
20
20
|
var exfiltration_backend_1 = require("./exfiltration-backend");
|
|
21
21
|
Object.defineProperty(exports, "ExfiltrationDetectionBackend", { enumerable: true, get: function () { return exfiltration_backend_1.ExfiltrationDetectionBackend; } });
|
|
22
|
+
var nemo_backend_1 = require("./nemo-backend");
|
|
23
|
+
Object.defineProperty(exports, "NemoGuardrailsBackend", { enumerable: true, get: function () { return nemo_backend_1.NemoGuardrailsBackend; } });
|
|
22
24
|
var text_normalizer_1 = require("./text-normalizer");
|
|
23
25
|
Object.defineProperty(exports, "normalizeText", { enumerable: true, get: function () { return text_normalizer_1.normalizeText; } });
|
|
24
26
|
Object.defineProperty(exports, "normalizeLeetspeak", { enumerable: true, get: function () { return text_normalizer_1.normalizeLeetspeak; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dlp/index.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AAA9B,qGAAA,UAAU,OAAA;AAEnB,uCAAuE;AAAlD,2GAAA,eAAe,OAAA;AAAE,wGAAA,YAAY,OAAA;AAClD,iDAAsE;AAA7D,gHAAA,eAAe,OAAA;AACxB,2DAA2E;AAAlE,uHAAA,iBAAiB,OAAA;AAC1B,yDAA0D;AAAjD,wHAAA,mBAAmB,OAAA;AAC5B,yEAAmG;AAA1F,sIAAA,yBAAyB,OAAA;AAAE,sIAAA,yBAAyB,OAAA;AAC7D,uEAA2F;AAAlF,kIAAA,sBAAsB,OAAA;AAC/B,+DAAsE;AAA7D,oIAAA,4BAA4B,OAAA;AACrC,qDAAmJ;AAA1I,gHAAA,aAAa,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AAAE,8GAAA,WAAW,OAAA;AAAE,iHAAA,cAAc,OAAA;AAAE,mHAAA,gBAAgB,OAAA;AAAE,gHAAA,aAAa,OAAA;AAAE,gHAAA,aAAa,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dlp/index.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AAA9B,qGAAA,UAAU,OAAA;AAEnB,uCAAuE;AAAlD,2GAAA,eAAe,OAAA;AAAE,wGAAA,YAAY,OAAA;AAClD,iDAAsE;AAA7D,gHAAA,eAAe,OAAA;AACxB,2DAA2E;AAAlE,uHAAA,iBAAiB,OAAA;AAC1B,yDAA0D;AAAjD,wHAAA,mBAAmB,OAAA;AAC5B,yEAAmG;AAA1F,sIAAA,yBAAyB,OAAA;AAAE,sIAAA,yBAAyB,OAAA;AAC7D,uEAA2F;AAAlF,kIAAA,sBAAsB,OAAA;AAC/B,+DAAsE;AAA7D,oIAAA,4BAA4B,OAAA;AACrC,+CAA6E;AAApE,qHAAA,qBAAqB,OAAA;AAC9B,qDAAmJ;AAA1I,gHAAA,aAAa,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AAAE,8GAAA,WAAW,OAAA;AAAE,iHAAA,cAAc,OAAA;AAAE,mHAAA,gBAAgB,OAAA;AAAE,gHAAA,aAAa,OAAA;AAAE,gHAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DLPBackend, DLPDetection } from './interfaces';
|
|
2
|
+
export interface NemoGuardrailsConfig {
|
|
3
|
+
/** NeMo Guardrails API URL (e.g. 'http://nemo:8000'). */
|
|
4
|
+
api_url: string;
|
|
5
|
+
/** Request timeout in milliseconds. Defaults to 5000. */
|
|
6
|
+
timeout_ms?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* DLP backend that delegates content safety classification to NeMo Guardrails.
|
|
10
|
+
*
|
|
11
|
+
* NeMo Guardrails (NVIDIA) provides LLM-based detection of prompt injection,
|
|
12
|
+
* jailbreaks, and harmful content — catching semantic attacks that regex misses.
|
|
13
|
+
*
|
|
14
|
+
* Uses synchronous curl via execFileSync (same pattern as TruffleHogBackend)
|
|
15
|
+
* to comply with the synchronous DLPBackend interface.
|
|
16
|
+
*
|
|
17
|
+
* Graceful degradation: returns [] on timeout, connection error, or parse failure.
|
|
18
|
+
*/
|
|
19
|
+
export declare class NemoGuardrailsBackend implements DLPBackend {
|
|
20
|
+
readonly name = "nemo_guardrails";
|
|
21
|
+
private readonly apiUrl;
|
|
22
|
+
private readonly timeoutMs;
|
|
23
|
+
constructor(config: NemoGuardrailsConfig);
|
|
24
|
+
scanString(value: string): DLPDetection[];
|
|
25
|
+
private parseResponse;
|
|
26
|
+
private mapSeverity;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=nemo-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nemo-backend.d.ts","sourceRoot":"","sources":["../../../src/dlp/nemo-backend.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGxD,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,YAAW,UAAU;IACtD,QAAQ,CAAC,IAAI,qBAAqB;IAElC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE,oBAAoB;IAKxC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;IA8BzC,OAAO,CAAC,aAAa;IA0CrB,OAAO,CAAC,WAAW;CAWpB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NemoGuardrailsBackend = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
/**
|
|
6
|
+
* DLP backend that delegates content safety classification to NeMo Guardrails.
|
|
7
|
+
*
|
|
8
|
+
* NeMo Guardrails (NVIDIA) provides LLM-based detection of prompt injection,
|
|
9
|
+
* jailbreaks, and harmful content — catching semantic attacks that regex misses.
|
|
10
|
+
*
|
|
11
|
+
* Uses synchronous curl via execFileSync (same pattern as TruffleHogBackend)
|
|
12
|
+
* to comply with the synchronous DLPBackend interface.
|
|
13
|
+
*
|
|
14
|
+
* Graceful degradation: returns [] on timeout, connection error, or parse failure.
|
|
15
|
+
*/
|
|
16
|
+
class NemoGuardrailsBackend {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.name = 'nemo_guardrails';
|
|
19
|
+
this.apiUrl = config.api_url.replace(/\/+$/, '');
|
|
20
|
+
this.timeoutMs = config.timeout_ms ?? 5000;
|
|
21
|
+
}
|
|
22
|
+
scanString(value) {
|
|
23
|
+
if (!value || value.length < 5)
|
|
24
|
+
return [];
|
|
25
|
+
try {
|
|
26
|
+
const payload = JSON.stringify({
|
|
27
|
+
messages: [{ role: 'user', content: value }],
|
|
28
|
+
});
|
|
29
|
+
const stdout = (0, child_process_1.execFileSync)('curl', [
|
|
30
|
+
'-s',
|
|
31
|
+
'-X', 'POST',
|
|
32
|
+
`${this.apiUrl}/v1/guardrails/check`,
|
|
33
|
+
'-H', 'Content-Type: application/json',
|
|
34
|
+
'-d', payload,
|
|
35
|
+
'--max-time', String(Math.ceil(this.timeoutMs / 1000)),
|
|
36
|
+
'--connect-timeout', '2',
|
|
37
|
+
], {
|
|
38
|
+
timeout: this.timeoutMs + 1000,
|
|
39
|
+
encoding: 'utf-8',
|
|
40
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
41
|
+
});
|
|
42
|
+
return this.parseResponse(stdout, value);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
console.warn(`[NemoGuardrailsBackend] scan failed: ${message}`);
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
parseResponse(raw, originalValue) {
|
|
51
|
+
const detections = [];
|
|
52
|
+
try {
|
|
53
|
+
const data = JSON.parse(raw);
|
|
54
|
+
// NeMo Guardrails returns rails/violations in response
|
|
55
|
+
const rails = data.rails ?? data.violations ?? data.results ?? [];
|
|
56
|
+
const blocked = data.blocked ?? false;
|
|
57
|
+
if (Array.isArray(rails)) {
|
|
58
|
+
for (const rail of rails) {
|
|
59
|
+
const railName = rail.name ?? rail.type ?? rail.rail ?? 'unknown';
|
|
60
|
+
const severity = this.mapSeverity(rail.severity ?? rail.score ?? (blocked ? 'high' : 'medium'));
|
|
61
|
+
detections.push({
|
|
62
|
+
pattern_name: `nemo:${railName}`,
|
|
63
|
+
severity,
|
|
64
|
+
match: originalValue.slice(0, 200),
|
|
65
|
+
start: 0,
|
|
66
|
+
end: originalValue.length,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// If response indicates blocked but no specific rails listed
|
|
71
|
+
if (blocked && detections.length === 0) {
|
|
72
|
+
detections.push({
|
|
73
|
+
pattern_name: 'nemo:content_blocked',
|
|
74
|
+
severity: 'high',
|
|
75
|
+
match: originalValue.slice(0, 200),
|
|
76
|
+
start: 0,
|
|
77
|
+
end: originalValue.length,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
console.warn('[NemoGuardrailsBackend] failed to parse response');
|
|
83
|
+
}
|
|
84
|
+
return detections;
|
|
85
|
+
}
|
|
86
|
+
mapSeverity(level) {
|
|
87
|
+
if (typeof level === 'number') {
|
|
88
|
+
if (level >= 0.8)
|
|
89
|
+
return 'high';
|
|
90
|
+
if (level >= 0.5)
|
|
91
|
+
return 'medium';
|
|
92
|
+
return 'low';
|
|
93
|
+
}
|
|
94
|
+
const lower = String(level).toLowerCase();
|
|
95
|
+
if (lower === 'high' || lower === 'critical')
|
|
96
|
+
return 'high';
|
|
97
|
+
if (lower === 'medium' || lower === 'moderate')
|
|
98
|
+
return 'medium';
|
|
99
|
+
return 'low';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.NemoGuardrailsBackend = NemoGuardrailsBackend;
|
|
103
|
+
//# sourceMappingURL=nemo-backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nemo-backend.js","sourceRoot":"","sources":["../../../src/dlp/nemo-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/saas/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,SAAS,EAAE,cAAc,EAAE,oBAAoB,EAC/C,eAAe,EAAE,YAAY,EAAE,WAAW,EAC1C,oBAAoB,EAAE,iBAAiB,EAExC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAwB5C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAmBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/saas/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,SAAS,EAAE,cAAc,EAAE,oBAAoB,EAC/C,eAAe,EAAE,YAAY,EAAE,WAAW,EAC1C,oBAAoB,EAAE,iBAAiB,EAExC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAwB5C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAmBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAq8E5D"}
|
package/dist/src/saas/routes.js
CHANGED
|
@@ -206,6 +206,29 @@ function createSaaSRouter(deps) {
|
|
|
206
206
|
const workspace = workspaceStore.getById(workspaceId);
|
|
207
207
|
res.status(201).json(workspace);
|
|
208
208
|
});
|
|
209
|
+
router.delete('/workspaces/:id', (req, res) => {
|
|
210
|
+
if (!requireSession(req, res))
|
|
211
|
+
return;
|
|
212
|
+
const user = req.sessionUser;
|
|
213
|
+
const workspaceId = param(req, 'id');
|
|
214
|
+
const membership = workspaceMemberStore.getByWorkspaceAndUser(workspaceId, user.id);
|
|
215
|
+
if (!membership || membership.role !== 'owner') {
|
|
216
|
+
res.status(403).json({ error: 'Only workspace owner can delete a workspace' });
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const workspace = workspaceStore.getById(workspaceId);
|
|
220
|
+
if (!workspace) {
|
|
221
|
+
res.status(404).json({ error: 'Workspace not found' });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// Remove members, then workspace
|
|
225
|
+
const members = workspaceMemberStore.getByWorkspace(workspaceId);
|
|
226
|
+
for (const m of members) {
|
|
227
|
+
workspaceMemberStore.delete(m.id);
|
|
228
|
+
}
|
|
229
|
+
workspaceStore.delete(workspaceId);
|
|
230
|
+
res.json({ deleted: true, id: workspaceId });
|
|
231
|
+
});
|
|
209
232
|
router.get('/workspaces/:id', (req, res) => {
|
|
210
233
|
if (!requireSession(req, res))
|
|
211
234
|
return;
|