agent-comms 4.1.10 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +5 -1
- package/dist/bridges/cc-peer/approval-commands.d.ts +26 -0
- package/dist/bridges/cc-peer/approval-commands.d.ts.map +1 -0
- package/dist/bridges/cc-peer/approval-commands.js +56 -0
- package/dist/bridges/cc-peer/approval-commands.js.map +1 -0
- package/dist/bridges/cc-peer/bridge.d.ts +2 -0
- package/dist/bridges/cc-peer/bridge.d.ts.map +1 -1
- package/dist/bridges/cc-peer/bridge.js +16 -8
- package/dist/bridges/cc-peer/bridge.js.map +1 -1
- package/dist/bridges/cc-peer/default-front.d.ts +2 -0
- package/dist/bridges/cc-peer/default-front.d.ts.map +1 -1
- package/dist/bridges/cc-peer/default-front.js +1 -0
- package/dist/bridges/cc-peer/default-front.js.map +1 -1
- package/dist/bridges/cc-peer/front-relay.d.ts +2 -0
- package/dist/bridges/cc-peer/front-relay.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-relay.js +17 -9
- package/dist/bridges/cc-peer/front-relay.js.map +1 -1
- package/dist/bridges/cc-peer/front-runtime.d.ts +2 -0
- package/dist/bridges/cc-peer/front-runtime.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-runtime.js +2 -0
- package/dist/bridges/cc-peer/front-runtime.js.map +1 -1
- package/dist/bridges/cc-peer/run.d.ts.map +1 -1
- package/dist/bridges/cc-peer/run.js +5 -1
- package/dist/bridges/cc-peer/run.js.map +1 -1
- package/dist/bridges/user/web/dist/mesh-worker.js +1 -1
- package/dist/bridges/user/web/dist/sw.js +1 -1
- package/dist/core/bridge.d.ts +4 -0
- package/dist/core/bridge.d.ts.map +1 -1
- package/dist/core/bridge.js +19 -0
- package/dist/core/bridge.js.map +1 -1
- package/dist/core/dm-grant-actions.d.ts +20 -0
- package/dist/core/dm-grant-actions.d.ts.map +1 -0
- package/dist/core/dm-grant-actions.js +49 -0
- package/dist/core/dm-grant-actions.js.map +1 -0
- package/dist/core/identity-store.d.ts +16 -0
- package/dist/core/identity-store.d.ts.map +1 -1
- package/dist/core/identity-store.js +5 -3
- package/dist/core/identity-store.js.map +1 -1
- package/dist/core/token-text.d.ts +9 -0
- package/dist/core/token-text.d.ts.map +1 -0
- package/dist/core/token-text.js +24 -0
- package/dist/core/token-text.js.map +1 -0
- package/dist/core/tool.d.ts +7 -0
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +7 -0
- package/dist/core/tool.js.map +1 -1
- package/dist/core/types.d.ts +20 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -1
- package/dist/test/cc-peer-approval-commands.unit.test.d.ts +2 -0
- package/dist/test/cc-peer-approval-commands.unit.test.d.ts.map +1 -0
- package/dist/test/cc-peer-approval-commands.unit.test.js +110 -0
- package/dist/test/cc-peer-approval-commands.unit.test.js.map +1 -0
- package/dist/test/cc-peer-bridge.unit.test.js +107 -0
- package/dist/test/cc-peer-bridge.unit.test.js.map +1 -1
- package/dist/test/cc-peer-front-relay.unit.test.js +113 -0
- package/dist/test/cc-peer-front-relay.unit.test.js.map +1 -1
- package/dist/test/cc-peer-fronted-approval.integration.test.d.ts +5 -0
- package/dist/test/cc-peer-fronted-approval.integration.test.d.ts.map +1 -0
- package/dist/test/cc-peer-fronted-approval.integration.test.js +125 -0
- package/dist/test/cc-peer-fronted-approval.integration.test.js.map +1 -0
- package/dist/test/dm-grant-actions.unit.test.d.ts +2 -0
- package/dist/test/dm-grant-actions.unit.test.d.ts.map +1 -0
- package/dist/test/dm-grant-actions.unit.test.js +72 -0
- package/dist/test/dm-grant-actions.unit.test.js.map +1 -0
- package/dist/test/dm-grant-tool.integration.test.d.ts +5 -0
- package/dist/test/dm-grant-tool.integration.test.d.ts.map +1 -0
- package/dist/test/dm-grant-tool.integration.test.js +145 -0
- package/dist/test/dm-grant-tool.integration.test.js.map +1 -0
- package/dist/test/token-text.unit.test.d.ts +2 -0
- package/dist/test/token-text.unit.test.d.ts.map +1 -0
- package/dist/test/token-text.unit.test.js +46 -0
- package/dist/test/token-text.unit.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the dm_admit, dm_use_grant and dm_revoke tool actions, against a fake store so no mesh is involved.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { dmAdmit, dmRevoke, dmUseGrant } from "../core/dm-grant-actions.js";
|
|
6
|
+
import { encodeTokenText } from "../core/token-text.js";
|
|
7
|
+
/** A device-id is a 64-character lowercase hex SHA-256 digest. */
|
|
8
|
+
const DEVICE_ID_HEX_LENGTH = 64;
|
|
9
|
+
const SENDER = "a".repeat(DEVICE_ID_HEX_LENGTH);
|
|
10
|
+
const RECEIVER = "b".repeat(DEVICE_ID_HEX_LENGTH);
|
|
11
|
+
const bytes = (text) => Uint8Array.from(new TextEncoder().encode(text));
|
|
12
|
+
const GRANT = [
|
|
13
|
+
bytes("protected"),
|
|
14
|
+
{},
|
|
15
|
+
bytes("payload"),
|
|
16
|
+
bytes("signature"),
|
|
17
|
+
];
|
|
18
|
+
describe("dmAdmit", () => {
|
|
19
|
+
it("mints a grant for the named device and returns it with the exact call the sender should make", async () => {
|
|
20
|
+
const admitAgentForDm = vi.fn(async () => Promise.resolve(GRANT));
|
|
21
|
+
const result = await dmAdmit({ admitAgentForDm }, { action: "dm_admit", target: SENDER }, RECEIVER);
|
|
22
|
+
expect(admitAgentForDm).toHaveBeenCalledWith(SENDER);
|
|
23
|
+
expect(result.isError).toBe(false);
|
|
24
|
+
expect(result.content).toContain(encodeTokenText(GRANT));
|
|
25
|
+
expect(result.content).toContain(`dm_use_grant with target ${RECEIVER}`);
|
|
26
|
+
});
|
|
27
|
+
it("reports that grants are unavailable on a store that cannot mint them", async () => {
|
|
28
|
+
const result = await dmAdmit({}, { action: "dm_admit", target: SENDER }, RECEIVER);
|
|
29
|
+
expect(result.isError).toBe(true);
|
|
30
|
+
expect(result.content).toContain("not available");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("dmUseGrant", () => {
|
|
34
|
+
it("presents the decoded grant to the counterpart and reports DM access", async () => {
|
|
35
|
+
const requestDmAccess = vi.fn(async () => Promise.resolve());
|
|
36
|
+
const result = await dmUseGrant({ requestDmAccess }, {
|
|
37
|
+
action: "dm_use_grant",
|
|
38
|
+
target: RECEIVER,
|
|
39
|
+
grant: encodeTokenText(GRANT),
|
|
40
|
+
});
|
|
41
|
+
expect(requestDmAccess).toHaveBeenCalledWith(RECEIVER, GRANT);
|
|
42
|
+
expect(result.isError).toBe(false);
|
|
43
|
+
expect(result.content).toContain(RECEIVER);
|
|
44
|
+
});
|
|
45
|
+
it("refuses text that is not a token before contacting anyone", async () => {
|
|
46
|
+
const requestDmAccess = vi.fn(async () => Promise.resolve());
|
|
47
|
+
await expect(dmUseGrant({ requestDmAccess }, { action: "dm_use_grant", target: RECEIVER, grant: "not a token" })).rejects.toThrow(/not a valid capability token/);
|
|
48
|
+
expect(requestDmAccess).not.toHaveBeenCalled();
|
|
49
|
+
});
|
|
50
|
+
it("reports that grants are unavailable on a store that cannot present them", async () => {
|
|
51
|
+
const result = await dmUseGrant({}, {
|
|
52
|
+
action: "dm_use_grant",
|
|
53
|
+
target: RECEIVER,
|
|
54
|
+
grant: encodeTokenText(GRANT),
|
|
55
|
+
});
|
|
56
|
+
expect(result.isError).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe("dmRevoke", () => {
|
|
60
|
+
it("revokes the named device's grant and says so", async () => {
|
|
61
|
+
const revokeAgentDmAccess = vi.fn(async () => Promise.resolve());
|
|
62
|
+
const result = await dmRevoke({ revokeAgentDmAccess }, { action: "dm_revoke", target: SENDER });
|
|
63
|
+
expect(revokeAgentDmAccess).toHaveBeenCalledWith(SENDER);
|
|
64
|
+
expect(result.isError).toBe(false);
|
|
65
|
+
expect(result.content).toContain(SENDER);
|
|
66
|
+
});
|
|
67
|
+
it("reports that revoking is unavailable on a store that cannot", async () => {
|
|
68
|
+
const result = await dmRevoke({}, { action: "dm_revoke", target: SENDER });
|
|
69
|
+
expect(result.isError).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=dm-grant-actions.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dm-grant-actions.unit.test.js","sourceRoot":"","sources":["../../src/test/dm-grant-actions.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for pre-authorised DMs through the tool surface: the receiver admits the sender (dm_admit), the sender presents the grant (dm_use_grant), and the first DM is delivered with no decision at the receiving end. A grant minted for someone else, or revoked, is refused.
|
|
3
|
+
*/
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=dm-grant-tool.integration.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dm-grant-tool.integration.test.d.ts","sourceRoot":"","sources":["../../src/test/dm-grant-tool.integration.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for pre-authorised DMs through the tool surface: the receiver admits the sender (dm_admit), the sender presents the grant (dm_use_grant), and the first DM is delivered with no decision at the receiving end. A grant minted for someone else, or revoked, is refused.
|
|
3
|
+
*/
|
|
4
|
+
import { test, expect } from "vitest";
|
|
5
|
+
import { MeshStore } from "../core/mesh-store.js";
|
|
6
|
+
import { CommsTool } from "../core/tool.js";
|
|
7
|
+
import { dmRoomPath } from "../core/room-path.js";
|
|
8
|
+
import { waitFor, wireTestTransport } from "./test-transport.js";
|
|
9
|
+
let nextPort = 25_450;
|
|
10
|
+
function freshPort() {
|
|
11
|
+
nextPort += 1;
|
|
12
|
+
return nextPort;
|
|
13
|
+
}
|
|
14
|
+
async function party(port, name) {
|
|
15
|
+
const store = new MeshStore({ coordinatorPort: port });
|
|
16
|
+
await wireTestTransport(store);
|
|
17
|
+
await store.init();
|
|
18
|
+
await store.registerAgent({
|
|
19
|
+
name,
|
|
20
|
+
harness: "test",
|
|
21
|
+
cwd: `/test/${name}`,
|
|
22
|
+
pid: process.pid,
|
|
23
|
+
visibility: "visible",
|
|
24
|
+
tags: [],
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
store,
|
|
28
|
+
tool: new CommsTool(store),
|
|
29
|
+
ctx: {
|
|
30
|
+
agentId: store.peerId,
|
|
31
|
+
harness: "test",
|
|
32
|
+
cwd: `/test/${name}`,
|
|
33
|
+
pid: process.pid,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function connectedPair() {
|
|
38
|
+
const port = freshPort();
|
|
39
|
+
const sender = await party(port, "sender");
|
|
40
|
+
const receiver = await party(port, "receiver");
|
|
41
|
+
await waitFor(() => sender.store.serialise().agents[receiver.store.peerId] !== undefined, "the sender sees the receiver");
|
|
42
|
+
return { sender, receiver };
|
|
43
|
+
}
|
|
44
|
+
/** The grant text in a dm_admit result: its last line. */
|
|
45
|
+
function grantFrom(content) {
|
|
46
|
+
const line = content.split("\n").at(-1);
|
|
47
|
+
if (line === undefined || line === "")
|
|
48
|
+
throw new Error("no grant in result");
|
|
49
|
+
return line;
|
|
50
|
+
}
|
|
51
|
+
test("a grant lets the sender's first DM through with no decision at the receiver", async () => {
|
|
52
|
+
const { sender, receiver } = await connectedPair();
|
|
53
|
+
try {
|
|
54
|
+
const admitted = await receiver.tool.handle(receiver.ctx, {
|
|
55
|
+
action: "dm_admit",
|
|
56
|
+
target: sender.store.peerId,
|
|
57
|
+
});
|
|
58
|
+
expect(admitted.isError).toBe(false);
|
|
59
|
+
expect(admitted.content).toContain(`dm_use_grant with target ${receiver.store.peerId}`);
|
|
60
|
+
const used = await sender.tool.handle(sender.ctx, {
|
|
61
|
+
action: "dm_use_grant",
|
|
62
|
+
target: receiver.store.peerId,
|
|
63
|
+
grant: grantFrom(admitted.content),
|
|
64
|
+
});
|
|
65
|
+
expect(used.isError).toBe(false);
|
|
66
|
+
expect(receiver.store.listPendingRoomJoins()).toEqual([]);
|
|
67
|
+
const sent = await sender.tool.handle(sender.ctx, {
|
|
68
|
+
action: "dm",
|
|
69
|
+
target: receiver.store.peerId,
|
|
70
|
+
content: "no decision needed",
|
|
71
|
+
});
|
|
72
|
+
expect(sent.isError).toBe(false);
|
|
73
|
+
const dmPath = dmRoomPath(sender.store.peerId, receiver.store.peerId);
|
|
74
|
+
await waitFor(() => (receiver.store.serialise().dms[dmPath] ?? []).some((m) => m.content === "no decision needed"), "the receiver gets the DM");
|
|
75
|
+
expect(receiver.store.listPendingRoomJoins()).toEqual([]);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await receiver.store.shutdown();
|
|
79
|
+
await sender.store.shutdown();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
test("a grant minted for a different device is refused", async () => {
|
|
83
|
+
const { sender, receiver } = await connectedPair();
|
|
84
|
+
try {
|
|
85
|
+
const someoneElse = "c".repeat(sender.store.peerId.length);
|
|
86
|
+
const admitted = await receiver.tool.handle(receiver.ctx, {
|
|
87
|
+
action: "dm_admit",
|
|
88
|
+
target: someoneElse,
|
|
89
|
+
});
|
|
90
|
+
const used = await sender.tool.handle(sender.ctx, {
|
|
91
|
+
action: "dm_use_grant",
|
|
92
|
+
target: receiver.store.peerId,
|
|
93
|
+
grant: grantFrom(admitted.content),
|
|
94
|
+
});
|
|
95
|
+
expect(used.isError).toBe(true);
|
|
96
|
+
expect(used.content).toMatch(/refused/);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await receiver.store.shutdown();
|
|
100
|
+
await sender.store.shutdown();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
test("a revoked grant is refused", async () => {
|
|
104
|
+
const { sender, receiver } = await connectedPair();
|
|
105
|
+
try {
|
|
106
|
+
const admitted = await receiver.tool.handle(receiver.ctx, {
|
|
107
|
+
action: "dm_admit",
|
|
108
|
+
target: sender.store.peerId,
|
|
109
|
+
});
|
|
110
|
+
const revoked = await receiver.tool.handle(receiver.ctx, {
|
|
111
|
+
action: "dm_revoke",
|
|
112
|
+
target: sender.store.peerId,
|
|
113
|
+
});
|
|
114
|
+
expect(revoked.isError).toBe(false);
|
|
115
|
+
const used = await sender.tool.handle(sender.ctx, {
|
|
116
|
+
action: "dm_use_grant",
|
|
117
|
+
target: receiver.store.peerId,
|
|
118
|
+
grant: grantFrom(admitted.content),
|
|
119
|
+
});
|
|
120
|
+
expect(used.isError).toBe(true);
|
|
121
|
+
expect(used.content).toMatch(/refused/);
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
await receiver.store.shutdown();
|
|
125
|
+
await sender.store.shutdown();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
test("dm_use_grant with text that is not a grant fails without contacting the receiver", async () => {
|
|
129
|
+
const { sender, receiver } = await connectedPair();
|
|
130
|
+
try {
|
|
131
|
+
const used = await sender.tool.handle(sender.ctx, {
|
|
132
|
+
action: "dm_use_grant",
|
|
133
|
+
target: receiver.store.peerId,
|
|
134
|
+
grant: "this is not a grant",
|
|
135
|
+
});
|
|
136
|
+
expect(used.isError).toBe(true);
|
|
137
|
+
expect(used.content).toMatch(/not a valid capability token/);
|
|
138
|
+
expect(receiver.store.listPendingRoomJoins()).toEqual([]);
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
await receiver.store.shutdown();
|
|
142
|
+
await sender.store.shutdown();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=dm-grant-tool.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dm-grant-tool.integration.test.js","sourceRoot":"","sources":["../../src/test/dm-grant-tool.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-text.unit.test.d.ts","sourceRoot":"","sources":["../../src/test/token-text.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the text form of a capability token, used to hand a dm:send grant from one person to another as a plain string.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { decodeTokenText, encodeTokenText } from "../core/token-text.js";
|
|
6
|
+
const bytes = (text) => Uint8Array.from(new TextEncoder().encode(text));
|
|
7
|
+
// A structurally valid stand-in: the codec only serialises a token's byte-string fields, it never verifies one.
|
|
8
|
+
const TOKEN = [
|
|
9
|
+
bytes("protected"),
|
|
10
|
+
{ "4": bytes("key-id") },
|
|
11
|
+
bytes("payload"),
|
|
12
|
+
bytes("signature"),
|
|
13
|
+
];
|
|
14
|
+
/** Long enough to be plausible text, short enough that it cannot be the whole token. */
|
|
15
|
+
const TRUNCATED_LENGTH = 10;
|
|
16
|
+
describe("token text", () => {
|
|
17
|
+
it("round-trips a token exactly", () => {
|
|
18
|
+
expect(decodeTokenText(encodeTokenText(TOKEN))).toEqual(TOKEN);
|
|
19
|
+
});
|
|
20
|
+
it("round-trips a token with no payload", () => {
|
|
21
|
+
const detached = [
|
|
22
|
+
bytes("protected"),
|
|
23
|
+
{},
|
|
24
|
+
null,
|
|
25
|
+
bytes("signature"),
|
|
26
|
+
];
|
|
27
|
+
expect(decodeTokenText(encodeTokenText(detached))).toEqual(detached);
|
|
28
|
+
});
|
|
29
|
+
it("encodes to a single line with no whitespace, safe to paste into a message", () => {
|
|
30
|
+
expect(encodeTokenText(TOKEN)).toMatch(/^\S+$/);
|
|
31
|
+
});
|
|
32
|
+
it("tolerates whitespace around a pasted token", () => {
|
|
33
|
+
expect(decodeTokenText(` ${encodeTokenText(TOKEN)}\n`)).toEqual(TOKEN);
|
|
34
|
+
});
|
|
35
|
+
it("rejects text that is not a token, with a message naming what was wrong", () => {
|
|
36
|
+
for (const text of [
|
|
37
|
+
"",
|
|
38
|
+
"not a token",
|
|
39
|
+
"e30",
|
|
40
|
+
encodeTokenText(TOKEN).slice(0, TRUNCATED_LENGTH),
|
|
41
|
+
]) {
|
|
42
|
+
expect(() => decodeTokenText(text)).toThrow(/not a valid capability token/);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=token-text.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-text.unit.test.js","sourceRoot":"","sources":["../../src/test/token-text.unit.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEzE,MAAM,KAAK,GAAG,CAAC,IAAY,EAA2B,EAAE,CACtD,UAAU,CAAC,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAElD,gHAAgH;AAChH,MAAM,KAAK,GAAoB;IAC7B,KAAK,CAAC,WAAW,CAAC;IAClB,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE;IACxB,KAAK,CAAC,SAAS,CAAC;IAChB,KAAK,CAAC,WAAW,CAAC;CACnB,CAAC;AAEF,wFAAwF;AACxF,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,QAAQ,GAAoB;YAChC,KAAK,CAAC,WAAW,CAAC;YAClB,EAAE;YACF,IAAI;YACJ,KAAK,CAAC,WAAW,CAAC;SACnB,CAAC;QACF,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,eAAe,CAAC,KAAK,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,KAAK,MAAM,IAAI,IAAI;YACjB,EAAE;YACF,aAAa;YACb,KAAK;YACL,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC;SAClD,EAAE,CAAC;YACF,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CACzC,8BAA8B,CAC/B,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED