@lucid-fdn/plugin-policy 0.1.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 (49) hide show
  1. package/dist/__tests__/audit.test.d.ts +2 -0
  2. package/dist/__tests__/audit.test.d.ts.map +1 -0
  3. package/dist/__tests__/audit.test.js +54 -0
  4. package/dist/__tests__/audit.test.js.map +1 -0
  5. package/dist/__tests__/manifest.test.d.ts +2 -0
  6. package/dist/__tests__/manifest.test.d.ts.map +1 -0
  7. package/dist/__tests__/manifest.test.js +83 -0
  8. package/dist/__tests__/manifest.test.js.map +1 -0
  9. package/dist/__tests__/policy.test.d.ts +2 -0
  10. package/dist/__tests__/policy.test.d.ts.map +1 -0
  11. package/dist/__tests__/policy.test.js +71 -0
  12. package/dist/__tests__/policy.test.js.map +1 -0
  13. package/dist/__tests__/registry.test.d.ts +2 -0
  14. package/dist/__tests__/registry.test.d.ts.map +1 -0
  15. package/dist/__tests__/registry.test.js +65 -0
  16. package/dist/__tests__/registry.test.js.map +1 -0
  17. package/dist/__tests__/router.test.d.ts +2 -0
  18. package/dist/__tests__/router.test.d.ts.map +1 -0
  19. package/dist/__tests__/router.test.js +80 -0
  20. package/dist/__tests__/router.test.js.map +1 -0
  21. package/dist/audit.d.ts +20 -0
  22. package/dist/audit.d.ts.map +1 -0
  23. package/dist/audit.js +46 -0
  24. package/dist/audit.js.map +1 -0
  25. package/dist/index.d.ts +17 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +20 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/manifest.d.ts +13 -0
  30. package/dist/manifest.d.ts.map +1 -0
  31. package/dist/manifest.js +56 -0
  32. package/dist/manifest.js.map +1 -0
  33. package/dist/policy.d.ts +23 -0
  34. package/dist/policy.d.ts.map +1 -0
  35. package/dist/policy.js +65 -0
  36. package/dist/policy.js.map +1 -0
  37. package/dist/registry.d.ts +24 -0
  38. package/dist/registry.d.ts.map +1 -0
  39. package/dist/registry.js +52 -0
  40. package/dist/registry.js.map +1 -0
  41. package/dist/router.d.ts +28 -0
  42. package/dist/router.d.ts.map +1 -0
  43. package/dist/router.js +68 -0
  44. package/dist/router.js.map +1 -0
  45. package/dist/types.d.ts +82 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +8 -0
  48. package/dist/types.js.map +1 -0
  49. package/package.json +30 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=audit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { AuditEmitter } from '../audit.js';
