@cargo-ai/cdk 1.0.3 → 1.0.5
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/README.md +64 -35
- package/build/src/cli/auth.d.ts +9 -0
- package/build/src/cli/auth.d.ts.map +1 -0
- package/build/src/cli/auth.js +100 -0
- package/build/src/cli/bin.d.ts +3 -0
- package/build/src/cli/bin.d.ts.map +1 -0
- package/build/src/cli/bin.js +9 -0
- package/build/src/cli/commands/deploy.d.ts +4 -0
- package/build/src/cli/commands/deploy.d.ts.map +1 -0
- package/build/src/cli/commands/deploy.js +531 -0
- package/build/src/cli/commands/index.d.ts +4 -0
- package/build/src/cli/commands/index.d.ts.map +1 -0
- package/build/src/cli/commands/index.js +11 -0
- package/build/src/cli/commands/init.d.ts +3 -0
- package/build/src/cli/commands/init.d.ts.map +1 -0
- package/build/src/cli/commands/init.js +76 -0
- package/build/src/cli/commands/inputTypes.d.ts +24 -0
- package/build/src/cli/commands/inputTypes.d.ts.map +1 -0
- package/build/src/cli/commands/inputTypes.js +273 -0
- package/build/src/cli/commands/templates.d.ts +6 -0
- package/build/src/cli/commands/templates.d.ts.map +1 -0
- package/build/src/cli/commands/templates.js +33 -0
- package/build/src/cli/commands/types.d.ts +4 -0
- package/build/src/cli/commands/types.d.ts.map +1 -0
- package/build/src/cli/commands/types.js +385 -0
- package/build/src/cli/index.d.ts +4 -0
- package/build/src/cli/index.d.ts.map +1 -0
- package/build/src/cli/index.js +20 -0
- package/build/src/cli/io.d.ts +38 -0
- package/build/src/cli/io.d.ts.map +1 -0
- package/build/src/cli/io.js +226 -0
- package/build/src/cli/version.d.ts +2 -0
- package/build/src/cli/version.d.ts.map +1 -0
- package/build/src/cli/version.js +25 -0
- package/build/src/deploy/executors.live.d.ts.map +1 -1
- package/build/src/deploy/executors.live.js +15 -3
- package/build/src/resources/bundle.d.ts +4 -2
- package/build/src/resources/bundle.d.ts.map +1 -1
- package/build/src/resources/bundle.js +11 -2
- package/build/src/resources/connector.d.ts.map +1 -1
- package/build/src/resources/connector.js +3 -2
- package/build/src/resources/worker.d.ts.map +1 -1
- package/build/src/resources/worker.js +14 -7
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -4
- package/templates/blank/package.json +3 -3
- package/templates/full/README.md +21 -20
- package/templates/full/apps/dashboard/index.html +1 -1
- package/templates/full/apps/dashboard/package.json +18 -3
- package/templates/full/apps/dashboard/src/App.tsx +57 -0
- package/templates/full/apps/dashboard/src/index.css +4 -0
- package/templates/full/apps/dashboard/src/main.tsx +13 -7
- package/templates/full/apps/dashboard/tailwind.config.ts +13 -0
- package/templates/full/apps/dashboard/tsconfig.json +10 -3
- package/templates/full/apps/dashboard/vite.config.ts +22 -0
- package/templates/full/package.json +3 -3
- package/templates/full/workers/webhook/package.json +12 -1
- package/templates/full/workers/webhook/src/index.ts +53 -0
- package/templates/full/workers/webhook/tsconfig.json +14 -0
- package/templates/full/workers/webhook.ts +9 -7
- package/templates/full/apps/dashboard/package-lock.json +0 -1080
- package/templates/full/workers/webhook/index.js +0 -12
- package/templates/full/workers/webhook/package-lock.json +0 -12
package/README.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# Cargo CDK
|
|
2
2
|
|
|
3
3
|
Define your entire Cargo workspace in code — connectors, models, plays, tools,
|
|
4
|
-
agents, MCP servers, context, segments, capacities, territories, folders, files, workers
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[Cargo CDK docs](https://docs.getcargo.ai/cdk/overview).
|
|
4
|
+
agents, MCP servers, context, segments, capacities, territories, folders, files, workers and apps — and deploy it
|
|
5
|
+
declaratively, the same way you'd manage cloud infrastructure with Pulumi or the
|
|
6
|
+
AWS CDK. For a complete overview, see the [Cargo CDK docs](https://docs.getcargo.ai/cdk/overview).
|
|
8
7
|
|
|
9
8
|
## Requirements
|
|
10
9
|
|
|
@@ -13,28 +12,45 @@ infrastructure with Pulumi or the AWS CDK. For a complete overview, see the
|
|
|
13
12
|
|
|
14
13
|
## Installation
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
`@cargo-ai/cdk` gives you both the `define*` builders you import in your resource
|
|
16
|
+
files **and** the `cargo-cdk` command to deploy them:
|
|
18
17
|
|
|
19
18
|
```bash
|
|
20
19
|
npm install @cargo-ai/cdk
|
|
20
|
+
npx @cargo-ai/cdk --help
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
`cargo-cdk` is a **project-local** tool — run it through the scaffolded `npm run`
|
|
24
|
+
scripts or `npx @cargo-ai/cdk`, the way you'd use the AWS CDK or SST. Don't install
|
|
25
|
+
it globally: a global `cargo-cdk` on your `PATH` would clash with the AWS CDK. (If you
|
|
26
|
+
also use the AWS CDK inside the same project, always call this one as
|
|
27
|
+
`npx @cargo-ai/cdk` to disambiguate.)
|
|
28
|
+
|
|
29
|
+
Authenticate with the Cargo CLI (or set a token for CI):
|
|
24
30
|
|
|
25
31
|
```bash
|
|
26
|
-
npm install -g @cargo-ai/cli
|
|
27
|
-
cargo-ai login --
|
|
32
|
+
npm install -g @cargo-ai/cli # the Cargo CLI — `cargo-ai login` + the `cargo-ai cdk` alias
|
|
33
|
+
cargo-ai login --oauth # browser sign-in
|
|
34
|
+
# …or, for CI / non-interactive (no CLI needed):
|
|
35
|
+
export CARGO_API_TOKEN=<your-api-token>
|
|
28
36
|
```
|
|
29
37
|
|
|
38
|
+
Login writes `~/.config/cargo-ai/credentials.json`, which `cargo-cdk` reads (along
|
|
39
|
+
with the `CARGO_API_TOKEN` / `CARGO_WORKSPACE_UUID` env vars). Everywhere below you
|
|
40
|
+
run the CDK one of two ways: **`npm run <script>`** for the everyday commands (a
|
|
41
|
+
scaffolded project wires up `types` / `plan` / `deploy`), or **`npx
|
|
42
|
+
@cargo-ai/cdk <command>`** for any command — both resolve the project-local
|
|
43
|
+
`cargo-cdk` bin. The `cargo-ai cdk <command>` alias works too.
|
|
44
|
+
|
|
30
45
|
## Quick start
|
|
31
46
|
|
|
32
|
-
Scaffold a starter project from a template
|
|
47
|
+
Scaffold a starter project from a template — `npx @cargo-ai/cdk` runs the CDK with
|
|
48
|
+
no global install:
|
|
33
49
|
|
|
34
50
|
```bash
|
|
35
|
-
cargo-ai
|
|
36
|
-
cargo-ai
|
|
37
|
-
cargo-ai
|
|
51
|
+
npx @cargo-ai/cdk init my-workspace --template full # every resource type, wired up
|
|
52
|
+
# or: npx @cargo-ai/cdk init my-workspace # minimal 'blank' template
|
|
53
|
+
# or: npx @cargo-ai/cdk init --list-templates # see all templates
|
|
38
54
|
cd my-workspace && npm install
|
|
39
55
|
```
|
|
40
56
|
|
|
@@ -48,7 +64,7 @@ import { defineConnector, defineModel, secret } from "@cargo-ai/cdk";
|
|
|
48
64
|
// `secret()` reads the value at deploy time and keeps it out of state and the
|
|
49
65
|
// content hash — use it for credentials. The config shape is per-integration
|
|
50
66
|
// (HubSpot takes a Private App token or an OAuth refresh token); run
|
|
51
|
-
// `cargo-ai
|
|
67
|
+
// `npx @cargo-ai/cdk types` to have it type-checked (see Typed config below).
|
|
52
68
|
export const hubspot = defineConnector("hubspot", {
|
|
53
69
|
integration: "hubspot",
|
|
54
70
|
config: { method: "privateApp", accessToken: secret("HUBSPOT_API_KEY") },
|
|
@@ -63,11 +79,14 @@ export const contacts = defineModel("contacts", {
|
|
|
63
79
|
```
|
|
64
80
|
|
|
65
81
|
```bash
|
|
66
|
-
export HUBSPOT_API_KEY=...
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
export HUBSPOT_API_KEY=... # secret() reads this at deploy time
|
|
83
|
+
npm run plan # offline diff — no API calls (runs `cargo-cdk plan`)
|
|
84
|
+
npm run deploy # create everything, write cargo.state.json
|
|
69
85
|
```
|
|
70
86
|
|
|
87
|
+
(The scaffolded `package.json` wires `npm run types` / `plan` / `deploy` to the
|
|
88
|
+
project-local `cargo-cdk`. Or run any command directly with `npx @cargo-ai/cdk <command>`.)
|
|
89
|
+
|
|
71
90
|
Re-running `deploy` only changes what changed; an unchanged workspace is a no-op.
|
|
72
91
|
|
|
73
92
|
## Typed config
|
|
@@ -76,7 +95,7 @@ Re-running `deploy` only changes what changed; an unchanged workspace is a no-op
|
|
|
76
95
|
actual integration schemas. Generate the types once:
|
|
77
96
|
|
|
78
97
|
```bash
|
|
79
|
-
cargo-ai
|
|
98
|
+
npm run types # or: npx @cargo-ai/cdk types
|
|
80
99
|
```
|
|
81
100
|
|
|
82
101
|
They land in `.cargo-ai/`. Add it to your tsconfig `include` with an explicit
|
|
@@ -90,11 +109,11 @@ glob — a bare `.cargo-ai` (a dot-dir) is ignored by TypeScript:
|
|
|
90
109
|
After that, `config` is checked against the integration's schema — e.g. HubSpot
|
|
91
110
|
is a discriminated union, so the editor completes `method` and requires the
|
|
92
111
|
matching credential, and `secret()` is accepted wherever a credential is
|
|
93
|
-
expected. Re-run `
|
|
112
|
+
expected. Re-run `npm run types` after adding or changing workspace integrations.
|
|
94
113
|
|
|
95
114
|
Typing is a bonus, never a gate: an integration you haven't synced (or a custom
|
|
96
115
|
one) falls back to a loose `Record<string, unknown>`, so `deploy` still works
|
|
97
|
-
without ever running `
|
|
116
|
+
without ever running `npm run types`.
|
|
98
117
|
|
|
99
118
|
## Defining resources
|
|
100
119
|
|
|
@@ -144,29 +163,39 @@ added elsewhere (the UI, other tooling) are left in place.
|
|
|
144
163
|
|
|
145
164
|
## Commands
|
|
146
165
|
|
|
166
|
+
In a scaffolded project, the everyday commands are `npm run` scripts:
|
|
167
|
+
|
|
147
168
|
```bash
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
cargo-ai cdk deploy # create/update resources, write cargo.state.json
|
|
152
|
-
cargo-ai cdk deploy --prune # also delete resources removed from code
|
|
153
|
-
cargo-ai cdk deploy --refresh # re-read live resources, re-apply out-of-band changes
|
|
154
|
-
cargo-ai cdk refresh # read-only: report resources that drifted from code
|
|
155
|
-
cargo-ai cdk import <id> <uuid> # bind an existing live resource into state
|
|
156
|
-
cargo-ai cdk rollback # restore cargo.state.json from the pre-deploy snapshot
|
|
157
|
-
cargo-ai cdk destroy --target <id> # tear down one resource
|
|
158
|
-
cargo-ai cdk destroy --all # tear down everything in state
|
|
169
|
+
npm run types # generate per-workspace types for typed config
|
|
170
|
+
npm run plan # offline: diff the code against cargo.state.json
|
|
171
|
+
npm run deploy # create/update resources, write cargo.state.json
|
|
159
172
|
```
|
|
160
173
|
|
|
174
|
+
Run any command — including the ones without a script — with `npx @cargo-ai/cdk`:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npx @cargo-ai/cdk init <directory> # scaffold from a template (--template, --list-templates)
|
|
178
|
+
npx @cargo-ai/cdk deploy --prune # also delete resources removed from code
|
|
179
|
+
npx @cargo-ai/cdk deploy --refresh # re-read live resources, re-apply out-of-band changes
|
|
180
|
+
npx @cargo-ai/cdk refresh # read-only: report resources that drifted from code
|
|
181
|
+
npx @cargo-ai/cdk import <id> <uuid> # bind an existing live resource into state
|
|
182
|
+
npx @cargo-ai/cdk rollback # restore cargo.state.json from the pre-deploy snapshot
|
|
183
|
+
npx @cargo-ai/cdk destroy --target <id> # tear down one resource
|
|
184
|
+
npx @cargo-ai/cdk destroy --all # tear down everything in state
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Every command also works as `cargo-ai cdk <command>` if you have the global Cargo
|
|
188
|
+
CLI installed — same engine, same login.
|
|
189
|
+
|
|
161
190
|
Common flags: `--dir <path>`, `--yes` (skip the prompt — required in CI),
|
|
162
191
|
`--json`, and `--force` (steal a stale state lock). See
|
|
163
192
|
[Deploying](https://docs.getcargo.ai/cdk/deploying).
|
|
164
193
|
|
|
165
194
|
## State & drift
|
|
166
195
|
|
|
167
|
-
`
|
|
196
|
+
`npm run deploy` writes `cargo.state.json` — the link from your code to the
|
|
168
197
|
resources Cargo created. **Commit it** (losing it orphans resources; recover a
|
|
169
|
-
link with `cdk import`). It records only uuids, hashes and outputs — never
|
|
198
|
+
link with `npx @cargo-ai/cdk import`). It records only uuids, hashes and outputs — never
|
|
170
199
|
secret values.
|
|
171
200
|
|
|
172
201
|
Git-ignore the generated types and the working files the CDK writes alongside it
|
|
@@ -179,8 +208,8 @@ cargo.state.bak.json
|
|
|
179
208
|
cargo.state.audit.jsonl
|
|
180
209
|
```
|
|
181
210
|
|
|
182
|
-
`cargo-ai
|
|
183
|
-
(e.g. edited in the Cargo UI); `cargo-ai
|
|
211
|
+
`npx @cargo-ai/cdk refresh` reports resources changed or deleted outside the CDK
|
|
212
|
+
(e.g. edited in the Cargo UI); `npx @cargo-ai/cdk deploy --refresh` re-applies your
|
|
184
213
|
code over them. See [State & Drift](https://docs.getcargo.ai/cdk/state-and-drift).
|
|
185
214
|
|
|
186
215
|
## Documentation
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Api } from "@cargo-ai/api";
|
|
2
|
+
export type Config = {
|
|
3
|
+
accessToken: string | undefined;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
workspaceUuid: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
export declare function getConfig(): Config;
|
|
8
|
+
export declare function getApi(): Api;
|
|
9
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/cli/auth.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,GAAG,EAAkC,MAAM,eAAe,CAAC;AAuBzE,MAAM,MAAM,MAAM,GAAG;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAYF,wBAAgB,SAAS,IAAI,MAAM,CAoBlC;AA4DD,wBAAgB,MAAM,IAAI,GAAG,CAS5B"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Authentication for the standalone `cargo-cdk` bin: reads the same credentials
|
|
2
|
+
// `cargo-ai login` writes (`~/.config/cargo-ai/credentials.json`) plus the
|
|
3
|
+
// `CARGO_*` env vars, so one login serves both `cargo-cdk` and `cargo-ai cdk`.
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { buildApi } from "@cargo-ai/api";
|
|
8
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
9
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
10
|
+
import { ExitCodes, failWith } from "./io.js";
|
|
11
|
+
import { packageVersion } from "./version.js";
|
|
12
|
+
const ORIGIN = { name: "cargo-cdk", version: packageVersion() };
|
|
13
|
+
const DEFAULT_BASE_URL = "https://api.getcargo.io";
|
|
14
|
+
const CREDENTIALS_FILE = join(homedir(), ".config", "cargo-ai", "credentials.json");
|
|
15
|
+
function loadCredentials() {
|
|
16
|
+
if (!existsSync(CREDENTIALS_FILE))
|
|
17
|
+
return undefined;
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(readFileSync(CREDENTIALS_FILE, "utf-8"));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Resolve token / baseUrl / workspace, preferring env over the credentials file.
|
|
26
|
+
export function getConfig() {
|
|
27
|
+
const credentials = loadCredentials();
|
|
28
|
+
const envToken = process.env["CARGO_API_TOKEN"];
|
|
29
|
+
const accessToken = envToken !== undefined ? envToken : credentials?.accessToken;
|
|
30
|
+
const envUrl = process.env["CARGO_BASE_URL"];
|
|
31
|
+
const baseUrl = envUrl !== undefined
|
|
32
|
+
? envUrl
|
|
33
|
+
: credentials?.baseUrl !== undefined
|
|
34
|
+
? credentials.baseUrl
|
|
35
|
+
: DEFAULT_BASE_URL;
|
|
36
|
+
const envUuid = process.env["CARGO_WORKSPACE_UUID"];
|
|
37
|
+
const workspaceUuid = envUuid !== undefined ? envUuid : credentials?.workspaceUuid;
|
|
38
|
+
return { accessToken, baseUrl, workspaceUuid };
|
|
39
|
+
}
|
|
40
|
+
// Tunnel through an HTTP/HTTPS proxy when one is configured via the standard env
|
|
41
|
+
// vars (honoring NO_PROXY); returns undefined otherwise so egress stays direct.
|
|
42
|
+
function getProxyTransport(targetUrl) {
|
|
43
|
+
const getEnv = (...names) => {
|
|
44
|
+
for (const name of names) {
|
|
45
|
+
const value = process.env[name];
|
|
46
|
+
if (value !== undefined && value.trim() !== "")
|
|
47
|
+
return value.trim();
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
};
|
|
51
|
+
const noProxy = getEnv("NO_PROXY", "no_proxy");
|
|
52
|
+
if (noProxy === "*")
|
|
53
|
+
return undefined;
|
|
54
|
+
if (noProxy !== undefined) {
|
|
55
|
+
let hostname = "";
|
|
56
|
+
try {
|
|
57
|
+
hostname = new URL(targetUrl).hostname;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
hostname = "";
|
|
61
|
+
}
|
|
62
|
+
const bypass = noProxy
|
|
63
|
+
.split(",")
|
|
64
|
+
.map((e) => e.trim())
|
|
65
|
+
.filter((e) => e.length > 0)
|
|
66
|
+
.some((e) => {
|
|
67
|
+
const normalized = e.replace(/^\./, "");
|
|
68
|
+
return hostname === normalized || hostname.endsWith(`.${normalized}`);
|
|
69
|
+
});
|
|
70
|
+
if (bypass)
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const isHttps = targetUrl.startsWith("https:");
|
|
74
|
+
const proxyUrl = isHttps
|
|
75
|
+
? getEnv("HTTPS_PROXY", "https_proxy", "ALL_PROXY", "all_proxy")
|
|
76
|
+
: getEnv("HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy");
|
|
77
|
+
if (proxyUrl === undefined)
|
|
78
|
+
return undefined;
|
|
79
|
+
return {
|
|
80
|
+
httpAgent: new HttpProxyAgent(proxyUrl),
|
|
81
|
+
httpsAgent: new HttpsProxyAgent(proxyUrl),
|
|
82
|
+
proxy: false,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function createApi(opts) {
|
|
86
|
+
return buildApi({
|
|
87
|
+
baseUrl: opts.baseUrl,
|
|
88
|
+
workspaceUuid: opts.workspaceUuid,
|
|
89
|
+
accessToken: opts.accessToken,
|
|
90
|
+
origin: ORIGIN,
|
|
91
|
+
transport: getProxyTransport(opts.baseUrl),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export function getApi() {
|
|
95
|
+
const { baseUrl, accessToken, workspaceUuid } = getConfig();
|
|
96
|
+
if (accessToken === undefined) {
|
|
97
|
+
failWith("Not authenticated. Run 'cargo-ai login --token <token>' or 'cargo-ai login --oauth' (cargo-cdk shares the Cargo CLI login), or set CARGO_API_TOKEN.", { code: ExitCodes.NotAuthenticated });
|
|
98
|
+
}
|
|
99
|
+
return createApi({ baseUrl, accessToken, workspaceUuid });
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../../src/cli/bin.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `cargo-cdk` executable — the standalone Cargo CDK CLI.
|
|
3
|
+
import { runCdkBin } from "./index.js";
|
|
4
|
+
import { failWith } from "./io.js";
|
|
5
|
+
// Route any failure through `failWith` for structured stderr + exit code, rather
|
|
6
|
+
// than an unhandled promise rejection.
|
|
7
|
+
runCdkBin().catch((error) => {
|
|
8
|
+
failWith(error instanceof Error ? error.message : String(error));
|
|
9
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0CzC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA0oBN"}
|