devflare 1.0.0-next.17 → 1.0.0-next.19
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/LLM.md +15 -5
- package/dist/account-d43d1eqs.js +475 -0
- package/dist/build-hpkbanpw.js +54 -0
- package/dist/cli/commands/build-artifacts.d.ts +13 -0
- package/dist/cli/commands/build-artifacts.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cloudflare/index.js +2 -2
- package/dist/cloudflare/tokens.d.ts.map +1 -1
- package/dist/deploy-sany8t54.js +1045 -0
- package/dist/dev-at6gy2td.js +2427 -0
- package/dist/index-7e359eb5.js +895 -0
- package/dist/index-7r7dfpcm.js +133 -0
- package/dist/index-dmf76tac.js +1372 -0
- package/dist/index-fgk87mk2.js +1067 -0
- package/dist/index-k7m5f1dg.js +200 -0
- package/dist/index-vt803j3b.js +1372 -0
- package/dist/index-xec4p3v5.js +560 -0
- package/dist/index.js +1 -1
- package/dist/login-7yex6ppq.js +77 -0
- package/dist/previews-6fepv94a.js +1225 -0
- package/dist/productions-2t9q8f57.js +505 -0
- package/dist/token-a2b38w0z.js +419 -0
- package/dist/vite/index.js +1 -1
- package/dist/worker-99tew196.js +513 -0
- package/dist/worker-entry/composed-worker.d.ts.map +1 -1
- package/dist/worker-entry/surface-paths.d.ts +9 -0
- package/dist/worker-entry/surface-paths.d.ts.map +1 -1
- package/package.json +1 -1
package/LLM.md
CHANGED
|
@@ -56,7 +56,7 @@ Keep the day-to-day Devflare surfaces easy to scan: runtime model, HTTP split, a
|
|
|
56
56
|
- **Frameworks** — Choose the right host lane for worker-rendered Svelte, standalone Vite apps, and full SvelteKit shells without losing the worker-first mental model.
|
|
57
57
|
- [Svelte in workers](/docs/svelte-with-rolldown) — When a worker-only fetch surface or Durable Object imports `.svelte`, add the Svelte compiler to `rolldown.options.plugins`. That compilation belongs to Devflare’s worker bundler, not the main Vite plugin chain.
|
|
58
58
|
- [Vite standalone](/docs/vite-standalone) — An effective Vite config is what opts the package into Vite-backed flows: a local `vite.config.*`, a non-empty `config.vite`, or both together. Use `devflare/vite` when the package really is a Vite app and you want Devflare to keep Worker config, Durable Objects, and generated Wrangler output aligned underneath it.
|
|
59
|
-
- [SvelteKit](/docs/sveltekit-with-devflare) —
|
|
59
|
+
- [SvelteKit](/docs/sveltekit-with-devflare) — Hand SvelteKit's Cloudflare adapter output to Devflare via `wrangler.passthrough.main` (the adapter worker is a build artifact and does not exist until `vite build` runs), keep `sveltekit()` in `vite.config.ts`, and compose `devflare/sveltekit` into `src/hooks.server.ts` so local platform bindings line up with the Worker runtime Devflare manages.
|
|
60
60
|
|
|
61
61
|
### Ship & operate
|
|
62
62
|
Deploy explicitly, choose the right preview model, manage preview lifecycle cleanly, and keep CI/CD plus verification honest.
|
|
@@ -4196,7 +4196,7 @@ That means you should think in terms of host ownership, not a separate CLI mode.
|
|
|
4196
4196
|
|
|
4197
4197
|
### Compose Devflare with SvelteKit by letting SvelteKit host the app and Devflare supply the Worker platform
|
|
4198
4198
|
|
|
4199
|
-
>
|
|
4199
|
+
> Hand SvelteKit's Cloudflare adapter output to Devflare via `wrangler.passthrough.main` (the adapter worker is a build artifact and does not exist until `vite build` runs), keep `sveltekit()` in `vite.config.ts`, and compose `devflare/sveltekit` into `src/hooks.server.ts` so local platform bindings line up with the Worker runtime Devflare manages.
|
|
4200
4200
|
|
|
4201
4201
|
| Field | Value |
|
|
4202
4202
|
| --- | --- |
|
|
@@ -4212,14 +4212,16 @@ This is the path for full SvelteKit apps where the framework owns the outer shel
|
|
|
4212
4212
|
| Fact | Value |
|
|
4213
4213
|
| --- | --- |
|
|
4214
4214
|
| Best for | Full SvelteKit apps that deploy through Devflare |
|
|
4215
|
-
| Worker entry | The adapter worker output your package actually emits, commonly `.svelte-kit/cloudflare/_worker.js` or a repo-specific path such as `.adapter-cloudflare/_worker.js` |
|
|
4215
|
+
| Worker entry | The adapter worker output your package actually emits, commonly `.svelte-kit/cloudflare/_worker.js` or a repo-specific path such as `.adapter-cloudflare/_worker.js`, wired via `wrangler.passthrough.main` |
|
|
4216
4216
|
| Hook helper | `devflare/sveltekit` |
|
|
4217
4217
|
|
|
4218
4218
|
#### Wire the SvelteKit package like a SvelteKit app first
|
|
4219
4219
|
|
|
4220
4220
|
SvelteKit still owns the app shell, routing, and framework build. Devflare plugs Worker-aware config, generated Wrangler output, and any Durable Object discovery into that Vite-driven flow.
|
|
4221
4221
|
|
|
4222
|
-
|
|
4222
|
+
The adapter worker is a **build artifact** — `@sveltejs/adapter-cloudflare` only writes `.svelte-kit/cloudflare/_worker.js` (or your repo's equivalent, like `.adapter-cloudflare/_worker.js`) during `vite build`. Devflare resolves handler paths *before* the framework build runs, so pointing `files.fetch` at that path fails on a clean checkout with `Configured fetch handler "…" was not found`. Use `wrangler.passthrough.main` instead: devflare skips composition entirely for the worker entry, and wrangler picks up the adapter output post-build.
|
|
4223
|
+
|
|
4224
|
+
If you also have queue handlers, scheduled handlers, durable objects, or routes, keep those in `files.queue` / `files.scheduled` / `files.durableObjects` / `files.routes` as normal source files — composition still applies to those surfaces.
|
|
4223
4225
|
|
|
4224
4226
|
##### Example — `devflare.config.ts`
|
|
4225
4227
|
|
|
@@ -4229,8 +4231,16 @@ import { defineConfig } from 'devflare/config'
|
|
|
4229
4231
|
export default defineConfig({
|
|
4230
4232
|
name: 'notes-app',
|
|
4231
4233
|
files: {
|
|
4232
|
-
fetch
|
|
4234
|
+
// fetch is supplied by SvelteKit's adapter output below;
|
|
4235
|
+
// keep this false so devflare does not try to compose around an unbuilt artifact.
|
|
4236
|
+
fetch: false,
|
|
4233
4237
|
durableObjects: 'src/do/**/*.ts'
|
|
4238
|
+
},
|
|
4239
|
+
wrangler: {
|
|
4240
|
+
passthrough: {
|
|
4241
|
+
// SvelteKit's @sveltejs/adapter-cloudflare writes this file during vite build.
|
|
4242
|
+
main: '.svelte-kit/cloudflare/_worker.js'
|
|
4243
|
+
}
|
|
4234
4244
|
}
|
|
4235
4245
|
})
|
|
4236
4246
|
```
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getConfiguredAccountId
|
|
3
|
+
} from "./index-678j0n13.js";
|
|
4
|
+
import {
|
|
5
|
+
account
|
|
6
|
+
} from "./index-7r7dfpcm.js";
|
|
7
|
+
import"./index-k7m5f1dg.js";
|
|
8
|
+
import"./index-nbs4q0qg.js";
|
|
9
|
+
import {
|
|
10
|
+
bold,
|
|
11
|
+
createCliTheme,
|
|
12
|
+
dim,
|
|
13
|
+
formatCommand,
|
|
14
|
+
formatLabelValue,
|
|
15
|
+
green,
|
|
16
|
+
logLine,
|
|
17
|
+
logTable,
|
|
18
|
+
whiteDim,
|
|
19
|
+
yellow
|
|
20
|
+
} from "./index-stgn34cr.js";
|
|
21
|
+
import {
|
|
22
|
+
CYAN,
|
|
23
|
+
CYAN_BOLD,
|
|
24
|
+
DIM,
|
|
25
|
+
RESET
|
|
26
|
+
} from "./index-3t6rypgc.js";
|
|
27
|
+
import"./index-15fpa5tx.js";
|
|
28
|
+
import"./index-5vzcszr2.js";
|
|
29
|
+
import {
|
|
30
|
+
getGlobalDefaultAccountId,
|
|
31
|
+
getWorkspaceAccountId,
|
|
32
|
+
setGlobalDefaultAccountId,
|
|
33
|
+
setWorkspaceAccountId
|
|
34
|
+
} from "./index-1d4jg11n.js";
|
|
35
|
+
import {
|
|
36
|
+
AuthenticationError,
|
|
37
|
+
CloudflareAPIError
|
|
38
|
+
} from "./index-mg8vwqxf.js";
|
|
39
|
+
import"./index-c0whkev9.js";
|
|
40
|
+
import"./index-37x76zdn.js";
|
|
41
|
+
|
|
42
|
+
// src/cli/commands/account.ts
|
|
43
|
+
var ACCOUNT_SUBCOMMANDS = [
|
|
44
|
+
"info",
|
|
45
|
+
"workers",
|
|
46
|
+
"kv",
|
|
47
|
+
"d1",
|
|
48
|
+
"r2",
|
|
49
|
+
"vectorize",
|
|
50
|
+
"limits",
|
|
51
|
+
"usage",
|
|
52
|
+
"global",
|
|
53
|
+
"workspace"
|
|
54
|
+
];
|
|
55
|
+
function isAccountSubcommand(value) {
|
|
56
|
+
return ACCOUNT_SUBCOMMANDS.includes(value);
|
|
57
|
+
}
|
|
58
|
+
var CLI_API_OPTIONS = { timeout: 1e4 };
|
|
59
|
+
function formatDate(date) {
|
|
60
|
+
if (!date)
|
|
61
|
+
return "N/A";
|
|
62
|
+
return date.toLocaleDateString("en-US", {
|
|
63
|
+
year: "numeric",
|
|
64
|
+
month: "short",
|
|
65
|
+
day: "numeric"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function formatPercent(value) {
|
|
69
|
+
if (value === undefined)
|
|
70
|
+
return "N/A";
|
|
71
|
+
return `${value.toFixed(1)}%`;
|
|
72
|
+
}
|
|
73
|
+
function logSection(logger, title, theme, count, accent = "cyan") {
|
|
74
|
+
logLine(logger);
|
|
75
|
+
const heading = accent === "yellow" ? yellow(title, theme) : accent === "green" ? green(title, theme) : bold(title, theme);
|
|
76
|
+
logLine(logger, `${heading}${count === undefined ? "" : ` ${dim(`(${count})`, theme)}`}`);
|
|
77
|
+
}
|
|
78
|
+
function logEmptyState(logger, message, theme) {
|
|
79
|
+
logLine(logger);
|
|
80
|
+
logLine(logger, dim(message, theme));
|
|
81
|
+
logLine(logger);
|
|
82
|
+
return { exitCode: 0 };
|
|
83
|
+
}
|
|
84
|
+
async function runAccountCommand(parsed, logger, options) {
|
|
85
|
+
const theme = createCliTheme(parsed.options);
|
|
86
|
+
const isAuth = await account.isAuthenticated();
|
|
87
|
+
if (!isAuth) {
|
|
88
|
+
logger.error("Not authenticated with Cloudflare");
|
|
89
|
+
logLine(logger, dim("Run: devflare login", theme));
|
|
90
|
+
return { exitCode: 1 };
|
|
91
|
+
}
|
|
92
|
+
const subcommand = parsed.args[0];
|
|
93
|
+
const rawSubcommand = parsed.args[0];
|
|
94
|
+
if (rawSubcommand && !isAccountSubcommand(rawSubcommand)) {
|
|
95
|
+
logger.error(`Unknown account subcommand: ${rawSubcommand}`);
|
|
96
|
+
logLine(logger, dim(`Available account subcommands: ${ACCOUNT_SUBCOMMANDS.join(", ")}`, theme));
|
|
97
|
+
return { exitCode: 1 };
|
|
98
|
+
}
|
|
99
|
+
if (subcommand === "global") {
|
|
100
|
+
return await selectGlobalAccount(logger, theme);
|
|
101
|
+
}
|
|
102
|
+
if (subcommand === "workspace") {
|
|
103
|
+
return await selectWorkspaceAccount(logger, theme);
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
let accountId = parsed.options.account;
|
|
107
|
+
if (!accountId) {
|
|
108
|
+
accountId = await getConfiguredAccountId(options.cwd ?? process.cwd());
|
|
109
|
+
}
|
|
110
|
+
if (!accountId) {
|
|
111
|
+
const primary = await account.getPrimaryAccount();
|
|
112
|
+
if (!primary) {
|
|
113
|
+
logger.error("No Cloudflare accounts found");
|
|
114
|
+
return { exitCode: 1 };
|
|
115
|
+
}
|
|
116
|
+
accountId = primary.id;
|
|
117
|
+
}
|
|
118
|
+
switch (subcommand) {
|
|
119
|
+
case "workers":
|
|
120
|
+
return await showWorkers(accountId, logger, theme);
|
|
121
|
+
case "kv":
|
|
122
|
+
return await showKV(accountId, logger, theme);
|
|
123
|
+
case "d1":
|
|
124
|
+
return await showD1(accountId, logger, theme);
|
|
125
|
+
case "r2":
|
|
126
|
+
return await showR2(accountId, logger, theme);
|
|
127
|
+
case "vectorize":
|
|
128
|
+
return await showVectorize(accountId, logger, theme);
|
|
129
|
+
case "limits":
|
|
130
|
+
return await handleLimits(accountId, parsed, logger, theme);
|
|
131
|
+
case "usage":
|
|
132
|
+
return await showUsage(accountId, logger, theme);
|
|
133
|
+
case "info":
|
|
134
|
+
default:
|
|
135
|
+
return await showAccountOverview(accountId, logger, theme);
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (error instanceof AuthenticationError) {
|
|
139
|
+
logger.error(error.message);
|
|
140
|
+
return { exitCode: 1 };
|
|
141
|
+
}
|
|
142
|
+
if (error instanceof CloudflareAPIError) {
|
|
143
|
+
logger.error(`API Error: ${error.message}`);
|
|
144
|
+
return { exitCode: 1 };
|
|
145
|
+
}
|
|
146
|
+
if (error instanceof Error) {
|
|
147
|
+
if (error.name === "AbortError" || error.message.includes("timed out")) {
|
|
148
|
+
logger.error("Request timed out. The Cloudflare API is slow or unavailable.");
|
|
149
|
+
return { exitCode: 1 };
|
|
150
|
+
}
|
|
151
|
+
logger.error(`Error: ${error.message}`);
|
|
152
|
+
return { exitCode: 1 };
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function showAccountOverview(accountId, logger, theme) {
|
|
158
|
+
logSection(logger, "Accounts", theme);
|
|
159
|
+
let accounts = [];
|
|
160
|
+
let limitedAccountView = false;
|
|
161
|
+
try {
|
|
162
|
+
accounts = await account.getAccounts();
|
|
163
|
+
} catch {
|
|
164
|
+
const fallbackAccount = await account.getAccountById(accountId);
|
|
165
|
+
if (!fallbackAccount) {
|
|
166
|
+
logger.error("Could not inspect Cloudflare accounts with the current credentials");
|
|
167
|
+
return { exitCode: 1 };
|
|
168
|
+
}
|
|
169
|
+
accounts = [fallbackAccount];
|
|
170
|
+
limitedAccountView = true;
|
|
171
|
+
}
|
|
172
|
+
if (accounts.length === 0) {
|
|
173
|
+
logger.error("No Cloudflare accounts found");
|
|
174
|
+
return { exitCode: 1 };
|
|
175
|
+
}
|
|
176
|
+
const workspaceId = getWorkspaceAccountId();
|
|
177
|
+
const globalId = await getGlobalDefaultAccountId(accountId);
|
|
178
|
+
if (limitedAccountView) {
|
|
179
|
+
logLine(logger, dim("Using the configured account directly because the current credentials cannot enumerate all Cloudflare accounts.", theme));
|
|
180
|
+
}
|
|
181
|
+
for (let i = 0;i < accounts.length; i++) {
|
|
182
|
+
const acc = accounts[i];
|
|
183
|
+
const isWorkspace = acc.id === workspaceId;
|
|
184
|
+
const isGlobal = acc.id === globalId;
|
|
185
|
+
let badge = "";
|
|
186
|
+
if (isWorkspace) {
|
|
187
|
+
badge = ` ${CYAN_BOLD}(workspace)${RESET}`;
|
|
188
|
+
} else if (isGlobal) {
|
|
189
|
+
badge = workspaceId ? ` ${DIM}(global)${RESET}` : ` ${CYAN}(global)${RESET}`;
|
|
190
|
+
}
|
|
191
|
+
if (i > 0) {
|
|
192
|
+
logLine(logger);
|
|
193
|
+
}
|
|
194
|
+
logLine(logger, `${dim("account", theme)} ${green(acc.name, theme)}${badge}`);
|
|
195
|
+
logLine(logger, formatLabelValue("id", whiteDim(acc.id, theme), theme, 10));
|
|
196
|
+
logLine(logger, formatLabelValue("type", acc.type, theme, 10));
|
|
197
|
+
}
|
|
198
|
+
logSection(logger, "Commands", theme);
|
|
199
|
+
logLine(logger, formatCommand("devflare account global", "Set global default account", theme));
|
|
200
|
+
logLine(logger, formatCommand("devflare account workspace", "Set workspace account", theme));
|
|
201
|
+
logLine(logger, formatCommand("devflare account workers", "List Workers", theme));
|
|
202
|
+
logLine(logger, formatCommand("devflare account kv", "List KV namespaces", theme));
|
|
203
|
+
logLine(logger, formatCommand("devflare account d1", "List D1 databases", theme));
|
|
204
|
+
logLine(logger, formatCommand("devflare account r2", "List R2 buckets", theme));
|
|
205
|
+
logLine(logger, formatCommand("devflare account vectorize", "List Vectorize indexes", theme));
|
|
206
|
+
logLine(logger, formatCommand("devflare account limits", "View or set usage limits", theme));
|
|
207
|
+
logLine(logger, formatCommand("devflare account usage", "View detailed usage", theme));
|
|
208
|
+
logLine(logger, formatCommand("devflare ai", "View AI models and pricing", theme));
|
|
209
|
+
logLine(logger);
|
|
210
|
+
return { exitCode: 0 };
|
|
211
|
+
}
|
|
212
|
+
async function selectGlobalAccount(logger, theme) {
|
|
213
|
+
const accounts = await account.getAccounts();
|
|
214
|
+
if (accounts.length === 0) {
|
|
215
|
+
logger.error("No Cloudflare accounts found");
|
|
216
|
+
return { exitCode: 1 };
|
|
217
|
+
}
|
|
218
|
+
if (accounts.length === 1) {
|
|
219
|
+
await setGlobalDefaultAccountId(accounts[0].id);
|
|
220
|
+
logger.success(`Global default set to: ${accounts[0].name}`);
|
|
221
|
+
return { exitCode: 0 };
|
|
222
|
+
}
|
|
223
|
+
const currentGlobal = await getGlobalDefaultAccountId(accounts[0].id);
|
|
224
|
+
const options = accounts.map((acc) => {
|
|
225
|
+
const isCurrent = acc.id === currentGlobal;
|
|
226
|
+
return {
|
|
227
|
+
label: isCurrent ? `${acc.name} ${CYAN}(default)${RESET}` : acc.name,
|
|
228
|
+
value: acc.id,
|
|
229
|
+
hint: acc.id.substring(0, 8) + "..."
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
const selected = await logger.prompt("Select global default account:", {
|
|
233
|
+
type: "select",
|
|
234
|
+
options,
|
|
235
|
+
initial: currentGlobal ?? accounts[0].id
|
|
236
|
+
});
|
|
237
|
+
if (!selected || typeof selected === "symbol") {
|
|
238
|
+
logLine(logger, dim("Cancelled", theme));
|
|
239
|
+
return { exitCode: 0 };
|
|
240
|
+
}
|
|
241
|
+
await setGlobalDefaultAccountId(selected, accounts[0].id);
|
|
242
|
+
const selectedAccount = accounts.find((a) => a.id === selected);
|
|
243
|
+
logger.success(`Global default set to: ${selectedAccount?.name}`);
|
|
244
|
+
logLine(logger, `${dim("saved to", theme)} ~/.devflare/preferences.json + cloud KV`);
|
|
245
|
+
return { exitCode: 0 };
|
|
246
|
+
}
|
|
247
|
+
async function selectWorkspaceAccount(logger, theme) {
|
|
248
|
+
const accounts = await account.getAccounts();
|
|
249
|
+
if (accounts.length === 0) {
|
|
250
|
+
logger.error("No Cloudflare accounts found");
|
|
251
|
+
return { exitCode: 1 };
|
|
252
|
+
}
|
|
253
|
+
if (accounts.length === 1) {
|
|
254
|
+
const pkgPath2 = setWorkspaceAccountId(accounts[0].id);
|
|
255
|
+
logger.success(`Workspace account set to: ${accounts[0].name}`);
|
|
256
|
+
logLine(logger, `${dim("saved to", theme)} ${pkgPath2}`);
|
|
257
|
+
return { exitCode: 0 };
|
|
258
|
+
}
|
|
259
|
+
const currentWorkspace = getWorkspaceAccountId();
|
|
260
|
+
const options = accounts.map((acc) => {
|
|
261
|
+
const isCurrent = acc.id === currentWorkspace;
|
|
262
|
+
return {
|
|
263
|
+
label: isCurrent ? `${acc.name} ${CYAN}(workspace)${RESET}` : acc.name,
|
|
264
|
+
value: acc.id,
|
|
265
|
+
hint: acc.id.substring(0, 8) + "..."
|
|
266
|
+
};
|
|
267
|
+
});
|
|
268
|
+
const selected = await logger.prompt("Select workspace account:", {
|
|
269
|
+
type: "select",
|
|
270
|
+
options,
|
|
271
|
+
initial: currentWorkspace ?? accounts[0].id
|
|
272
|
+
});
|
|
273
|
+
if (!selected || typeof selected === "symbol") {
|
|
274
|
+
logLine(logger, dim("Cancelled", theme));
|
|
275
|
+
return { exitCode: 0 };
|
|
276
|
+
}
|
|
277
|
+
const pkgPath = setWorkspaceAccountId(selected);
|
|
278
|
+
const selectedAccount = accounts.find((a) => a.id === selected);
|
|
279
|
+
logger.success(`Workspace account set to: ${selectedAccount?.name}`);
|
|
280
|
+
logLine(logger, `${dim("saved to", theme)} ${pkgPath}`);
|
|
281
|
+
return { exitCode: 0 };
|
|
282
|
+
}
|
|
283
|
+
async function showWorkers(accountId, logger, theme) {
|
|
284
|
+
const workers = await account.workers(accountId, CLI_API_OPTIONS);
|
|
285
|
+
if (workers.length === 0) {
|
|
286
|
+
return logEmptyState(logger, "No Workers found", theme);
|
|
287
|
+
}
|
|
288
|
+
logSection(logger, "Workers", theme, workers.length, "green");
|
|
289
|
+
logTable(logger, {
|
|
290
|
+
title: "Worker list",
|
|
291
|
+
rows: workers,
|
|
292
|
+
columns: [
|
|
293
|
+
{ label: "Name", width: 30, value: (worker) => worker.name },
|
|
294
|
+
{ label: "Modified", width: 20, value: (worker) => whiteDim(formatDate(worker.modifiedOn), theme) }
|
|
295
|
+
],
|
|
296
|
+
theme,
|
|
297
|
+
titleAccent: "green"
|
|
298
|
+
});
|
|
299
|
+
logLine(logger);
|
|
300
|
+
return { exitCode: 0 };
|
|
301
|
+
}
|
|
302
|
+
async function showKV(accountId, logger, theme) {
|
|
303
|
+
const namespaces = await account.kv(accountId, CLI_API_OPTIONS);
|
|
304
|
+
if (namespaces.length === 0) {
|
|
305
|
+
return logEmptyState(logger, "No KV namespaces found", theme);
|
|
306
|
+
}
|
|
307
|
+
logSection(logger, "KV namespaces", theme, namespaces.length);
|
|
308
|
+
logTable(logger, {
|
|
309
|
+
title: "Namespace list",
|
|
310
|
+
rows: namespaces,
|
|
311
|
+
columns: [
|
|
312
|
+
{ label: "Name", width: 35, value: (ns) => ns.name },
|
|
313
|
+
{ label: "ID", width: 35, value: (ns) => whiteDim(ns.id, theme) }
|
|
314
|
+
],
|
|
315
|
+
theme,
|
|
316
|
+
titleAccent: "cyan"
|
|
317
|
+
});
|
|
318
|
+
logLine(logger);
|
|
319
|
+
return { exitCode: 0 };
|
|
320
|
+
}
|
|
321
|
+
async function showD1(accountId, logger, theme) {
|
|
322
|
+
const databases = await account.d1(accountId, CLI_API_OPTIONS);
|
|
323
|
+
if (databases.length === 0) {
|
|
324
|
+
return logEmptyState(logger, "No D1 databases found", theme);
|
|
325
|
+
}
|
|
326
|
+
logSection(logger, "D1 databases", theme, databases.length, "yellow");
|
|
327
|
+
logTable(logger, {
|
|
328
|
+
title: "Database list",
|
|
329
|
+
rows: databases,
|
|
330
|
+
columns: [
|
|
331
|
+
{ label: "Name", width: 25, value: (db) => db.name },
|
|
332
|
+
{ label: "ID", width: 40, value: (db) => whiteDim(db.id, theme) },
|
|
333
|
+
{ label: "Tables", width: 8, value: (db) => String(db.tableCount ?? "N/A") }
|
|
334
|
+
],
|
|
335
|
+
theme,
|
|
336
|
+
titleAccent: "yellow"
|
|
337
|
+
});
|
|
338
|
+
logLine(logger);
|
|
339
|
+
return { exitCode: 0 };
|
|
340
|
+
}
|
|
341
|
+
async function showR2(accountId, logger, theme) {
|
|
342
|
+
const buckets = await account.r2(accountId, CLI_API_OPTIONS);
|
|
343
|
+
if (buckets.length === 0) {
|
|
344
|
+
return logEmptyState(logger, "No R2 buckets found", theme);
|
|
345
|
+
}
|
|
346
|
+
logSection(logger, "R2 buckets", theme, buckets.length, "green");
|
|
347
|
+
logTable(logger, {
|
|
348
|
+
title: "Bucket list",
|
|
349
|
+
rows: buckets,
|
|
350
|
+
columns: [
|
|
351
|
+
{ label: "Name", width: 30, value: (bucket) => bucket.name },
|
|
352
|
+
{ label: "Created", width: 20, value: (bucket) => whiteDim(formatDate(bucket.createdOn), theme) },
|
|
353
|
+
{ label: "Location", width: 10, value: (bucket) => bucket.location ?? "auto" }
|
|
354
|
+
],
|
|
355
|
+
theme,
|
|
356
|
+
titleAccent: "green"
|
|
357
|
+
});
|
|
358
|
+
logLine(logger);
|
|
359
|
+
return { exitCode: 0 };
|
|
360
|
+
}
|
|
361
|
+
async function showVectorize(accountId, logger, theme) {
|
|
362
|
+
const indexes = await account.vectorize(accountId, CLI_API_OPTIONS);
|
|
363
|
+
if (indexes.length === 0) {
|
|
364
|
+
return logEmptyState(logger, "No Vectorize indexes found", theme);
|
|
365
|
+
}
|
|
366
|
+
logSection(logger, "Vectorize indexes", theme, indexes.length, "yellow");
|
|
367
|
+
logTable(logger, {
|
|
368
|
+
title: "Index list",
|
|
369
|
+
rows: indexes,
|
|
370
|
+
columns: [
|
|
371
|
+
{ label: "Name", width: 25, value: (idx) => idx.name },
|
|
372
|
+
{ label: "Dimensions", width: 12, value: (idx) => String(idx.dimensions) },
|
|
373
|
+
{ label: "Metric", width: 15, value: (idx) => idx.metric }
|
|
374
|
+
],
|
|
375
|
+
theme,
|
|
376
|
+
titleAccent: "yellow"
|
|
377
|
+
});
|
|
378
|
+
logLine(logger);
|
|
379
|
+
return { exitCode: 0 };
|
|
380
|
+
}
|
|
381
|
+
async function showUsage(accountId, logger, theme) {
|
|
382
|
+
const usages = await account.getAllUsageSummaries(accountId);
|
|
383
|
+
const limits = await account.getLimits(accountId);
|
|
384
|
+
logSection(logger, "Usage", theme, undefined, "yellow");
|
|
385
|
+
logLine(logger, formatLabelValue("limits", limits.enabled ? green("enabled", theme) : dim("disabled", theme), theme, 12));
|
|
386
|
+
if (usages.length === 0) {
|
|
387
|
+
return logEmptyState(logger, "No usage tracked yet", theme);
|
|
388
|
+
}
|
|
389
|
+
logTable(logger, {
|
|
390
|
+
title: "Usage by service",
|
|
391
|
+
rows: usages,
|
|
392
|
+
columns: [
|
|
393
|
+
{ label: "Service", width: 15, value: (usage) => usage.service },
|
|
394
|
+
{ label: "Today", width: 10, value: (usage) => String(usage.today) },
|
|
395
|
+
{ label: "Limit", width: 10, value: (usage) => usage.limit?.toString() ?? "∞" },
|
|
396
|
+
{ label: "%", width: 10, value: (usage) => formatPercent(usage.percentUsed) },
|
|
397
|
+
{ label: "Status", width: 10, value: (usage) => usage.withinLimit ? green("ok", theme) : yellow("limit", theme) }
|
|
398
|
+
],
|
|
399
|
+
theme,
|
|
400
|
+
titleAccent: "yellow"
|
|
401
|
+
});
|
|
402
|
+
logLine(logger);
|
|
403
|
+
return { exitCode: 0 };
|
|
404
|
+
}
|
|
405
|
+
async function handleLimits(accountId, parsed, logger, theme) {
|
|
406
|
+
const action = parsed.args[1];
|
|
407
|
+
switch (action) {
|
|
408
|
+
case "set":
|
|
409
|
+
return await setLimit(accountId, parsed, logger, theme);
|
|
410
|
+
case "enable":
|
|
411
|
+
await account.setLimitsEnabled(accountId, true);
|
|
412
|
+
logger.success("Usage limits enabled");
|
|
413
|
+
return { exitCode: 0 };
|
|
414
|
+
case "disable":
|
|
415
|
+
await account.setLimitsEnabled(accountId, false);
|
|
416
|
+
logger.success("Usage limits disabled");
|
|
417
|
+
return { exitCode: 0 };
|
|
418
|
+
default:
|
|
419
|
+
return await showLimits(accountId, logger, theme);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
async function showLimits(accountId, logger, theme) {
|
|
423
|
+
const limits = await account.getLimits(accountId);
|
|
424
|
+
logSection(logger, "Usage limits", theme, undefined, "yellow");
|
|
425
|
+
logLine(logger, formatLabelValue("status", limits.enabled ? green("enabled", theme) : dim("disabled", theme), theme, 16));
|
|
426
|
+
logLine(logger);
|
|
427
|
+
logLine(logger, dim("current limits", theme));
|
|
428
|
+
logLine(logger, formatLabelValue("AI Requests/Day", String(limits.aiRequestsPerDay ?? "Unlimited"), theme, 18));
|
|
429
|
+
logLine(logger, formatLabelValue("AI Tokens/Day", String(limits.aiTokensPerDay ?? "Unlimited"), theme, 18));
|
|
430
|
+
logLine(logger, formatLabelValue("Vectorize Ops/Day", String(limits.vectorizeOpsPerDay ?? "Unlimited"), theme, 18));
|
|
431
|
+
logSection(logger, "Commands", theme);
|
|
432
|
+
logLine(logger, formatCommand("devflare account limits set ai-requests 50", "Set the AI request daily limit", theme));
|
|
433
|
+
logLine(logger, formatCommand("devflare account limits set ai-tokens 5000", "Set the AI token daily limit", theme));
|
|
434
|
+
logLine(logger, formatCommand("devflare account limits set vectorize-ops 500", "Set the Vectorize daily limit", theme));
|
|
435
|
+
logLine(logger, formatCommand("devflare account limits enable", "Enable usage limits", theme));
|
|
436
|
+
logLine(logger, formatCommand("devflare account limits disable", "Disable usage limits", theme));
|
|
437
|
+
logLine(logger);
|
|
438
|
+
return { exitCode: 0 };
|
|
439
|
+
}
|
|
440
|
+
async function setLimit(accountId, parsed, logger, theme) {
|
|
441
|
+
const limitName = parsed.args[2];
|
|
442
|
+
const limitValue = parsed.args[3];
|
|
443
|
+
if (!limitName || !limitValue) {
|
|
444
|
+
logger.error("Usage: devflare account limits set <limit-name> <value>");
|
|
445
|
+
logLine(logger, dim("Limit names: ai-requests, ai-tokens, vectorize-ops", theme));
|
|
446
|
+
return { exitCode: 1 };
|
|
447
|
+
}
|
|
448
|
+
const value = parseInt(limitValue, 10);
|
|
449
|
+
if (isNaN(value) || value < 0) {
|
|
450
|
+
logger.error("Limit value must be a positive number");
|
|
451
|
+
return { exitCode: 1 };
|
|
452
|
+
}
|
|
453
|
+
switch (limitName) {
|
|
454
|
+
case "ai-requests":
|
|
455
|
+
await account.setLimits(accountId, { aiRequestsPerDay: value });
|
|
456
|
+
logger.success(`AI requests limit set to ${value}/day`);
|
|
457
|
+
break;
|
|
458
|
+
case "ai-tokens":
|
|
459
|
+
await account.setLimits(accountId, { aiTokensPerDay: value });
|
|
460
|
+
logger.success(`AI tokens limit set to ${value}/day`);
|
|
461
|
+
break;
|
|
462
|
+
case "vectorize-ops":
|
|
463
|
+
await account.setLimits(accountId, { vectorizeOpsPerDay: value });
|
|
464
|
+
logger.success(`Vectorize ops limit set to ${value}/day`);
|
|
465
|
+
break;
|
|
466
|
+
default:
|
|
467
|
+
logger.error(`Unknown limit: ${limitName}`);
|
|
468
|
+
logLine(logger, dim("Valid limits: ai-requests, ai-tokens, vectorize-ops", theme));
|
|
469
|
+
return { exitCode: 1 };
|
|
470
|
+
}
|
|
471
|
+
return { exitCode: 0 };
|
|
472
|
+
}
|
|
473
|
+
export {
|
|
474
|
+
runAccountCommand
|
|
475
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {
|
|
2
|
+
prepareBuildArtifacts
|
|
3
|
+
} from "./index-xec4p3v5.js";
|
|
4
|
+
import"./index-aabgympv.js";
|
|
5
|
+
import"./index-z9gy8w6b.js";
|
|
6
|
+
import"./index-7e359eb5.js";
|
|
7
|
+
import"./index-gn5wy09x.js";
|
|
8
|
+
import"./index-6h8xbs75.js";
|
|
9
|
+
import {
|
|
10
|
+
createCliTheme,
|
|
11
|
+
cyanBold,
|
|
12
|
+
dim,
|
|
13
|
+
logLine
|
|
14
|
+
} from "./index-stgn34cr.js";
|
|
15
|
+
import"./index-3t6rypgc.js";
|
|
16
|
+
import"./index-t4fhcx1n.js";
|
|
17
|
+
import"./index-fgk87mk2.js";
|
|
18
|
+
import"./index-3e7by9sy.js";
|
|
19
|
+
import"./index-rbht7m9r.js";
|
|
20
|
+
import"./index-65e7xx1a.js";
|
|
21
|
+
import"./index-vhqww6tt.js";
|
|
22
|
+
import"./index-kawa49m8.js";
|
|
23
|
+
import"./index-5vzcszr2.js";
|
|
24
|
+
import"./index-1d4jg11n.js";
|
|
25
|
+
import"./index-mg8vwqxf.js";
|
|
26
|
+
import"./index-c0whkev9.js";
|
|
27
|
+
import"./index-q8f4kawk.js";
|
|
28
|
+
import"./index-37x76zdn.js";
|
|
29
|
+
|
|
30
|
+
// src/cli/commands/build.ts
|
|
31
|
+
async function runBuildCommand(parsed, logger, options) {
|
|
32
|
+
const theme = createCliTheme(parsed.options);
|
|
33
|
+
logLine(logger);
|
|
34
|
+
logLine(logger, `${cyanBold("build", theme)} ${dim("Preparing production artifacts", theme)}`);
|
|
35
|
+
try {
|
|
36
|
+
await prepareBuildArtifacts(parsed, logger, options);
|
|
37
|
+
logger.success("Generated .devflare/wrangler.jsonc");
|
|
38
|
+
logger.success("Generated .devflare/build/wrangler.jsonc");
|
|
39
|
+
logger.success("Generated .wrangler/deploy/config.json");
|
|
40
|
+
logger.success("Build complete!");
|
|
41
|
+
return { exitCode: 0 };
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error instanceof Error) {
|
|
44
|
+
logger.error("Build failed:", error.message);
|
|
45
|
+
if (parsed.options.debug) {
|
|
46
|
+
logger.error(error.stack);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { exitCode: 1 };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
runBuildCommand
|
|
54
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ConsolaInstance } from 'consola';
|
|
2
2
|
import type { CliOptions, ParsedArgs } from '../index';
|
|
3
|
+
import type { FileSystem } from '../dependencies';
|
|
3
4
|
import { type DevflareConfig } from '../../config';
|
|
4
5
|
import { type WranglerConfig } from '../../config/compiler';
|
|
5
6
|
import { type EffectiveViteProjectDetection } from '../../vite';
|
|
@@ -22,6 +23,18 @@ export declare function getViteBuildCleanupTargets(cwd: string, wranglerConfig:
|
|
|
22
23
|
export declare function createDeferredCleanupPath(targetPath: string, uniqueSuffix?: string): string;
|
|
23
24
|
export declare function removePathWithRetries(targetPath: string, logger: ConsolaInstance, attempts?: number, cleanupFs?: CleanupFileSystem): Promise<void>;
|
|
24
25
|
export declare function cleanupViteBuildOutputs(cwd: string, wranglerConfig: WranglerConfig, logger: ConsolaInstance): Promise<void>;
|
|
26
|
+
export declare function resolveLocalViteExecutable(cwd: string, fs: FileSystem): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Walk up the directory tree from `startDir` looking for
|
|
29
|
+
* `node_modules/<segments>`. Returns the first match or null.
|
|
30
|
+
*
|
|
31
|
+
* This preserves the workspace-local (symlinked) path rather than the
|
|
32
|
+
* package manager's underlying cache realpath, which matters for Node
|
|
33
|
+
* package resolution semantics under Bun on Windows.
|
|
34
|
+
*/
|
|
35
|
+
export declare function findWorkspaceLocalBinary(startDir: string, fs: FileSystem, segments: readonly string[]): Promise<string | null>;
|
|
36
|
+
/** True when the current process is Bun (and `bun` is therefore on PATH). */
|
|
37
|
+
export declare function isRunningUnderBun(): boolean;
|
|
25
38
|
export declare function prepareBuildArtifacts(parsed: ParsedArgs, logger: ConsolaInstance, options: CliOptions): Promise<PreparedBuildArtifactsResult>;
|
|
26
39
|
export {};
|
|
27
40
|
//# sourceMappingURL=build-artifacts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-artifacts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/build-artifacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"build-artifacts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/build-artifacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EAKN,KAAK,cAAc,EACnB,MAAM,uBAAuB,CAAA;AAM9B,OAAO,EAGN,KAAK,6BAA6B,EAClC,MAAM,YAAY,CAAA;AAanB,MAAM,WAAW,4BAA4B;IAC5C,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,cAAc,CAAA;IAC9B,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,6BAA6B,CAAA;CAC1C;AAMD,UAAU,iBAAiB;IAC1B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,EAAE,CACD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QACR,SAAS,EAAE,OAAO,CAAA;QAClB,KAAK,EAAE,OAAO,CAAA;KACd,GACC,OAAO,CAAC,IAAI,CAAC,CAAA;CAChB;AAaD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,cAAc,GAC5B,cAAc,CAEhB;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,GAAG,MAAM,EAAE,CAqBhG;AAwBD,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAM3F;AA0CD,wBAAsB,qBAAqB,CAC1C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,QAAQ,GAAE,MAAU,EACpB,SAAS,CAAC,EAAE,iBAAiB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA6Cf;AAED,wBAAsB,uBAAuB,CAC5C,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAMf;AA4FD,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B7F;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC7C,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBxB;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,IAAI,OAAO,CAG3C;AAED,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,UAAU,GACjB,OAAO,CAAC,4BAA4B,CAAC,CA4JvC"}
|
package/dist/cli/index.js
CHANGED
package/dist/cloudflare/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/cloudflare/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAEpF,OAAO,KAAK,EACX,oBAAoB,EACpB,gCAAgC,EAEhC,2BAA2B,EAC3B,MAAM,SAAS,CAAA;AAGhB,eAAO,MAAM,6BAA6B,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/cloudflare/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAEpF,OAAO,KAAK,EACX,oBAAoB,EACpB,gCAAgC,EAEhC,2BAA2B,EAC3B,MAAM,SAAS,CAAA;AAGhB,eAAO,MAAM,6BAA6B,cAAc,CAAA;AAsExD,eAAO,MAAM,0BAA0B,0NAEO,CAAA;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,oCAAoC,EAAE,MAAM,CACxD,MAAM,OAAO,0BAA0B,EACvC,MAAM,CASN,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,0BAA0B,CAAA;AAE9E;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAC1C,YAAY,EAAE,wBAAwB,EACtC,eAAe,EAAE,IAAI,CAAC,2BAA2B,EAAE,IAAI,GAAG,MAAM,CAAC,EACjE,OAAO,CAAC,EAAE;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC1C,GACC,OAAO,CAqBT;AA2GD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAe/D;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQjE;AAED,wBAAgB,2BAA2B,CAC1C,MAAM,EAAE,oBAAoB,EAAE,GAC5B,oBAAoB,EAAE,CAExB;AAED,wBAAgB,8BAA8B,CAC7C,gBAAgB,EAAE,2BAA2B,EAAE,GAC7C,2BAA2B,EAAE,CAoB/B;AAED,wBAAgB,iCAAiC,CAChD,gBAAgB,EAAE,2BAA2B,EAAE,GAC7C,2BAA2B,EAAE,CAgB/B;AAED,wBAAsB,gCAAgC,CACrD,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAOxC;AAED,wBAAsB,yBAAyB,CAC9C,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGjC;AAED,wBAAsB,0BAA0B,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,gCAAgC,CAAC,CAE3C;AAED,wBAAsB,6BAA6B,CAClD,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAsB,0BAA0B,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACR,IAAI,EAAE,MAAM,CAAA;IACZ,kBAAkB,EAAE,MAAM,EAAE,CAAA;CAC5B,EACD,aAAa,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CA+B/B"}
|