@forumone/throughline-core 0.0.1 → 0.2.1
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/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +104 -28
- package/dist/audit/collection.d.ts +19 -0
- package/dist/audit/collection.d.ts.map +1 -0
- package/dist/audit/collection.js +107 -0
- package/dist/audit/collection.js.map +1 -0
- package/dist/audit/index.d.ts +9 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +5 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/plugin.d.ts +20 -0
- package/dist/audit/plugin.d.ts.map +1 -0
- package/dist/audit/plugin.js +55 -0
- package/dist/audit/plugin.js.map +1 -0
- package/dist/audit/types.d.ts +11 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +45 -0
- package/dist/audit/types.js.map +1 -0
- package/dist/audit/writer.d.ts +50 -0
- package/dist/audit/writer.d.ts.map +1 -0
- package/dist/audit/writer.js +101 -0
- package/dist/audit/writer.js.map +1 -0
- package/dist/auth/api-keys.d.ts +21 -0
- package/dist/auth/api-keys.d.ts.map +1 -0
- package/dist/auth/api-keys.js +115 -0
- package/dist/auth/api-keys.js.map +1 -0
- package/dist/auth/authenticator.d.ts +15 -0
- package/dist/auth/authenticator.d.ts.map +1 -0
- package/dist/auth/authenticator.js +63 -0
- package/dist/auth/authenticator.js.map +1 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/env/index.d.ts +51 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +59 -0
- package/dist/env/index.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/inngest.d.ts +24 -0
- package/dist/events/inngest.d.ts.map +1 -0
- package/dist/events/inngest.js +24 -0
- package/dist/events/inngest.js.map +1 -0
- package/dist/events/taxonomy.d.ts +84 -0
- package/dist/events/taxonomy.d.ts.map +1 -0
- package/dist/events/taxonomy.js +10 -0
- package/dist/events/taxonomy.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +9 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +41 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/mcp/handler.d.ts +20 -0
- package/dist/mcp/handler.d.ts.map +1 -0
- package/dist/mcp/handler.js +109 -0
- package/dist/mcp/handler.js.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/meta.d.ts +74 -0
- package/dist/mcp/meta.d.ts.map +1 -0
- package/dist/mcp/meta.js +27 -0
- package/dist/mcp/meta.js.map +1 -0
- package/dist/utils/diff.d.ts +13 -0
- package/dist/utils/diff.d.ts.map +1 -0
- package/dist/utils/diff.js +31 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/id.d.ts +6 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +13 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +82 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @forumone/throughline-core
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a4b5108: Initial release of the forms package. Wraps Payload's Form Builder plugin with the Throughline policy layer: mandatory privacy notice, consent enforcement (server-side), honeypot spam protection, Postgres-backed per-IP rate limiting, a destination allowlist (the security perimeter), and submitter confirmations. Six MCP tools (`list_allowed_destinations`, `validate_form`, `create_form`, `update_form_fields`, `update_form_destinations`, `get_form_submissions`) and four Inngest functions (`form-fan-out`, `form-email-destination`, `form-webhook-destination`, `form-submitter-confirmation`) drive the conversational flow and the async destination delivery. Includes `FormSubmissionEmail` and `SubmitterConfirmationEmail` React Email templates. Allowlist enforcement runs at three layers (MCP tool, collection beforeChange hook, fan-out worker) so prompt injection or admin direct-API writes can't bypass it. IPs are HMAC-hashed; raw IPs are never persisted. Adds `form.updated` to the core audit-action taxonomy used by the two update tools.
|
|
8
|
+
|
|
9
|
+
## 0.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#14](https://github.com/forumone/throughline/pull/14) [`5329d97`](https://github.com/forumone/throughline/commit/5329d97363099a54bcae2516a8aa9eff8cd735fc) Thanks [@briangraves](https://github.com/briangraves)! - Initial release. Provides the audit log (collection + fire-and-forget writer + plugin), MCP authentication (bearer-token authenticator + API-keys collection with SHA-256 hashed keys), event taxonomy and Inngest client factory, MCP handler infrastructure (JSON-RPC over HTTP) with the `_meta` helper for prompt/reasoning capture, standard env-var conventions, a default logger, and shared utilities. Every server package in the framework depends on this.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Forum One Communications Corporation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,45 +1,121 @@
|
|
|
1
1
|
# @forumone/throughline-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The shared plumbing every Throughline server package depends on. Drop it into a Payload + Next.js app and you get the audit log, MCP authentication and request handling, the framework event taxonomy + Inngest client factory, env-var conventions, a logger, and a handful of small utilities.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What's inside
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| Subsystem | Subpath | Role |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Audit | `./audit` | `auditPlugin`, `createAuditCollection`, `createAuditWriter`, `getAuditWriter`, `AUDIT_ACTIONS`, `AUDIT_MCP_SERVERS` |
|
|
10
|
+
| Auth | `./auth` | `createApiKeysCollection`, `createBearerTokenAuthenticator`, `generateApiKey`, `sha256Hex` |
|
|
11
|
+
| Events | `./events` | `createInngestClient`, `CoreEvents`, `FrameworkEvents` (module-augmentation seam) |
|
|
12
|
+
| MCP | `./mcp` | `createMcpHandler`, `McpMetaSchema`, `withMeta` |
|
|
13
|
+
| Env | `./env` | `ENV_VARS`, `validateBaseEnv`, `requireEnv`, `optionalEnv` |
|
|
14
|
+
| Logger | (main) | `defaultLogger`, `createNamedLogger` |
|
|
15
|
+
| Utils | (main) | `shallowDiff`, `generateId` |
|
|
8
16
|
|
|
9
|
-
|
|
17
|
+
The main entry re-exports everything; the subpath exports keep bundles smaller for consumers who only need one slice.
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@forumone/throughline-core`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
19
|
+
## Installation
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @forumone/throughline-core
|
|
23
|
+
```
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
Peers: `payload@^3.0.0` and `inngest@^4.0.0`.
|
|
19
26
|
|
|
20
|
-
##
|
|
27
|
+
## The audit log
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
Every consequential action in the framework writes to a single immutable Payload collection. Plugins do not write directly — they call the writer attached to the Payload instance by `auditPlugin`.
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
31
|
+
```ts
|
|
32
|
+
import { auditPlugin, createInngestClient } from '@forumone/throughline-core'
|
|
33
|
+
import { buildConfig } from 'payload'
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
const inngest = createInngestClient({ id: 'my-site' })
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
export default buildConfig({
|
|
38
|
+
// collections, db, secret...
|
|
39
|
+
plugins: [
|
|
40
|
+
auditPlugin({ inngest }),
|
|
41
|
+
// your other Throughline plugins
|
|
42
|
+
],
|
|
43
|
+
})
|
|
44
|
+
```
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
In a downstream plugin's `onInit`:
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
48
|
+
```ts
|
|
49
|
+
import { getAuditWriter } from '@forumone/throughline-core'
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
onInit: async (payload) => {
|
|
52
|
+
const writer = getAuditWriter(payload)
|
|
53
|
+
await writer({
|
|
54
|
+
actor: { type: 'user', userId: 'u1' },
|
|
55
|
+
action: 'publishing.publish',
|
|
56
|
+
mcpServer: 'publishing',
|
|
57
|
+
mcpTool: 'publishing.publish',
|
|
58
|
+
targetCollection: 'pages',
|
|
59
|
+
targetId: 'p1',
|
|
60
|
+
targetTitle: 'Homepage',
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
```
|
|
44
64
|
|
|
45
|
-
**
|
|
65
|
+
The writer is **fire-and-forget**: failures log but never throw. Audit failures must never break the originating action.
|
|
66
|
+
|
|
67
|
+
## MCP authentication
|
|
68
|
+
|
|
69
|
+
`createApiKeysCollection` adds a Payload collection that stores SHA-256 hashes of bearer tokens (the raw key is shown to the operator once on create, then never persisted). `createBearerTokenAuthenticator` validates incoming requests against that collection.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { createApiKeysCollection, createBearerTokenAuthenticator, createMcpHandler } from '@forumone/throughline-core'
|
|
73
|
+
import type { Payload } from 'payload'
|
|
74
|
+
|
|
75
|
+
// In your Payload config:
|
|
76
|
+
collections: [createApiKeysCollection({ usersSlug: 'users' })],
|
|
77
|
+
|
|
78
|
+
// In your MCP route:
|
|
79
|
+
const authenticator = createBearerTokenAuthenticator({ payload })
|
|
80
|
+
const handleMcp = createMcpHandler({
|
|
81
|
+
payload,
|
|
82
|
+
serverName: 'publishing',
|
|
83
|
+
tools: [/* McpToolDefinition[] */],
|
|
84
|
+
authenticator,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Next.js app router:
|
|
88
|
+
export const POST = (req: Request) => handleMcp(req)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Events
|
|
92
|
+
|
|
93
|
+
`CoreEvents` enumerates the events the framework fires today. Server packages add their own via TypeScript module augmentation:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
declare module '@forumone/throughline-core/events' {
|
|
97
|
+
interface FrameworkEvents {
|
|
98
|
+
'approval/decided': {
|
|
99
|
+
data: { approvalId: string; decision: 'granted' | 'declined' }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
After augmentation, `inngest.send({ name: 'approval/decided', data: { ... } })` is type-checked everywhere.
|
|
106
|
+
|
|
107
|
+
## Env vars
|
|
108
|
+
|
|
109
|
+
`ENV_VARS` is the canonical list of names the framework reads. Plugins reach into `process.env` through these constants rather than hard-coded strings:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { ENV_VARS, requireEnv, validateBaseEnv } from '@forumone/throughline-core'
|
|
113
|
+
|
|
114
|
+
validateBaseEnv() // throws on missing PAYLOAD_SECRET / DATABASE_URI / NEXT_PUBLIC_SERVER_URL
|
|
115
|
+
|
|
116
|
+
const apiKey = requireEnv(ENV_VARS.PUBLISHING_SERVER_API_KEY)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Why all of this lives in one package
|
|
120
|
+
|
|
121
|
+
Server packages (Component, Publishing, Approvals, Audit Query, Forms, Integrations) all depend on the same audit log, the same authentication pattern, and the same event taxonomy. Splitting these across packages would create circular dependencies — every server package would need the audit writer, and an audit-only package would need to know about every server. Consolidating the plumbing here keeps the dependency graph one-way: core → server packages → client app.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Access, CollectionConfig } from 'payload';
|
|
2
|
+
export interface AuditCollectionOptions {
|
|
3
|
+
/** Override the collection slug. Default: `'audit-events'`. */
|
|
4
|
+
slug?: string;
|
|
5
|
+
/**
|
|
6
|
+
* Read access function. Receives the standard Payload access args.
|
|
7
|
+
* Defaults to admin/editor roles.
|
|
8
|
+
*/
|
|
9
|
+
readAccess?: Access;
|
|
10
|
+
}
|
|
11
|
+
export declare const DEFAULT_AUDIT_SLUG = "audit-events";
|
|
12
|
+
/**
|
|
13
|
+
* Builds the audit-events collection config. The collection is read-only
|
|
14
|
+
* from outside the writer: `create`, `update`, and `delete` are denied
|
|
15
|
+
* for all callers; the writer uses Payload's local API which bypasses
|
|
16
|
+
* these checks.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createAuditCollection(options?: AuditCollectionOptions): CollectionConfig;
|
|
19
|
+
//# sourceMappingURL=collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../src/audit/collection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAGvD,MAAM,WAAW,sBAAsB;IACrC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,kBAAkB,iBAAiB,CAAA;AAOhD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,gBAAgB,CA+F5F"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { AUDIT_ACTIONS, AUDIT_MCP_SERVERS } from './types.js';
|
|
2
|
+
export const DEFAULT_AUDIT_SLUG = 'audit-events';
|
|
3
|
+
const defaultReadAccess = ({ req }) => {
|
|
4
|
+
const roles = req.user?.['roles'] ?? [];
|
|
5
|
+
return roles.includes('admin') || roles.includes('editor');
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Builds the audit-events collection config. The collection is read-only
|
|
9
|
+
* from outside the writer: `create`, `update`, and `delete` are denied
|
|
10
|
+
* for all callers; the writer uses Payload's local API which bypasses
|
|
11
|
+
* these checks.
|
|
12
|
+
*/
|
|
13
|
+
export function createAuditCollection(options = {}) {
|
|
14
|
+
const slug = options.slug ?? DEFAULT_AUDIT_SLUG;
|
|
15
|
+
return {
|
|
16
|
+
slug,
|
|
17
|
+
admin: {
|
|
18
|
+
useAsTitle: 'summary',
|
|
19
|
+
defaultColumns: ['createdAt', 'actor', 'action', 'targetCollection', 'targetId'],
|
|
20
|
+
description: 'Immutable record of every consequential action in the system. Read-only through the admin.',
|
|
21
|
+
},
|
|
22
|
+
access: {
|
|
23
|
+
read: options.readAccess ?? defaultReadAccess,
|
|
24
|
+
create: () => false,
|
|
25
|
+
update: () => false,
|
|
26
|
+
delete: () => false,
|
|
27
|
+
},
|
|
28
|
+
fields: [
|
|
29
|
+
{
|
|
30
|
+
name: 'createdAt',
|
|
31
|
+
type: 'date',
|
|
32
|
+
required: true,
|
|
33
|
+
defaultValue: () => new Date().toISOString(),
|
|
34
|
+
admin: { position: 'sidebar', readOnly: true },
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'actor',
|
|
38
|
+
type: 'group',
|
|
39
|
+
fields: [
|
|
40
|
+
{
|
|
41
|
+
name: 'type',
|
|
42
|
+
type: 'select',
|
|
43
|
+
required: true,
|
|
44
|
+
options: [
|
|
45
|
+
{ label: 'User', value: 'user' },
|
|
46
|
+
{ label: 'System', value: 'system' },
|
|
47
|
+
{ label: 'Integration', value: 'integration' },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{ name: 'userId', type: 'text' },
|
|
51
|
+
{ name: 'userName', type: 'text' },
|
|
52
|
+
{ name: 'apiKeyName', type: 'text' },
|
|
53
|
+
{ name: 'apiKeyId', type: 'text' },
|
|
54
|
+
{ name: 'sessionId', type: 'text' },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'action',
|
|
59
|
+
type: 'select',
|
|
60
|
+
required: true,
|
|
61
|
+
options: AUDIT_ACTIONS.map((value) => ({ label: value, value })),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'mcpServer',
|
|
65
|
+
type: 'select',
|
|
66
|
+
required: true,
|
|
67
|
+
options: AUDIT_MCP_SERVERS.map((value) => ({ label: value, value })),
|
|
68
|
+
},
|
|
69
|
+
{ name: 'mcpTool', type: 'text', required: true },
|
|
70
|
+
{ name: 'targetCollection', type: 'text' },
|
|
71
|
+
{ name: 'targetId', type: 'text' },
|
|
72
|
+
{ name: 'targetTitle', type: 'text' },
|
|
73
|
+
{
|
|
74
|
+
name: 'prompt',
|
|
75
|
+
type: 'textarea',
|
|
76
|
+
admin: { description: "The user's natural-language prompt, if surfaced via _meta." },
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'reasoning',
|
|
80
|
+
type: 'textarea',
|
|
81
|
+
admin: { description: "Claude's reasoning, if surfaced via _meta." },
|
|
82
|
+
},
|
|
83
|
+
{ name: 'changesSummary', type: 'textarea' },
|
|
84
|
+
{ name: 'summary', type: 'text', required: true },
|
|
85
|
+
{
|
|
86
|
+
name: 'diff',
|
|
87
|
+
type: 'json',
|
|
88
|
+
admin: {
|
|
89
|
+
description: 'Before/after fields for update operations; null for reads.',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{ name: 'success', type: 'checkbox', defaultValue: true },
|
|
93
|
+
{ name: 'errorMessage', type: 'text' },
|
|
94
|
+
{ name: 'approvalRequestId', type: 'text' },
|
|
95
|
+
{ name: 'integrationId', type: 'text' },
|
|
96
|
+
],
|
|
97
|
+
indexes: [
|
|
98
|
+
{ fields: ['createdAt'] },
|
|
99
|
+
{ fields: ['actor.userId', 'createdAt'] },
|
|
100
|
+
{ fields: ['targetCollection', 'targetId', 'createdAt'] },
|
|
101
|
+
{ fields: ['action', 'createdAt'] },
|
|
102
|
+
{ fields: ['mcpServer', 'createdAt'] },
|
|
103
|
+
],
|
|
104
|
+
timestamps: false,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collection.js","sourceRoot":"","sources":["../../src/audit/collection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { auditPlugin, getAuditWriter } from './plugin.js';
|
|
2
|
+
export type { AuditPluginOptions } from './plugin.js';
|
|
3
|
+
export { createAuditCollection, DEFAULT_AUDIT_SLUG } from './collection.js';
|
|
4
|
+
export type { AuditCollectionOptions } from './collection.js';
|
|
5
|
+
export { createAuditWriter } from './writer.js';
|
|
6
|
+
export type { AuditWriter, AuditWriterOptions, AuditEventInput, AuditActor } from './writer.js';
|
|
7
|
+
export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS } from './types.js';
|
|
8
|
+
export type { AuditAction, AuditMcpServer } from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACzD,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAC3E,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE/F,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC7D,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { auditPlugin, getAuditWriter } from './plugin.js';
|
|
2
|
+
export { createAuditCollection, DEFAULT_AUDIT_SLUG } from './collection.js';
|
|
3
|
+
export { createAuditWriter } from './writer.js';
|
|
4
|
+
export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS } from './types.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGzD,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAG3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Inngest } from 'inngest';
|
|
2
|
+
import { type BaseCorePluginOptions, type CorePlugin } from '@forumone/throughline-plugin-contract';
|
|
3
|
+
import { type AuditCollectionOptions } from './collection.js';
|
|
4
|
+
import { type AuditWriter } from './writer.js';
|
|
5
|
+
export interface AuditPluginOptions extends BaseCorePluginOptions, AuditCollectionOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Inngest client used to fire `audit/event.recorded` events. If omitted,
|
|
8
|
+
* audit writes still persist; downstream subscribers simply won't receive
|
|
9
|
+
* events.
|
|
10
|
+
*/
|
|
11
|
+
inngest?: Inngest;
|
|
12
|
+
}
|
|
13
|
+
export declare const auditPlugin: CorePlugin<AuditPluginOptions>;
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves the audit writer attached to a Payload instance by `auditPlugin`.
|
|
16
|
+
* Plugins that depend on auditing call this in their own `onInit` to record
|
|
17
|
+
* events without importing this package's writer factory directly.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getAuditWriter(payload: object): AuditWriter;
|
|
20
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/audit/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EAEhB,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAyB,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACpF,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAOjE,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB,EAAE,sBAAsB;IACvF;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,WAAW,EAAE,UAAU,CAAC,kBAAkB,CA8BtD,CAAA;AAWD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAQ3D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getPluginRegistry, } from '@forumone/throughline-plugin-contract';
|
|
2
|
+
import { createAuditCollection } from './collection.js';
|
|
3
|
+
import { createAuditWriter } from './writer.js';
|
|
4
|
+
import { defaultLogger } from '../logger/index.js';
|
|
5
|
+
const AUDIT_PLUGIN_ID = '@forumone/throughline-core/audit';
|
|
6
|
+
const AUDIT_PLUGIN_VERSION = '0.1.0';
|
|
7
|
+
const AUDIT_WRITER_SYMBOL = Symbol.for('@forumone/throughline/audit-writer');
|
|
8
|
+
export const auditPlugin = (options) => (incomingConfig) => {
|
|
9
|
+
if (options.enabled === false)
|
|
10
|
+
return incomingConfig;
|
|
11
|
+
const auditCollection = createAuditCollection(options);
|
|
12
|
+
return {
|
|
13
|
+
...incomingConfig,
|
|
14
|
+
collections: [...(incomingConfig.collections ?? []), auditCollection],
|
|
15
|
+
onInit: async (payload) => {
|
|
16
|
+
if (incomingConfig.onInit) {
|
|
17
|
+
await incomingConfig.onInit(payload);
|
|
18
|
+
}
|
|
19
|
+
const writer = createAuditWriter({
|
|
20
|
+
payload,
|
|
21
|
+
inngest: options.inngest,
|
|
22
|
+
collectionSlug: options.slug,
|
|
23
|
+
logger: options.logger ?? defaultLogger,
|
|
24
|
+
});
|
|
25
|
+
attachAuditWriter(payload, writer);
|
|
26
|
+
const registry = getPluginRegistry(payload);
|
|
27
|
+
registry.register({
|
|
28
|
+
id: AUDIT_PLUGIN_ID,
|
|
29
|
+
version: AUDIT_PLUGIN_VERSION,
|
|
30
|
+
capabilities: ['audit-log', 'audit-write'],
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
function attachAuditWriter(target, writer) {
|
|
36
|
+
Object.defineProperty(target, AUDIT_WRITER_SYMBOL, {
|
|
37
|
+
value: writer,
|
|
38
|
+
enumerable: false,
|
|
39
|
+
writable: false,
|
|
40
|
+
configurable: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Retrieves the audit writer attached to a Payload instance by `auditPlugin`.
|
|
45
|
+
* Plugins that depend on auditing call this in their own `onInit` to record
|
|
46
|
+
* events without importing this package's writer factory directly.
|
|
47
|
+
*/
|
|
48
|
+
export function getAuditWriter(payload) {
|
|
49
|
+
const writer = payload[AUDIT_WRITER_SYMBOL];
|
|
50
|
+
if (!writer) {
|
|
51
|
+
throw new Error('Audit writer not found. Ensure `auditPlugin` is registered in your Payload config before any plugin that depends on it.');
|
|
52
|
+
}
|
|
53
|
+
return writer;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/audit/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,iBAAiB,GAClB,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,qBAAqB,EAA+B,MAAM,iBAAiB,CAAA;AACpF,OAAO,EAAE,iBAAiB,EAAoB,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,MAAM,eAAe,GAAG,kCAAkC,CAAA;AAC1D,MAAM,oBAAoB,GAAG,OAAO,CAAA;AACpC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;AAW5E,MAAM,CAAC,MAAM,WAAW,GAAmC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,cAAc,EAAE,EAAE;IACzF,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,cAAc,CAAA;IAEpD,MAAM,eAAe,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAEtD,OAAO;QACL,GAAG,cAAc;QACjB,WAAW,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,eAAe,CAAC;QACrE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACxB,IAAI,cAAc,CAAC,MAAM,EAAE,CAAC;gBAC1B,MAAM,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACtC,CAAC;YAED,MAAM,MAAM,GAAG,iBAAiB,CAAC;gBAC/B,OAAO;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,cAAc,EAAE,OAAO,CAAC,IAAI;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,aAAa;aACxC,CAAC,CAAA;YAEF,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAElC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;YAC3C,QAAQ,CAAC,QAAQ,CAAC;gBAChB,EAAE,EAAE,eAAe;gBACnB,OAAO,EAAE,oBAAoB;gBAC7B,YAAY,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC;aAC3C,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAED,SAAS,iBAAiB,CAAC,MAAc,EAAE,MAAmB;IAC5D,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,mBAAmB,EAAE;QACjD,KAAK,EAAE,MAAM;QACb,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,KAAK;KACpB,CAAC,CAAA;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,MAAM,GAAI,OAAmC,CAAC,mBAAmB,CAAC,CAAA;IACxE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,yHAAyH,CAC1H,CAAA;IACH,CAAC;IACD,OAAO,MAAqB,CAAA;AAC9B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical action names for the audit log. Every server package picks
|
|
3
|
+
* actions from this list rather than introducing free-form strings, so
|
|
4
|
+
* audit queries (C8) can build on a known taxonomy.
|
|
5
|
+
*/
|
|
6
|
+
export declare const AUDIT_ACTIONS: readonly ["content.find", "content.create", "content.update", "content.delete", "design.list", "design.suggest", "design.validate", "design.get_contract", "design.find_anti_pattern", "publishing.draft", "publishing.publish", "publishing.unpublish", "publishing.schedule", "publishing.rollback", "approval.requested", "approval.granted", "approval.declined", "approval.changes_requested", "approval.expired", "approval.discussed", "form.created", "form.updated", "form.submission_received", "integration.synced", "integration.failed", "system.error", "system.healthcheck"];
|
|
7
|
+
export type AuditAction = (typeof AUDIT_ACTIONS)[number];
|
|
8
|
+
/** MCP server identifiers. Keep in sync with the planned server packages. */
|
|
9
|
+
export declare const AUDIT_MCP_SERVERS: readonly ["payload", "component", "publishing", "approvals", "audit", "forms", "integrations"];
|
|
10
|
+
export type AuditMcpServer = (typeof AUDIT_MCP_SERVERS)[number];
|
|
11
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/audit/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,aAAa,6jBA4BhB,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAA;AAExD,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,gGAQpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical action names for the audit log. Every server package picks
|
|
3
|
+
* actions from this list rather than introducing free-form strings, so
|
|
4
|
+
* audit queries (C8) can build on a known taxonomy.
|
|
5
|
+
*/
|
|
6
|
+
export const AUDIT_ACTIONS = [
|
|
7
|
+
'content.find',
|
|
8
|
+
'content.create',
|
|
9
|
+
'content.update',
|
|
10
|
+
'content.delete',
|
|
11
|
+
'design.list',
|
|
12
|
+
'design.suggest',
|
|
13
|
+
'design.validate',
|
|
14
|
+
'design.get_contract',
|
|
15
|
+
'design.find_anti_pattern',
|
|
16
|
+
'publishing.draft',
|
|
17
|
+
'publishing.publish',
|
|
18
|
+
'publishing.unpublish',
|
|
19
|
+
'publishing.schedule',
|
|
20
|
+
'publishing.rollback',
|
|
21
|
+
'approval.requested',
|
|
22
|
+
'approval.granted',
|
|
23
|
+
'approval.declined',
|
|
24
|
+
'approval.changes_requested',
|
|
25
|
+
'approval.expired',
|
|
26
|
+
'approval.discussed',
|
|
27
|
+
'form.created',
|
|
28
|
+
'form.updated',
|
|
29
|
+
'form.submission_received',
|
|
30
|
+
'integration.synced',
|
|
31
|
+
'integration.failed',
|
|
32
|
+
'system.error',
|
|
33
|
+
'system.healthcheck',
|
|
34
|
+
];
|
|
35
|
+
/** MCP server identifiers. Keep in sync with the planned server packages. */
|
|
36
|
+
export const AUDIT_MCP_SERVERS = [
|
|
37
|
+
'payload',
|
|
38
|
+
'component',
|
|
39
|
+
'publishing',
|
|
40
|
+
'approvals',
|
|
41
|
+
'audit',
|
|
42
|
+
'forms',
|
|
43
|
+
'integrations',
|
|
44
|
+
];
|
|
45
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/audit/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,cAAc;IACd,gBAAgB;IAChB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,gBAAgB;IAChB,iBAAiB;IACjB,qBAAqB;IACrB,0BAA0B;IAC1B,kBAAkB;IAClB,oBAAoB;IACpB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,oBAAoB;IACpB,kBAAkB;IAClB,mBAAmB;IACnB,4BAA4B;IAC5B,kBAAkB;IAClB,oBAAoB;IACpB,cAAc;IACd,cAAc;IACd,0BAA0B;IAC1B,oBAAoB;IACpB,oBAAoB;IACpB,cAAc;IACd,oBAAoB;CACZ,CAAA;AAIV,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,SAAS;IACT,WAAW;IACX,YAAY;IACZ,WAAW;IACX,OAAO;IACP,OAAO;IACP,cAAc;CACN,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Inngest } from 'inngest';
|
|
2
|
+
import type { Payload } from 'payload';
|
|
3
|
+
import type { Logger } from '@forumone/throughline-plugin-contract';
|
|
4
|
+
import type { AuditAction, AuditMcpServer } from './types.js';
|
|
5
|
+
export interface AuditActor {
|
|
6
|
+
type: 'user' | 'system' | 'integration';
|
|
7
|
+
userId?: string | undefined;
|
|
8
|
+
userName?: string | undefined;
|
|
9
|
+
apiKeyName?: string | undefined;
|
|
10
|
+
apiKeyId?: string | undefined;
|
|
11
|
+
sessionId?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface AuditEventInput {
|
|
14
|
+
actor: AuditActor;
|
|
15
|
+
action: AuditAction;
|
|
16
|
+
mcpServer: AuditMcpServer;
|
|
17
|
+
mcpTool: string;
|
|
18
|
+
targetCollection?: string | undefined;
|
|
19
|
+
targetId?: string | undefined;
|
|
20
|
+
targetTitle?: string | undefined;
|
|
21
|
+
prompt?: string | undefined;
|
|
22
|
+
reasoning?: string | undefined;
|
|
23
|
+
changesSummary?: string | undefined;
|
|
24
|
+
summary?: string | undefined;
|
|
25
|
+
diff?: Record<string, {
|
|
26
|
+
before: unknown;
|
|
27
|
+
after: unknown;
|
|
28
|
+
}> | null | undefined;
|
|
29
|
+
success?: boolean | undefined;
|
|
30
|
+
errorMessage?: string | undefined;
|
|
31
|
+
approvalRequestId?: string | undefined;
|
|
32
|
+
integrationId?: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
export interface AuditWriterOptions {
|
|
35
|
+
payload: Payload;
|
|
36
|
+
inngest?: Inngest | undefined;
|
|
37
|
+
collectionSlug?: string | undefined;
|
|
38
|
+
logger?: Logger | undefined;
|
|
39
|
+
}
|
|
40
|
+
export type AuditWriter = (event: AuditEventInput) => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Returns a fire-and-forget audit writer. The writer never throws — failures
|
|
43
|
+
* log via `options.logger` (or `console`). Audit failures must not break
|
|
44
|
+
* the originating action.
|
|
45
|
+
*
|
|
46
|
+
* If `inngest` is provided the writer also fires an `audit/event.recorded`
|
|
47
|
+
* event so subscribers (email, integrations, healthchecks) can react.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createAuditWriter(options: AuditWriterOptions): AuditWriter;
|
|
50
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/audit/writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE7D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,aAAa,CAAA;IACvC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;IACnB,SAAS,EAAE,cAAc,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IAC7E,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAEnE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CA0D1E"}
|