3
+ const event = {
4
+ timestamp: new Date().toISOString(),
5
+ pluginSlug: 'lucid-seo',
6
+ toolName: 'research_keywords',
7
+ executionPath: 'embedded',
8
+ durationMs: 5,
9
+ success: true,
10
+ };
11
+ describe('AuditEmitter', () => {
12
+ it('emits events to registered handlers', () => {
13
+ const emitter = new AuditEmitter();
14
+ const handler = vi.fn();
15
+ emitter.on(handler);
16
+ emitter.emit(event);
17
+ expect(handler).toHaveBeenCalledWith(event);
18
+ });
19
+ it('supports multiple handlers', () => {
20
+ const emitter = new AuditEmitter();
21
+ const h1 = vi.fn();
22
+ const h2 = vi.fn();
23
+ emitter.on(h1);
24
+ emitter.on(h2);
25
+ emitter.emit(event);
26
+ expect(h1).toHaveBeenCalledOnce();
27
+ expect(h2).toHaveBeenCalledOnce();
28
+ });
29
+ it('supports unsubscribe', () => {
30
+ const emitter = new AuditEmitter();
31
+ const handler = vi.fn();
32
+ const unsub = emitter.on(handler);
33
+ unsub();
34
+ emitter.emit(event);
35
+ expect(handler).not.toHaveBeenCalled();
36
+ });
37
+ it('does not throw when handler throws (fire-and-forget)', () => {
38
+ const emitter = new AuditEmitter();
39
+ emitter.on(() => { throw new Error('boom'); });
40
+ const good = vi.fn();
41
+ emitter.on(good);
42
+ expect(() => emitter.emit(event)).not.toThrow();
43
+ expect(good).toHaveBeenCalled();
44
+ });
45
+ it('clears all handlers', () => {
46
+ const emitter = new AuditEmitter();
47
+ emitter.on(vi.fn());
48
+ emitter.on(vi.fn());
49
+ expect(emitter.handlerCount).toBe(2);
50
+ emitter.clear();
51
+ expect(emitter.handlerCount).toBe(0);
52
+ });
53
+ });
54
+ //# sourceMappingURL=audit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.test.js","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=manifest.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/manifest.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { normalizePluginRow } from '../manifest.js';
3
+ describe('normalizePluginRow', () => {
4
+ it('transforms snake_case DB row to camelCase ActivatedPlugin', () => {
5
+ const row = {
6
+ plugin_slug: 'lucid-seo',
7
+ plugin_name: 'Lucid SEO',
8
+ tool_manifest: [{ name: 'research', description: 'Research', parameters: {} }],
9
+ enabled_tools: null,
10
+ plugin_config: { depth: 3 },
11
+ org_config: { orgKey: 'val' },
12
+ source: 'first-party',
13
+ mcpgate_server_id: null,
14
+ kind: 'plugin',
15
+ transport: 'embedded',
16
+ trust_level: 'internal',
17
+ execution_mode: 'in_process',
18
+ auth_type: 'none',
19
+ auth_provider: null,
20
+ };
21
+ const result = normalizePluginRow(row);
22
+ expect(result.slug).toBe('lucid-seo');
23
+ expect(result.name).toBe('Lucid SEO');
24
+ expect(result.tools).toHaveLength(1);
25
+ expect(result.config).toEqual({ orgKey: 'val', depth: 3 });
26
+ expect(result.kind).toBe('plugin');
27
+ expect(result.transport).toBe('embedded');
28
+ expect(result.trustLevel).toBe('internal');
29
+ expect(result.executionMode).toBe('in_process');
30
+ expect(result.authType).toBe('none');
31
+ });
32
+ it('filters tools by enabled_tools', () => {
33
+ const row = {
34
+ plugin_slug: 'lucid-seo',
35
+ plugin_name: 'SEO',
36
+ tool_manifest: [
37
+ { name: 'research', description: 'A', parameters: {} },
38
+ { name: 'analyze', description: 'B', parameters: {} },
39
+ ],
40
+ enabled_tools: ['research'],
41
+ plugin_config: {},
42
+ org_config: {},
43
+ source: 'first-party',
44
+ };
45
+ const result = normalizePluginRow(row);
46
+ expect(result.tools).toHaveLength(1);
47
+ expect(result.tools[0].name).toBe('research');
48
+ });
49
+ it('handles missing unified fields (old format)', () => {
50
+ const row = {
51
+ plugin_slug: 'old-plugin',
52
+ plugin_name: 'Old Plugin',
53
+ manifest_snapshot: [{ name: 'tool1', description: 'T', parameters: {} }],
54
+ enabled_tools: null,
55
+ config: { key: 'val' },
56
+ source: 'mcpgate',
57
+ mcpgate_server_id: 'server-1',
58
+ };
59
+ const result = normalizePluginRow(row);
60
+ expect(result.slug).toBe('old-plugin');
61
+ expect(result.tools).toHaveLength(1);
62
+ expect(result.mcpgateServerId).toBe('server-1');
63
+ // Missing UCA fields get safe defaults (least-privileged posture)
64
+ expect(result.kind).toBe('plugin');
65
+ expect(result.transport).toBe('remote-mcp');
66
+ expect(result.trustLevel).toBe('community');
67
+ expect(result.executionMode).toBe('gateway');
68
+ });
69
+ it('merges org config and plugin config (plugin wins)', () => {
70
+ const row = {
71
+ plugin_slug: 'test',
72
+ plugin_name: 'Test',
73
+ tool_manifest: [],
74
+ enabled_tools: null,
75
+ org_config: { shared: 'org', orgOnly: 'yes' },
76
+ plugin_config: { shared: 'plugin', pluginOnly: 'yes' },
77
+ source: 'first-party',
78
+ };
79
+ const result = normalizePluginRow(row);
80
+ expect(result.config).toEqual({ shared: 'plugin', orgOnly: 'yes', pluginOnly: 'yes' });
81
+ });
82
+ });
83
+ //# sourceMappingURL=manifest.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.test.js","sourceRoot":"","sources":["../../src/__tests__/manifest.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=policy.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { resolvePolicy } from '../policy.js';
3
+ describe('resolvePolicy', () => {
4
+ it('blocks plugins on the admin blocklist', () => {
5
+ const result = resolvePolicy({ slug: 'bad-plugin', trustLevel: 'internal', executionMode: 'in_process' }, { blockedPlugins: ['bad-plugin'] });
6
+ expect(result.decision).toBe('block');
7
+ expect(result.reason).toContain('blocklist');
8
+ });
9
+ it('forces gateway when forceGateway is set', () => {
10
+ const result = resolvePolicy({ slug: 'lucid-seo', trustLevel: 'internal', executionMode: 'in_process' }, { forceGateway: true });
11
+ expect(result.decision).toBe('allow_gateway');
12
+ expect(result.effectiveMode).toBe('gateway');
13
+ });
14
+ it('allows internal plugins in-process', () => {
15
+ const result = resolvePolicy({
16
+ slug: 'lucid-seo',
17
+ trustLevel: 'internal',
18
+ executionMode: 'in_process',
19
+ });
20
+ expect(result.decision).toBe('allow_in_process');
21
+ expect(result.effectiveMode).toBe('in_process');
22
+ });
23
+ it('allows verified plugins in-process', () => {
24
+ const result = resolvePolicy({
25
+ slug: 'partner-plugin',
26
+ trustLevel: 'verified',
27
+ executionMode: 'in_process',
28
+ });
29
+ expect(result.decision).toBe('allow_in_process');
30
+ expect(result.effectiveMode).toBe('in_process');
31
+ });
32
+ it('forces community plugins to gateway even if in_process requested', () => {
33
+ const result = resolvePolicy({
34
+ slug: 'community-plugin',
35
+ trustLevel: 'community',
36
+ executionMode: 'in_process',
37
+ });
38
+ expect(result.decision).toBe('allow_gateway');
39
+ expect(result.effectiveMode).toBe('gateway');
40
+ expect(result.reason).toContain('gateway-only');
41
+ });
42
+ it('allows community plugins in gateway mode', () => {
43
+ const result = resolvePolicy({
44
+ slug: 'community-plugin',
45
+ trustLevel: 'community',
46
+ executionMode: 'gateway',
47
+ });
48
+ expect(result.decision).toBe('allow_gateway');
49
+ expect(result.effectiveMode).toBe('gateway');
50
+ });
51
+ it('allows internal plugins in gateway mode when requested', () => {
52
+ const result = resolvePolicy({
53
+ slug: 'lucid-seo',
54
+ trustLevel: 'internal',
55
+ executionMode: 'gateway',
56
+ });
57
+ expect(result.decision).toBe('allow_gateway');
58
+ expect(result.effectiveMode).toBe('gateway');
59
+ });
60
+ it('defaults undefined trustLevel to community (safe default)', () => {
61
+ const result = resolvePolicy({
62
+ slug: 'old-plugin',
63
+ trustLevel: undefined,
64
+ executionMode: undefined,
65
+ });
66
+ expect(result.decision).toBe('allow_gateway');
67
+ expect(result.effectiveMode).toBe('gateway');
68
+ expect(result.reason).toContain('gateway-only');
69
+ });
70
+ });
71
+ //# sourceMappingURL=policy.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.test.js","sourceRoot":"","sources":["../../src/__tests__/policy.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,MAAM,GAAG,aAAa,CAC1B,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,EAC3E,EAAE,cAAc,EAAE,CAAC,YAAY,CAAC,EAAE,CACnC,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,MAAM,GAAG,aAAa,CAC1B,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,EAC1E,EAAE,YAAY,EAAE,IAAI,EAAE,CACvB,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,IAAI,EAAE,WAAW;YACjB,UAAU,EAAE,UAAU;YACtB,aAAa,EAAE,YAAY;SAC5B,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,IAAI,EAAE,gBAAgB;YACtB,UAAU,EAAE,UAAU;YACtB,aAAa,EAAE,YAAY;SAC5B,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,IAAI,EAAE,kBAAkB;YACxB,UAAU,EAAE,WAAW;YACvB,aAAa,EAAE,YAAY;SAC5B,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,IAAI,EAAE,kBAAkB;YACxB,UAAU,EAAE,WAAW;YACvB,aAAa,EAAE,SAAS;SACzB,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,IAAI,EAAE,WAAW;YACjB,UAAU,EAAE,UAAU;YACtB,aAAa,EAAE,SAAS;SACzB,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,IAAI,EAAE,YAAY;YAClB,UAAU,EAAE,SAAmC;YAC/C,aAAa,EAAE,SAAiC;SACjD,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { PluginRegistry } from '../registry.js';
3
+ const seoPlugin = {
4
+ slug: 'lucid-seo',
5
+ name: 'Lucid SEO',
6
+ tools: [
7
+ { name: 'research_keywords', description: 'Research keywords', parameters: {} },
8
+ { name: 'analyze_serp', description: 'Analyze SERP', parameters: {} },
9
+ ],
10
+ config: {},
11
+ kind: 'plugin',
12
+ transport: 'embedded',
13
+ trustLevel: 'internal',
14
+ executionMode: 'in_process',
15
+ authType: 'none',
16
+ authProvider: null,
17
+ };
18
+ const slackPlugin = {
19
+ slug: 'slack',
20
+ name: 'Slack',
21
+ tools: [{ name: 'send_message', description: 'Send a Slack message', parameters: {} }],
22
+ config: {},
23
+ kind: 'integration',
24
+ transport: 'remote-mcp',
25
+ trustLevel: 'community',
26
+ executionMode: 'gateway',
27
+ authType: 'oauth2',
28
+ authProvider: 'slack',
29
+ };
30
+ describe('PluginRegistry', () => {
31
+ it('registers and retrieves plugins', () => {
32
+ const reg = new PluginRegistry([seoPlugin]);
33
+ expect(reg.get('lucid-seo')).toEqual(seoPlugin);
34
+ expect(reg.has('lucid-seo')).toBe(true);
35
+ expect(reg.has('missing')).toBe(false);
36
+ });
37
+ it('returns all plugins', () => {
38
+ const reg = new PluginRegistry([seoPlugin, slackPlugin]);
39
+ expect(reg.getAll()).toHaveLength(2);
40
+ expect(reg.size).toBe(2);
41
+ });
42
+ it('resolves wire tool names with double underscore', () => {
43
+ const reg = new PluginRegistry([seoPlugin]);
44
+ const resolved = reg.resolveWireToolName('lucid-seo__research_keywords');
45
+ expect(resolved?.plugin.slug).toBe('lucid-seo');
46
+ expect(resolved?.tool.name).toBe('research_keywords');
47
+ });
48
+ it('resolves wire tool names with underscore slug (sanitized)', () => {
49
+ const reg = new PluginRegistry([seoPlugin]);
50
+ // Wire names replace hyphens with underscores
51
+ const resolved = reg.resolveWireToolName('lucid_seo__research_keywords');
52
+ expect(resolved?.plugin.slug).toBe('lucid-seo');
53
+ expect(resolved?.tool.name).toBe('research_keywords');
54
+ });
55
+ it('returns null for unknown wire tool names', () => {
56
+ const reg = new PluginRegistry([seoPlugin]);
57
+ expect(reg.resolveWireToolName('unknown__tool')).toBeNull();
58
+ expect(reg.resolveWireToolName('no-separator')).toBeNull();
59
+ });
60
+ it('returns null for known plugin but unknown tool', () => {
61
+ const reg = new PluginRegistry([seoPlugin]);
62
+ expect(reg.resolveWireToolName('lucid-seo__nonexistent_tool')).toBeNull();
63
+ });
64
+ });
65
+ //# sourceMappingURL=registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=router.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/router.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,80 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { routePlugin } from '../router.js';
3
+ function makePlugin(overrides = {}) {
4
+ return {
5
+ slug: 'test-plugin',
6
+ name: 'Test Plugin',
7
+ tools: [],
8
+ config: {},
9
+ kind: 'plugin',
10
+ transport: 'embedded',
11
+ trustLevel: 'internal',
12
+ executionMode: 'in_process',
13
+ authType: 'none',
14
+ authProvider: null,
15
+ ...overrides,
16
+ };
17
+ }
18
+ describe('routePlugin', () => {
19
+ it('routes embedded + internal to embedded path', () => {
20
+ const result = routePlugin(makePlugin({
21
+ transport: 'embedded',
22
+ trustLevel: 'internal',
23
+ executionMode: 'in_process',
24
+ }));
25
+ expect(result.path).toBe('embedded');
26
+ });
27
+ it('routes embedded + community to gateway-mcp (policy override)', () => {
28
+ const result = routePlugin(makePlugin({
29
+ transport: 'embedded',
30
+ trustLevel: 'community',
31
+ executionMode: 'in_process',
32
+ }));
33
+ expect(result.path).toBe('gateway-mcp');
34
+ expect(result.policy.reason).toContain('gateway-only');
35
+ });
36
+ it('routes remote-mcp to gateway-mcp', () => {
37
+ const result = routePlugin(makePlugin({
38
+ transport: 'remote-mcp',
39
+ trustLevel: 'verified',
40
+ executionMode: 'gateway',
41
+ mcpgateServerId: 'server-xyz',
42
+ }));
43
+ expect(result.path).toBe('gateway-mcp');
44
+ expect(result.target).toBe('server-xyz');
45
+ });
46
+ it('routes rest transport to gateway-rest with endpointUrl as target', () => {
47
+ const result = routePlugin(makePlugin({
48
+ transport: 'rest',
49
+ trustLevel: 'verified',
50
+ executionMode: 'gateway',
51
+ endpointUrl: 'https://api.weather.com/v1',
52
+ }));
53
+ expect(result.path).toBe('gateway-rest');
54
+ expect(result.target).toBe('https://api.weather.com/v1');
55
+ });
56
+ it('blocks plugins on admin blocklist', () => {
57
+ const result = routePlugin(makePlugin({ slug: 'bad-plugin', transport: 'embedded', trustLevel: 'internal' }), { policy: { blockedPlugins: ['bad-plugin'] } });
58
+ expect(result.path).toBe('blocked');
59
+ });
60
+ it('defaults unknown fields to safe values', () => {
61
+ // Plugin with no unified fields (old format) — cast to bypass required fields
62
+ const result = routePlugin(makePlugin({
63
+ transport: undefined,
64
+ trustLevel: undefined,
65
+ executionMode: undefined,
66
+ }));
67
+ // Defaults: transport=remote-mcp, trustLevel=community, executionMode=gateway
68
+ expect(result.path).toBe('gateway-mcp');
69
+ expect(result.policy.effectiveMode).toBe('gateway');
70
+ });
71
+ it('uses builtin: prefix for fallback server ID', () => {
72
+ const result = routePlugin(makePlugin({
73
+ slug: 'lucid-seo',
74
+ transport: 'remote-mcp',
75
+ mcpgateServerId: undefined,
76
+ }));
77
+ expect(result.target).toBe('builtin:lucid-seo');
78
+ });
79
+ });
80
+ //# sourceMappingURL=router.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.test.js","sourceRoot":"","sources":["../../src/__tests__/router.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capability Core — Audit Hooks
3
+ *
4
+ * Pluggable audit system for plugin tool executions.
5
+ * Consumers register handlers; the audit emitter fires after each tool call.
6
+ *
7
+ * Handlers are fire-and-forget — audit failures never block tool execution.
8
+ */
9
+ import type { AuditEvent, AuditHandler } from './types.js';
10
+ export declare class AuditEmitter {
11
+ private readonly handlers;
12
+ /** Register an audit handler. Returns unsubscribe function. */
13
+ on(handler: AuditHandler): () => void;
14
+ /** Emit an audit event to all registered handlers (fire-and-forget). */
15
+ emit(event: AuditEvent): void;
16
+ /** Remove all handlers. */
17
+ clear(): void;
18
+ get handlerCount(): number;
19
+ }
20
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE1D,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAE9C,+DAA+D;IAC/D,EAAE,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAQrC,wEAAwE;IACxE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAgB7B,2BAA2B;IAC3B,KAAK,IAAI,IAAI;IAIb,IAAI,YAAY,IAAI,MAAM,CAEzB;CACF"}
package/dist/audit.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Capability Core — Audit Hooks
3
+ *
4
+ * Pluggable audit system for plugin tool executions.
5
+ * Consumers register handlers; the audit emitter fires after each tool call.
6
+ *
7
+ * Handlers are fire-and-forget — audit failures never block tool execution.
8
+ */
9
+ export class AuditEmitter {
10
+ handlers = [];
11
+ /** Register an audit handler. Returns unsubscribe function. */
12
+ on(handler) {
13
+ this.handlers.push(handler);
14
+ return () => {
15
+ const idx = this.handlers.indexOf(handler);
16
+ if (idx >= 0)
17
+ this.handlers.splice(idx, 1);
18
+ };
19
+ }
20
+ /** Emit an audit event to all registered handlers (fire-and-forget). */
21
+ emit(event) {
22
+ for (const handler of this.handlers) {
23
+ try {
24
+ const result = handler(event);
25
+ // If handler returns a promise, catch errors silently
26
+ if (result && typeof result === 'object' && 'catch' in result) {
27
+ ;
28
+ result.catch((err) => {
29
+ console.error('[plugin-policy:audit] Handler error:', err);
30
+ });
31
+ }
32
+ }
33
+ catch (err) {
34
+ console.error('[plugin-policy:audit] Handler error:', err);
35
+ }
36
+ }
37
+ }
38
+ /** Remove all handlers. */
39
+ clear() {
40
+ this.handlers.length = 0;
41
+ }
42
+ get handlerCount() {
43
+ return this.handlers.length;
44
+ }
45
+ }
46
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,OAAO,YAAY;IACN,QAAQ,GAAmB,EAAE,CAAA;IAE9C,+DAA+D;IAC/D,EAAE,CAAC,OAAqB;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC3B,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YAC1C,IAAI,GAAG,IAAI,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QAC5C,CAAC,CAAA;IACH,CAAC;IAED,wEAAwE;IACxE,IAAI,CAAC,KAAiB;QACpB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;gBAC7B,sDAAsD;gBACtD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;oBAC9D,CAAC;oBAAC,MAAwB,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;wBACvC,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAA;oBAC5D,CAAC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAA;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;IAC1B,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAA;IAC7B,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @lucid/plugin-policy
3
+ *
4
+ * Unified capability registry, router, policy engine, and audit hooks.
5
+ * Shared between the worker (in-process execution) and MCPGate (gateway execution).
6
+ *
7
+ * Usage:
8
+ * import { PluginRegistry, routePlugin, resolvePolicy, AuditEmitter } from '@lucid/plugin-policy'
9
+ */
10
+ export type { PluginCatalogEntry, ToolDef, ActivatedPlugin, PolicyDecision, PolicyResult, PolicyConfig, ExecutionPath, RouteResult, AuditEvent, AuditHandler, } from './types.js';
11
+ export { PluginRegistry } from './registry.js';
12
+ export { resolvePolicy } from './policy.js';
13
+ export { routePlugin } from './router.js';
14
+ export type { RouterConfig } from './router.js';
15
+ export { AuditEmitter } from './audit.js';
16
+ export { normalizePluginRow } from './manifest.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,YAAY,EACV,kBAAkB,EAClB,OAAO,EACP,eAAe,EACf,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAG9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @lucid/plugin-policy
3
+ *
4
+ * Unified capability registry, router, policy engine, and audit hooks.
5
+ * Shared between the worker (in-process execution) and MCPGate (gateway execution).
6
+ *
7
+ * Usage:
8
+ * import { PluginRegistry, routePlugin, resolvePolicy, AuditEmitter } from '@lucid/plugin-policy'
9
+ */
10
+ // Registry
11
+ export { PluginRegistry } from './registry.js';
12
+ // Policy
13
+ export { resolvePolicy } from './policy.js';
14
+ // Router
15
+ export { routePlugin } from './router.js';
16
+ // Audit
17
+ export { AuditEmitter } from './audit.js';
18
+ // Manifest normalization
19
+ export { normalizePluginRow } from './manifest.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,QAAQ;AACR,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Capability Core — Manifest Normalization
3
+ *
4
+ * Normalizes DB rows (snake_case) into the internal ActivatedPlugin format (camelCase).
5
+ * Used by the worker when transforming RPC results.
6
+ */
7
+ import type { ActivatedPlugin } from './types.js';
8
+ /**
9
+ * Transform a raw DB row from get_assistant_active_plugins RPC into an ActivatedPlugin.
10
+ * Handles both old (source/mcpgate_server_id only) and new (unified fields) formats.
11
+ */
12
+ export declare function normalizePluginRow(row: Record<string, unknown>): ActivatedPlugin;
13
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CAiDhF"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Capability Core — Manifest Normalization
3
+ *
4
+ * Normalizes DB rows (snake_case) into the internal ActivatedPlugin format (camelCase).
5
+ * Used by the worker when transforming RPC results.
6
+ */
7
+ /**
8
+ * Transform a raw DB row from get_assistant_active_plugins RPC into an ActivatedPlugin.
9
+ * Handles both old (source/mcpgate_server_id only) and new (unified fields) formats.
10
+ */
11
+ export function normalizePluginRow(row) {
12
+ // Tool manifest: may be JSONB array or stringified
13
+ let tools = [];
14
+ const rawManifest = row.tool_manifest ?? row.manifest_snapshot;
15
+ if (Array.isArray(rawManifest)) {
16
+ tools = rawManifest;
17
+ }
18
+ else if (typeof rawManifest === 'string') {
19
+ try {
20
+ tools = JSON.parse(rawManifest);
21
+ }
22
+ catch {
23
+ tools = [];
24
+ }
25
+ }
26
+ // Filter tools by enabled_tools if present
27
+ const enabledTools = row.enabled_tools;
28
+ if (enabledTools && Array.isArray(enabledTools)) {
29
+ tools = tools.filter((t) => enabledTools.includes(t.name ?? ''));
30
+ }
31
+ // Merge org config + plugin config (plugin config takes precedence)
32
+ const orgConfig = (row.org_config ?? {});
33
+ const pluginConfig = (row.plugin_config ?? row.config ?? {});
34
+ const config = { ...orgConfig, ...pluginConfig };
35
+ return {
36
+ slug: row.plugin_slug,
37
+ name: row.plugin_name,
38
+ tools,
39
+ config,
40
+ // UCA dimensions (required — safe defaults match DB column defaults)
41
+ kind: (row.kind ?? 'plugin'),
42
+ transport: (row.transport ?? 'remote-mcp'),
43
+ trustLevel: (row.trust_level ?? 'community'),
44
+ executionMode: (row.execution_mode ?? 'gateway'),
45
+ authType: (row.auth_type ?? 'none'),
46
+ authProvider: row.auth_provider ?? null,
47
+ // Routing targets
48
+ mcpgateServerId: row.mcpgate_server_id ?? undefined,
49
+ endpointUrl: row.endpoint_url ?? undefined,
50
+ // Fallback policy
51
+ fallbackMode: (row.fallback_mode ?? null),
52
+ // Deprecated (kept for wire compat)
53
+ source: row.source ?? undefined,
54
+ };
55
+ }
56
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAA4B;IAC7D,mDAAmD;IACnD,IAAI,KAAK,GAAG,EAAE,CAAA;IACd,MAAM,WAAW,GAAG,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,iBAAiB,CAAA;IAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,KAAK,GAAG,WAAW,CAAA;IACrB,CAAC;SAAM,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;QAC3C,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,GAAG,EAAE,CAAA;QACZ,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,MAAM,YAAY,GAAG,GAAG,CAAC,aAAgC,CAAA;IACzD,IAAI,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QAChD,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAoB,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAA;IACrF,CAAC;IAED,oEAAoE;IACpE,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAA;IACnE,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAA;IACvF,MAAM,MAAM,GAAG,EAAE,GAAG,SAAS,EAAE,GAAG,YAAY,EAAE,CAAA;IAEhD,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,WAAqB;QAC/B,IAAI,EAAE,GAAG,CAAC,WAAqB;QAC/B,KAAK;QACL,MAAM;QAEN,qEAAqE;QACrE,IAAI,EAAE,CAAE,GAAG,CAAC,IAAe,IAAI,QAAQ,CAA4B;QACnE,SAAS,EAAE,CAAE,GAAG,CAAC,SAAoB,IAAI,YAAY,CAAiC;QACtF,UAAU,EAAE,CAAE,GAAG,CAAC,WAAsB,IAAI,WAAW,CAAkC;QACzF,aAAa,EAAE,CAAE,GAAG,CAAC,cAAyB,IAAI,SAAS,CAAqC;QAChG,QAAQ,EAAE,CAAE,GAAG,CAAC,SAAoB,IAAI,MAAM,CAAgC;QAC9E,YAAY,EAAG,GAAG,CAAC,aAAwB,IAAI,IAAI;QAEnD,kBAAkB;QAClB,eAAe,EAAG,GAAG,CAAC,iBAA4B,IAAI,SAAS;QAC/D,WAAW,EAAG,GAAG,CAAC,YAAuB,IAAI,SAAS;QAEtD,kBAAkB;QAClB,YAAY,EAAE,CAAE,GAAG,CAAC,aAAwB,IAAI,IAAI,CAAoC;QAExF,oCAAoC;QACpC,MAAM,EAAG,GAAG,CAAC,MAAoC,IAAI,SAAS;KAC/D,CAAA;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Capability Core — Policy Engine
3
+ *
4
+ * Resolves the effective execution mode for a plugin based on:
5
+ * 1. Admin blocklist
6
+ * 2. Trust level → execution mode matrix
7
+ * 3. Environment overrides (e.g., force gateway in staging)
8
+ *
9
+ * Policy matrix (RFC Section 4.2):
10
+ * internal + in_process → allow_in_process
11
+ * internal + gateway → allow_gateway
12
+ * verified + in_process → allow_in_process
13
+ * verified + gateway → allow_gateway
14
+ * community + in_process → allow_gateway (OVERRIDE — community never runs in-process)
15
+ * community + gateway → allow_gateway
16
+ */
17
+ import type { PluginCatalogEntry, PolicyConfig, PolicyResult } from './types.js';
18
+ /**
19
+ * Resolve the execution policy for a plugin.
20
+ * Takes the full catalog entry so policy can inspect any field.
21
+ */
22
+ export declare function resolvePolicy(plugin: Pick<PluginCatalogEntry, 'slug' | 'trustLevel' | 'executionMode'>, config?: PolicyConfig): PolicyResult;
23
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEhF;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAAC,EACzE,MAAM,CAAC,EAAE,YAAY,GACpB,YAAY,CAgDd"}
package/dist/policy.js ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Capability Core — Policy Engine
3
+ *
4
+ * Resolves the effective execution mode for a plugin based on:
5
+ * 1. Admin blocklist
6
+ * 2. Trust level → execution mode matrix
7
+ * 3. Environment overrides (e.g., force gateway in staging)
8
+ *
9
+ * Policy matrix (RFC Section 4.2):
10
+ * internal + in_process → allow_in_process
11
+ * internal + gateway → allow_gateway
12
+ * verified + in_process → allow_in_process
13
+ * verified + gateway → allow_gateway
14
+ * community + in_process → allow_gateway (OVERRIDE — community never runs in-process)
15
+ * community + gateway → allow_gateway
16
+ */
17
+ /**
18
+ * Resolve the execution policy for a plugin.
19
+ * Takes the full catalog entry so policy can inspect any field.
20
+ */
21
+ export function resolvePolicy(plugin, config) {
22
+ // 1. Admin blocklist
23
+ if (config?.blockedPlugins?.includes(plugin.slug)) {
24
+ return {
25
+ decision: 'block',
26
+ reason: `Plugin "${plugin.slug}" is on the admin blocklist`,
27
+ effectiveMode: 'gateway',
28
+ };
29
+ }
30
+ // 2. Environment override — force everything through gateway
31
+ if (config?.forceGateway) {
32
+ return {
33
+ decision: 'allow_gateway',
34
+ reason: 'Environment forces gateway mode',
35
+ effectiveMode: 'gateway',
36
+ };
37
+ }
38
+ // 3. Trust level → execution mode matrix
39
+ // Default undefined to safest posture (community + gateway) — matches DB column defaults.
40
+ // Without this, an old DB row missing these fields would fall through to allow_in_process.
41
+ const trustLevel = plugin.trustLevel ?? 'community';
42
+ const executionMode = plugin.executionMode ?? 'gateway';
43
+ // Community plugins: NEVER in-process, regardless of requested mode
44
+ if (trustLevel === 'community') {
45
+ return {
46
+ decision: 'allow_gateway',
47
+ reason: 'Community plugins are gateway-only (policy enforced)',
48
+ effectiveMode: 'gateway',
49
+ };
50
+ }
51
+ // Internal or verified: respect the requested execution mode
52
+ if (executionMode === 'in_process') {
53
+ return {
54
+ decision: 'allow_in_process',
55
+ reason: `${trustLevel} plugin allowed in-process`,
56
+ effectiveMode: 'in_process',
57
+ };
58
+ }
59
+ return {
60
+ decision: 'allow_gateway',
61
+ reason: `${trustLevel} plugin requested gateway mode`,
62
+ effectiveMode: 'gateway',
63
+ };
64
+ }
65
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAyE,EACzE,MAAqB;IAErB,qBAAqB;IACrB,IAAI,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,WAAW,MAAM,CAAC,IAAI,6BAA6B;YAC3D,aAAa,EAAE,SAAS;SACzB,CAAA;IACH,CAAC;IAED,6DAA6D;IAC7D,IAAI,MAAM,EAAE,YAAY,EAAE,CAAC;QACzB,OAAO;YACL,QAAQ,EAAE,eAAe;YACzB,MAAM,EAAE,iCAAiC;YACzC,aAAa,EAAE,SAAS;SACzB,CAAA;IACH,CAAC;IAED,yCAAyC;IACzC,0FAA0F;IAC1F,2FAA2F;IAC3F,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,WAAW,CAAA;IACnD,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,SAAS,CAAA;IAEvD,oEAAoE;IACpE,IAAI,UAAU,KAAK,WAAW,EAAE,CAAC;QAC/B,OAAO;YACL,QAAQ,EAAE,eAAe;YACzB,MAAM,EAAE,sDAAsD;YAC9D,aAAa,EAAE,SAAS;SACzB,CAAA;IACH,CAAC;IAED,6DAA6D;IAC7D,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO;YACL,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,GAAG,UAAU,4BAA4B;YACjD,aAAa,EAAE,YAAY;SAC5B,CAAA;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,eAAe;QACzB,MAAM,EAAE,GAAG,UAAU,gCAAgC;QACrD,aAAa,EAAE,SAAS;KACzB,CAAA;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Capability Core — Registry
3
+ *
4
+ * In-memory registry of activated plugins for a given context (e.g., assistant run).
5
+ * Provides lookup by slug and wire tool name parsing.
6
+ *
7
+ * Not a singleton — each agent run creates its own registry from the DB result.
8
+ */
9
+ import type { ActivatedPlugin, ToolDef } from './types.js';
10
+ export declare class PluginRegistry {
11
+ private readonly plugins;
12
+ constructor(plugins?: ActivatedPlugin[]);
13
+ register(plugin: ActivatedPlugin): void;
14
+ get(slug: string): ActivatedPlugin | undefined;
15
+ has(slug: string): boolean;
16
+ getAll(): ActivatedPlugin[];
17
+ /** Resolve a wire tool name (e.g., 'lucid_seo__research_keywords') to plugin + tool. */
18
+ resolveWireToolName(wireName: string): {
19
+ plugin: ActivatedPlugin;
20
+ tool: ToolDef;
21
+ } | null;
22
+ get size(): number;
23
+ }
24
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAK1D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;gBAEjD,OAAO,CAAC,EAAE,eAAe,EAAE;IAQvC,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAIvC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,MAAM,IAAI,eAAe,EAAE;IAI3B,wFAAwF;IACxF,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,eAAe,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAiBxF,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Capability Core — Registry
3
+ *
4
+ * In-memory registry of activated plugins for a given context (e.g., assistant run).
5
+ * Provides lookup by slug and wire tool name parsing.
6
+ *
7
+ * Not a singleton — each agent run creates its own registry from the DB result.
8
+ */
9
+ /** Wire tool name format: {pluginSlug}__{toolName} (double underscore separator). */
10
+ const WIRE_SEPARATOR = '__';
11
+ export class PluginRegistry {
12
+ plugins = new Map();
13
+ constructor(plugins) {
14
+ if (plugins) {
15
+ for (const p of plugins) {
16
+ this.register(p);
17
+ }
18
+ }
19
+ }
20
+ register(plugin) {
21
+ this.plugins.set(plugin.slug, plugin);
22
+ }
23
+ get(slug) {
24
+ return this.plugins.get(slug);
25
+ }
26
+ has(slug) {
27
+ return this.plugins.has(slug);
28
+ }
29
+ getAll() {
30
+ return Array.from(this.plugins.values());
31
+ }
32
+ /** Resolve a wire tool name (e.g., 'lucid_seo__research_keywords') to plugin + tool. */
33
+ resolveWireToolName(wireName) {
34
+ const idx = wireName.indexOf(WIRE_SEPARATOR);
35
+ if (idx === -1)
36
+ return null;
37
+ const slugPart = wireName.slice(0, idx);
38
+ const toolName = wireName.slice(idx + WIRE_SEPARATOR.length);
39
+ // Wire names sanitize hyphens to underscores, so try both
40
+ const plugin = this.plugins.get(slugPart) ?? this.plugins.get(slugPart.replace(/_/g, '-'));
41
+ if (!plugin)
42
+ return null;
43
+ const tool = plugin.tools.find((t) => t.name === toolName);
44
+ if (!tool)
45
+ return null;
46
+ return { plugin, tool };
47
+ }
48
+ get size() {
49
+ return this.plugins.size;
50
+ }
51
+ }
52
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,qFAAqF;AACrF,MAAM,cAAc,GAAG,IAAI,CAAA;AAE3B,MAAM,OAAO,cAAc;IACR,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAA;IAE7D,YAAY,OAA2B;QACrC,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,MAAuB;QAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACvC,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC1C,CAAC;IAED,wFAAwF;IACxF,mBAAmB,CAAC,QAAgB;QAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;QAC5C,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QAE3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QACvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;QAE5D,0DAA0D;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;QAC1F,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QAExB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;QAC1D,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QAEtB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IACzB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAA;IAC1B,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Capability Core — Router
3
+ *
4
+ * Determines the execution path for a plugin tool call:
5
+ * embedded → in-process MCP via InMemoryTransport
6
+ * gateway-mcp → HTTP call to MCPGate (remote MCP)
7
+ * gateway-rest → HTTP call to REST API endpoint
8
+ * blocked → execution denied by policy
9
+ *
10
+ * Decision table (RFC Section 3.2):
11
+ * transport=embedded + policy=in_process → embedded
12
+ * transport=embedded + policy=gateway → gateway-mcp (fallback)
13
+ * transport=remote-mcp + any → gateway-mcp
14
+ * transport=rest + any → gateway-rest
15
+ * policy=block → blocked
16
+ */
17
+ import type { ActivatedPlugin, PolicyConfig, RouteResult } from './types.js';
18
+ export interface RouterConfig {
19
+ /** MCPGate gateway URL (from MCPGATE_URL env). */
20
+ mcpgateUrl?: string;
21
+ /** Policy configuration. */
22
+ policy?: PolicyConfig;
23
+ }
24
+ /**
25
+ * Route a plugin to its execution path.
26
+ */
27
+ export declare function routePlugin(plugin: ActivatedPlugin, config?: RouterConfig): RouteResult;
28
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG5E,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,CAuDvF"}
package/dist/router.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Capability Core — Router
3
+ *
4
+ * Determines the execution path for a plugin tool call:
5
+ * embedded → in-process MCP via InMemoryTransport
6
+ * gateway-mcp → HTTP call to MCPGate (remote MCP)
7
+ * gateway-rest → HTTP call to REST API endpoint
8
+ * blocked → execution denied by policy
9
+ *
10
+ * Decision table (RFC Section 3.2):
11
+ * transport=embedded + policy=in_process → embedded
12
+ * transport=embedded + policy=gateway → gateway-mcp (fallback)
13
+ * transport=remote-mcp + any → gateway-mcp
14
+ * transport=rest + any → gateway-rest
15
+ * policy=block → blocked
16
+ */
17
+ import { resolvePolicy } from './policy.js';
18
+ /**
19
+ * Route a plugin to its execution path.
20
+ */
21
+ export function routePlugin(plugin, config) {
22
+ const trustLevel = plugin.trustLevel ?? 'community';
23
+ const executionMode = plugin.executionMode ?? 'gateway';
24
+ const transport = plugin.transport ?? 'remote-mcp';
25
+ // Resolve policy
26
+ const policy = resolvePolicy({ slug: plugin.slug, trustLevel, executionMode }, config?.policy);
27
+ // Blocked by policy
28
+ if (policy.decision === 'block') {
29
+ return { path: 'blocked', policy };
30
+ }
31
+ // Route based on transport + effective mode
32
+ switch (transport) {
33
+ case 'embedded': {
34
+ if (policy.effectiveMode === 'in_process') {
35
+ return { path: 'embedded', policy };
36
+ }
37
+ // Embedded plugin forced to gateway by policy → route through MCPGate
38
+ return {
39
+ path: 'gateway-mcp',
40
+ target: plugin.mcpgateServerId ?? `builtin:${plugin.slug}`,
41
+ policy,
42
+ };
43
+ }
44
+ case 'remote-mcp': {
45
+ return {
46
+ path: 'gateway-mcp',
47
+ target: plugin.mcpgateServerId ?? `builtin:${plugin.slug}`,
48
+ policy,
49
+ };
50
+ }
51
+ case 'rest': {
52
+ return {
53
+ path: 'gateway-rest',
54
+ target: plugin.endpointUrl ?? plugin.slug,
55
+ policy,
56
+ };
57
+ }
58
+ default: {
59
+ // Unknown transport → gateway as safe default
60
+ return {
61
+ path: 'gateway-mcp',
62
+ target: plugin.mcpgateServerId ?? `builtin:${plugin.slug}`,
63
+ policy,
64
+ };
65
+ }
66
+ }
67
+ }
68
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAS3C;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAAuB,EAAE,MAAqB;IACxE,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,WAAW,CAAA;IACnD,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,SAAS,CAAA;IACvD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,YAAY,CAAA;IAElD,iBAAiB;IACjB,MAAM,MAAM,GAAG,aAAa,CAC1B,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,EAChD,MAAM,EAAE,MAAM,CACf,CAAA;IAED,oBAAoB;IACpB,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAA;IACpC,CAAC;IAED,4CAA4C;IAC5C,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,IAAI,MAAM,CAAC,aAAa,KAAK,YAAY,EAAE,CAAC;gBAC1C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAA;YACrC,CAAC;YACD,sEAAsE;YACtE,OAAO;gBACL,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,MAAM,CAAC,eAAe,IAAI,WAAW,MAAM,CAAC,IAAI,EAAE;gBAC1D,MAAM;aACP,CAAA;QACH,CAAC;QAED,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,OAAO;gBACL,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,MAAM,CAAC,eAAe,IAAI,WAAW,MAAM,CAAC,IAAI,EAAE;gBAC1D,MAAM;aACP,CAAA;QACH,CAAC;QAED,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO;gBACL,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI;gBACzC,MAAM;aACP,CAAA;QACH,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;YACR,8CAA8C;YAC9C,OAAO;gBACL,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,MAAM,CAAC,eAAe,IAAI,WAAW,MAAM,CAAC,IAAI,EAAE;gBAC1D,MAAM;aACP,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Capability Core — Types
3
+ *
4
+ * Canonical types for the unified capability architecture.
5
+ * These mirror contracts/plugin.ts but are framework-independent.
6
+ */
7
+ export interface PluginCatalogEntry {
8
+ id: string;
9
+ slug: string;
10
+ name: string;
11
+ description: string | null;
12
+ version: string;
13
+ source: 'first-party' | 'mcpgate' | 'community';
14
+ kind: 'plugin' | 'integration';
15
+ transport: 'embedded' | 'remote-mcp' | 'rest';
16
+ trustLevel: 'internal' | 'verified' | 'community';
17
+ executionMode: 'in_process' | 'gateway';
18
+ authType: 'none' | 'oauth2' | 'api-key' | 'env-var';
19
+ authProvider: string | null;
20
+ toolManifest: ToolDef[];
21
+ mcpgateServerId?: string | null;
22
+ riskLevel: 'read' | 'write' | 'destructive';
23
+ verified: boolean;
24
+ isPublished: boolean;
25
+ maxTools: number;
26
+ }
27
+ export interface ToolDef {
28
+ name: string;
29
+ description: string;
30
+ parameters: Record<string, unknown>;
31
+ }
32
+ export interface ActivatedPlugin {
33
+ slug: string;
34
+ name: string;
35
+ tools: ToolDef[];
36
+ config: Record<string, unknown>;
37
+ kind: 'plugin' | 'integration';
38
+ transport: 'embedded' | 'remote-mcp' | 'rest';
39
+ trustLevel: 'internal' | 'verified' | 'community';
40
+ executionMode: 'in_process' | 'gateway';
41
+ authType: 'none' | 'oauth2' | 'api-key' | 'env-var';
42
+ authProvider: string | null;
43
+ mcpgateServerId?: string;
44
+ endpointUrl?: string;
45
+ fallbackMode?: 'gateway' | null;
46
+ /** @deprecated Use trustLevel + transport instead. Kept for DB wire compat. */
47
+ source?: 'first-party' | 'mcpgate' | 'community';
48
+ }
49
+ export type PolicyDecision = 'allow_in_process' | 'allow_gateway' | 'block';
50
+ export interface PolicyResult {
51
+ decision: PolicyDecision;
52
+ reason: string;
53
+ /** Effective execution mode after policy resolution. */
54
+ effectiveMode: 'in_process' | 'gateway';
55
+ }
56
+ export interface PolicyConfig {
57
+ /** Admin blocklist — slugs that are blocked regardless of trust. */
58
+ blockedPlugins?: string[];
59
+ /** Environment override (e.g., force gateway in staging). */
60
+ forceGateway?: boolean;
61
+ }
62
+ export type ExecutionPath = 'embedded' | 'gateway-mcp' | 'gateway-rest' | 'blocked';
63
+ export interface RouteResult {
64
+ path: ExecutionPath;
65
+ /** The target URL or server ID for gateway paths. */
66
+ target?: string;
67
+ /** Policy result that determined this route. */
68
+ policy: PolicyResult;
69
+ }
70
+ export interface AuditEvent {
71
+ timestamp: string;
72
+ pluginSlug: string;
73
+ toolName: string;
74
+ executionPath: ExecutionPath;
75
+ durationMs: number;
76
+ success: boolean;
77
+ error?: string;
78
+ /** Who triggered it (assistant ID, org ID). */
79
+ context?: Record<string, unknown>;
80
+ }
81
+ export type AuditHandler = (event: AuditEvent) => void | Promise<void>;
82
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Capability Core — Types
3
+ *
4
+ * Canonical types for the unified capability architecture.
5
+ * These mirror contracts/plugin.ts but are framework-independent.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@lucid-fdn/plugin-policy",
3
+ "version": "0.1.0",
4
+ "description": "Unified capability registry, router, policy engine, and audit hooks for plugins and integrations",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "typecheck": "tsc --noEmit"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^22.0.0",
21
+ "typescript": "^5.7.3"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "license": "MIT",
27
+ "files": [
28
+ "dist"
29
+ ]
30
+ }