nolo-cli 0.7.0 → 0.8.0-alpha.11
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/_executeModel-GPU2276G.js +198 -0
- package/action-PAXRPJJF.js +27 -0
- package/addContentAction-CZVWF3QZ.js +25 -0
- package/addDialogAgentAction-CCIDTPHC.js +67 -0
- package/agentDeleteCommand-4ZZFM6AT.js +323 -0
- package/agentEmailCommands-C4FIVQYV.js +621 -0
- package/agentListCommands-VQAKVNEX.js +219 -0
- package/agentMachineCommands-ONFDXZUQ.js +421 -0
- package/agentPullCommand-O2MTUAFR.js +122 -0
- package/agentRecordCommands-QANUGHLK.js +89 -0
- package/agentRunCommand-A3OSRB5Q.js +102 -0
- package/agentRunControl-K4VKNEHF.js +57 -0
- package/agentRuntimeLocal-62ZB2ODP.js +99 -0
- package/agentSlice-GCGLVR2N.js +41 -0
- package/authCommand-WXMD3IPR.js +574 -0
- package/authCommands-X74AFDTC.js +26 -0
- package/chunk-2EISRLRC.js +238 -0
- package/chunk-2FTTDCD4.js +675 -0
- package/chunk-2MALU52L.js +51 -0
- package/chunk-2UZXR7WO.js +3631 -0
- package/chunk-3ASDTTEI.js +1774 -0
- package/chunk-3EUW3WEO.js +8 -0
- package/chunk-3LY4F7SV.js +9293 -0
- package/chunk-4CQLVGRV.js +50 -0
- package/chunk-4IJYA27C.js +342 -0
- package/chunk-4SN6J65J.js +38 -0
- package/chunk-4VNS5WPM.js +42 -0
- package/chunk-53DNV5AT.js +421 -0
- package/chunk-572EKYLF.js +792 -0
- package/chunk-5MIDPSSK.js +206 -0
- package/chunk-5MMAK75Q.js +15 -0
- package/chunk-63W5N6P3.js +150 -0
- package/chunk-6B7G54GE.js +1078 -0
- package/chunk-6HYVJV7B.js +102 -0
- package/chunk-6WD3OOJS.js +20 -0
- package/chunk-7OC5VCLW.js +929 -0
- package/chunk-7YLKNMOM.js +562 -0
- package/chunk-ATNTHIZI.js +13 -0
- package/chunk-AUGHVUFE.js +69 -0
- package/chunk-AVMKZHBC.js +85 -0
- package/chunk-AZPCASRE.js +36 -0
- package/chunk-BR2WP3DF.js +548 -0
- package/chunk-BSTNFPHD.js +231 -0
- package/chunk-CF2WZF4N.js +134 -0
- package/chunk-CF7PE763.js +10 -0
- package/chunk-CJH2VTEU.js +360 -0
- package/chunk-CKOJQDKR.js +198 -0
- package/chunk-CM54RSSA.js +206 -0
- package/chunk-CQAHS7YO.js +4300 -0
- package/chunk-CWMSB67P.js +34 -0
- package/chunk-DFFIZ25G.js +30 -0
- package/chunk-DWLEOOGR.js +8 -0
- package/chunk-DZ3XJVET.js +231 -0
- package/chunk-EHLHSX7R.js +1433 -0
- package/chunk-ELRRLDWI.js +478 -0
- package/chunk-EYEEHCU4.js +3066 -0
- package/chunk-F6QQI5YI.js +19 -0
- package/chunk-G3SUCT4W.js +8 -0
- package/chunk-G5H7RNFL.js +807 -0
- package/chunk-GAKEBQD6.js +30 -0
- package/chunk-GBRG75BQ.js +86 -0
- package/chunk-GCMRDRCQ.js +190 -0
- package/chunk-GGUO4FKF.js +27158 -0
- package/chunk-GGXABIPP.js +628 -0
- package/chunk-H2RMRZJE.js +113 -0
- package/chunk-H33743XH.js +25 -0
- package/chunk-HEIIIZBX.js +104 -0
- package/chunk-HNMXYYJR.js +12 -0
- package/chunk-I3D64LRJ.js +1447 -0
- package/chunk-IAXBCTTE.js +175 -0
- package/chunk-IDZTNRP2.js +85 -0
- package/chunk-ISNCLGUZ.js +146 -0
- package/chunk-IYQV26RA.js +138 -0
- package/chunk-J4576WMJ.js +91 -0
- package/chunk-J5KV47ZW.js +222 -0
- package/chunk-JBTJAPUF.js +35 -0
- package/chunk-JZPBVBIY.js +94 -0
- package/chunk-KB7YFGL6.js +34 -0
- package/chunk-KKY4B2Q2.js +21 -0
- package/chunk-KQHGZWSV.js +63 -0
- package/chunk-KUG52IAP.js +8 -0
- package/chunk-KX6YBIHG.js +8 -0
- package/chunk-LAWBMYBC.js +171 -0
- package/chunk-LCBAMY2M.js +60 -0
- package/chunk-LM25IZBJ.js +902 -0
- package/chunk-LM6IYQ3F.js +16 -0
- package/chunk-M76ECQRD.js +13658 -0
- package/chunk-MRC4Q34M.js +188 -0
- package/chunk-NXZGF7F7.js +2878 -0
- package/chunk-OF5H3QWS.js +300 -0
- package/chunk-OLZBQWZU.js +6 -0
- package/chunk-OWOHNGCN.js +50 -0
- package/chunk-PN7AFLOK.js +3401 -0
- package/chunk-QR5IPGT3.js +24674 -0
- package/chunk-QSJ3HFEF.js +8 -0
- package/chunk-QYXLLLGL.js +4519 -0
- package/chunk-R2HXWML7.js +1949 -0
- package/chunk-ROWQEJRP.js +139 -0
- package/chunk-S7Z2HMCN.js +25 -0
- package/chunk-SYOF5TAS.js +962 -0
- package/chunk-TDIQFT2F.js +301 -0
- package/chunk-TILFE6LV.js +381 -0
- package/chunk-TZNCFAUP.js +2157 -0
- package/chunk-U4TRT5V4.js +246 -0
- package/chunk-U6VC4MU4.js +8 -0
- package/chunk-UAD2WT54.js +64 -0
- package/chunk-USZMK5UT.js +105 -0
- package/chunk-VEJLAVTC.js +2052 -0
- package/chunk-VF4K2QE6.js +21 -0
- package/chunk-VHBWHNVT.js +59 -0
- package/chunk-VIDPVFP3.js +20 -0
- package/chunk-VP4WJWKW.js +8882 -0
- package/chunk-VQ2AJRGD.js +148 -0
- package/chunk-W4NVOSFF.js +37 -0
- package/chunk-WWC7I6TA.js +8 -0
- package/chunk-X7W4TNB4.js +1550 -0
- package/chunk-XBIUN5CR.js +191 -0
- package/chunk-XDVAYP26.js +537 -0
- package/chunk-XKIMRZO2.js +221 -0
- package/chunk-Y5GCAMGP.js +9 -0
- package/chunk-YOUZDXU7.js +9013 -0
- package/chunk-Z4NR32XR.js +50 -0
- package/chunk-ZNFJWEN4.js +56 -0
- package/cliExecutor-DNE7TCC4.js +36 -0
- package/clipboardy-BVE3LVEH.js +12001 -0
- package/createAgentAutomationAction-537X433B.js +864 -0
- package/createDialogAction-YUD4RKBS.js +52 -0
- package/createPageAction-KJMFHL4C.js +169 -0
- package/db-HCJ5PRB5.js +271 -0
- package/dbSlice-C4UJLRZP.js +59 -0
- package/deleteFile-4SKGPHOZ.js +41 -0
- package/dialogCommands-H74KJKHC.js +59 -0
- package/dialogSlice-ETSD4YWS.js +146 -0
- package/docCreateCommands-ADUSU34K.js +215 -0
- package/docDeleteCommands-ZXV3S5OS.js +176 -0
- package/docReadCommands-YYYI6LT7.js +129 -0
- package/docStore-ZBF5DDKR.js +96 -0
- package/docUpdateCommands-7MGJ3BYA.js +313 -0
- package/fetchMessages-JOCYIFKL.js +16 -0
- package/getPricing-PWPJ6MNV.js +30 -0
- package/handleSendMessageAction-MGKI62Y6.js +183 -0
- package/index.js +184 -112288
- package/lib-FYYBQIXS.js +19839 -0
- package/localDialogRead-D3BELSTF.js +26 -0
- package/localFirstLog-DHNOY2NA.js +19 -0
- package/localRuntimeAuthority-TEGCOWX4.js +471 -0
- package/localRuntimeDb-LGDF6FQP.js +12 -0
- package/machineCommands-RMTMN7VQ.js +774 -0
- package/machineInfo-M6KB6HZN.js +10 -0
- package/machineWsRunDispatch-UIP355FN.js +105 -0
- package/memoryCommands-O4MIPIWQ.js +476 -0
- package/models-XLEOET3E.js +9 -0
- package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
- package/package.json +3 -25
- package/read-RIJCIVKX.js +17 -0
- package/readDocTool-GZD2N3LO.js +16 -0
- package/readlineWorkspace-CRNQRZ6D.js +5374 -0
- package/removeDialogAgentAction-CXLST3N6.js +72 -0
- package/runAgentClientLoop-2S334SGA.js +288 -0
- package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
- package/setDialogExtraReferencesAction-LP6VYGU7.js +59 -0
- package/setPrimaryDialogAgentAction-D3GGH23T.js +79 -0
- package/settingSlice-J4I3Z5H7.js +198 -0
- package/skillSummaryMarker-42HKSXYY.js +9 -0
- package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
- package/slateUtils-2M7MUTWX.js +19 -0
- package/spaceCommands-NDEWMFZJ.js +450 -0
- package/spaceSlice-RLB6RTHO.js +145 -0
- package/streamAgentChatTurn-Y2TTYPBD.js +4503 -0
- package/tableCommands-GOFP7QKA.js +1286 -0
- package/toolApiClient-QI3YBNWB.js +26 -0
- package/tools-YZYLY2ZQ.js +83 -0
- package/understanding-HCSFPE7R.js +318 -0
- package/updateCommands-VOSPKXFF.js +31 -0
- package/updateDialogTitleAction-LQV6QLBW.js +185 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asOptionalTrimmedString
|
|
3
|
+
} from "./chunk-G3SUCT4W.js";
|
|
4
|
+
import {
|
|
5
|
+
isRecord
|
|
6
|
+
} from "./chunk-KUG52IAP.js";
|
|
7
|
+
|
|
8
|
+
// packages/cli/cliSpaceHelpers.ts
|
|
9
|
+
function normalizeSpaceIdInput(rawInput) {
|
|
10
|
+
const raw = rawInput.trim();
|
|
11
|
+
if (!raw) return "";
|
|
12
|
+
let candidate = raw;
|
|
13
|
+
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
14
|
+
const match = new URL(raw).pathname.match(/^\/space\/([^/?#]+)/);
|
|
15
|
+
if (!match?.[1]) return "";
|
|
16
|
+
candidate = decodeURIComponent(match[1]);
|
|
17
|
+
}
|
|
18
|
+
return candidate.startsWith("space-") ? candidate.slice("space-".length) : candidate;
|
|
19
|
+
}
|
|
20
|
+
function buildSpaceLookup(rawInput) {
|
|
21
|
+
const spaceId = normalizeSpaceIdInput(rawInput);
|
|
22
|
+
return {
|
|
23
|
+
spaceId,
|
|
24
|
+
spaceKey: spaceId ? `space-${spaceId}` : ""
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function getSpaceContentKeys(spaceRecord) {
|
|
28
|
+
const keys = /* @__PURE__ */ new Set();
|
|
29
|
+
const contents = spaceRecord?.contents;
|
|
30
|
+
if (!contents || typeof contents !== "object") return keys;
|
|
31
|
+
for (const [entryKey, value] of Object.entries(contents)) {
|
|
32
|
+
const trimmedEntryKey = asOptionalTrimmedString(entryKey);
|
|
33
|
+
if (trimmedEntryKey) {
|
|
34
|
+
keys.add(trimmedEntryKey);
|
|
35
|
+
}
|
|
36
|
+
if (isRecord(value)) {
|
|
37
|
+
const contentKey = asOptionalTrimmedString(value.contentKey);
|
|
38
|
+
if (contentKey) {
|
|
39
|
+
keys.add(contentKey);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return keys;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
normalizeSpaceIdInput,
|
|
48
|
+
buildSpaceLookup,
|
|
49
|
+
getSpaceContentKeys
|
|
50
|
+
};
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generatePkcePair,
|
|
3
|
+
startCallbackServer
|
|
4
|
+
} from "./chunk-EHLHSX7R.js";
|
|
5
|
+
import {
|
|
6
|
+
toErrorMessage
|
|
7
|
+
} from "./chunk-HNMXYYJR.js";
|
|
8
|
+
import {
|
|
9
|
+
asOptionalFiniteNumber
|
|
10
|
+
} from "./chunk-WWC7I6TA.js";
|
|
11
|
+
|
|
12
|
+
// packages/cli/oauth/flows/cloudflare.ts
|
|
13
|
+
var CLOUDFLARE_OAUTH_AUTH_ENDPOINT = "https://dash.cloudflare.com/oauth2/auth";
|
|
14
|
+
var CLOUDFLARE_OAUTH_TOKEN_ENDPOINT = "https://dash.cloudflare.com/oauth2/token";
|
|
15
|
+
var CLOUDFLARE_API_BASE = "https://api.cloudflare.com/client/v4";
|
|
16
|
+
var CLOUDFLARE_OAUTH_REDIRECT_HOST = "127.0.0.1";
|
|
17
|
+
var CLOUDFLARE_OAUTH_REDIRECT_PORT = 56122;
|
|
18
|
+
var CLOUDFLARE_OAUTH_REDIRECT_PATH = "/callback";
|
|
19
|
+
var ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
|
|
20
|
+
var TOKEN_REQUEST_TIMEOUT_MS = 2e4;
|
|
21
|
+
var DEFAULT_SCOPE = "account:read zone:read zone:edit user:read user:edit";
|
|
22
|
+
function generateState() {
|
|
23
|
+
const bytes = new Uint8Array(16);
|
|
24
|
+
crypto.getRandomValues(bytes);
|
|
25
|
+
return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
26
|
+
}
|
|
27
|
+
function getClientId(args) {
|
|
28
|
+
const value = args?.clientId?.trim() || process.env.CLOUDFLARE_OAUTH_CLIENT_ID?.trim();
|
|
29
|
+
if (!value) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"Cloudflare OAuth client ID is required. Set CLOUDFLARE_OAUTH_CLIENT_ID or pass --client-id."
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
function getScope(args) {
|
|
37
|
+
return args?.scope?.trim() || process.env.CLOUDFLARE_OAUTH_SCOPE?.trim() || DEFAULT_SCOPE;
|
|
38
|
+
}
|
|
39
|
+
function buildCloudflareAuthorizeUrl(opts) {
|
|
40
|
+
const params = new URLSearchParams({
|
|
41
|
+
response_type: "code",
|
|
42
|
+
client_id: opts.clientId,
|
|
43
|
+
redirect_uri: opts.redirectUri,
|
|
44
|
+
scope: opts.scope,
|
|
45
|
+
code_challenge: opts.codeChallenge,
|
|
46
|
+
code_challenge_method: "S256",
|
|
47
|
+
state: opts.state
|
|
48
|
+
});
|
|
49
|
+
return `${CLOUDFLARE_OAUTH_AUTH_ENDPOINT}?${params.toString()}`;
|
|
50
|
+
}
|
|
51
|
+
async function exchangeCloudflareToken(fetchImpl, code, redirectUri, verifier, clientId) {
|
|
52
|
+
const body = new URLSearchParams({
|
|
53
|
+
grant_type: "authorization_code",
|
|
54
|
+
client_id: clientId,
|
|
55
|
+
code,
|
|
56
|
+
redirect_uri: redirectUri,
|
|
57
|
+
code_verifier: verifier
|
|
58
|
+
});
|
|
59
|
+
const response = await fetchImpl(CLOUDFLARE_OAUTH_TOKEN_ENDPOINT, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: {
|
|
62
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
63
|
+
Accept: "application/json"
|
|
64
|
+
},
|
|
65
|
+
body,
|
|
66
|
+
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
let detail = "";
|
|
70
|
+
try {
|
|
71
|
+
detail = (await response.text()).trim();
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Cloudflare token exchange failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const data = await response.json();
|
|
79
|
+
if (typeof data.access_token !== "string" || !data.access_token) {
|
|
80
|
+
throw new Error("Cloudflare token exchange response missing access_token");
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
accessToken: data.access_token,
|
|
84
|
+
refreshToken: typeof data.refresh_token === "string" ? data.refresh_token : void 0,
|
|
85
|
+
expiresIn: asOptionalFiniteNumber(data.expires_in),
|
|
86
|
+
scope: typeof data.scope === "string" ? data.scope : void 0,
|
|
87
|
+
idToken: typeof data.id_token === "string" ? data.id_token : void 0
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
async function runCloudflareOAuthLogin(deps = {}) {
|
|
91
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
92
|
+
const output = deps.output ?? console;
|
|
93
|
+
const error = deps.error ?? console;
|
|
94
|
+
const clientId = getClientId(deps);
|
|
95
|
+
const scope = getScope(deps);
|
|
96
|
+
const redirectUri = `http://${CLOUDFLARE_OAUTH_REDIRECT_HOST}:${CLOUDFLARE_OAUTH_REDIRECT_PORT}${CLOUDFLARE_OAUTH_REDIRECT_PATH}`;
|
|
97
|
+
let handle;
|
|
98
|
+
try {
|
|
99
|
+
handle = await startCallbackServer({
|
|
100
|
+
port: CLOUDFLARE_OAUTH_REDIRECT_PORT,
|
|
101
|
+
hostname: CLOUDFLARE_OAUTH_REDIRECT_HOST,
|
|
102
|
+
timeoutMs: 5 * 6e4
|
|
103
|
+
});
|
|
104
|
+
} catch (err) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Failed to start Cloudflare OAuth callback server on ${CLOUDFLARE_OAUTH_REDIRECT_PORT}: ${toErrorMessage(err)}`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const state = generateState();
|
|
111
|
+
const pkce = await generatePkcePair();
|
|
112
|
+
const authUrl = buildCloudflareAuthorizeUrl({
|
|
113
|
+
redirectUri,
|
|
114
|
+
codeChallenge: pkce.challenge,
|
|
115
|
+
state,
|
|
116
|
+
clientId,
|
|
117
|
+
scope
|
|
118
|
+
});
|
|
119
|
+
output.log(
|
|
120
|
+
`Open the following URL in your browser to authorize Cloudflare access:
|
|
121
|
+
${authUrl}
|
|
122
|
+
|
|
123
|
+
Requested scopes: ${scope}`
|
|
124
|
+
);
|
|
125
|
+
if (deps.openBrowser) {
|
|
126
|
+
try {
|
|
127
|
+
await deps.openBrowser(authUrl);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
error.error(
|
|
130
|
+
`Failed to open browser automatically: ${toErrorMessage(err)}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const callback = await handle.waitForCode();
|
|
135
|
+
const token = await exchangeCloudflareToken(
|
|
136
|
+
fetchImpl,
|
|
137
|
+
callback.code,
|
|
138
|
+
redirectUri,
|
|
139
|
+
pkce.verifier,
|
|
140
|
+
clientId
|
|
141
|
+
);
|
|
142
|
+
const now = (deps.now ?? Date.now)();
|
|
143
|
+
const expiresIn = token.expiresIn;
|
|
144
|
+
return {
|
|
145
|
+
provider: "cloudflare",
|
|
146
|
+
accessToken: token.accessToken,
|
|
147
|
+
refreshToken: token.refreshToken,
|
|
148
|
+
expiresAt: typeof expiresIn === "number" ? now + expiresIn * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS : void 0,
|
|
149
|
+
scope: token.scope,
|
|
150
|
+
idToken: token.idToken,
|
|
151
|
+
obtainedAt: now
|
|
152
|
+
};
|
|
153
|
+
} finally {
|
|
154
|
+
await handle.close();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function createCloudflareApiToken(input) {
|
|
158
|
+
const fetchImpl = input.fetchImpl ?? fetch;
|
|
159
|
+
const response = await fetchImpl(`${CLOUDFLARE_API_BASE}/user/tokens`, {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: {
|
|
162
|
+
"Content-Type": "application/json",
|
|
163
|
+
Authorization: `Bearer ${input.accessToken}`
|
|
164
|
+
},
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
name: input.name,
|
|
167
|
+
policies: input.policies
|
|
168
|
+
}),
|
|
169
|
+
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
|
|
170
|
+
});
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
let detail = "";
|
|
173
|
+
try {
|
|
174
|
+
detail = (await response.text()).trim();
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Cloudflare API token creation failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const data = await response.json();
|
|
182
|
+
const tokenValue = data.result?.value;
|
|
183
|
+
if (typeof tokenValue !== "string" || !tokenValue) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
"Cloudflare API token creation response did not contain a token value"
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return tokenValue;
|
|
189
|
+
}
|
|
190
|
+
async function listCloudflarePermissionGroups(accessToken, fetchImpl = fetch) {
|
|
191
|
+
const response = await fetchImpl(
|
|
192
|
+
`${CLOUDFLARE_API_BASE}/user/tokens/permission_groups`,
|
|
193
|
+
{
|
|
194
|
+
method: "GET",
|
|
195
|
+
headers: {
|
|
196
|
+
Authorization: `Bearer ${accessToken}`,
|
|
197
|
+
Accept: "application/json"
|
|
198
|
+
},
|
|
199
|
+
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
let detail = "";
|
|
204
|
+
try {
|
|
205
|
+
detail = (await response.text()).trim();
|
|
206
|
+
} catch {
|
|
207
|
+
}
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Cloudflare permission groups lookup failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
const data = await response.json();
|
|
213
|
+
if (!Array.isArray(data.result)) {
|
|
214
|
+
throw new Error("Cloudflare permission groups response missing result array");
|
|
215
|
+
}
|
|
216
|
+
return data.result.filter(
|
|
217
|
+
(group) => typeof group.id === "string" && typeof group.name === "string" && Array.isArray(group.permissions)
|
|
218
|
+
).map((group) => ({
|
|
219
|
+
id: group.id,
|
|
220
|
+
name: group.name,
|
|
221
|
+
permissions: group.permissions
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
async function findCloudflareZoneIdByName(accessToken, zoneName, fetchImpl = fetch) {
|
|
225
|
+
const response = await fetchImpl(
|
|
226
|
+
`${CLOUDFLARE_API_BASE}/zones?name=${encodeURIComponent(zoneName)}`,
|
|
227
|
+
{
|
|
228
|
+
method: "GET",
|
|
229
|
+
headers: {
|
|
230
|
+
Authorization: `Bearer ${accessToken}`,
|
|
231
|
+
Accept: "application/json"
|
|
232
|
+
},
|
|
233
|
+
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
if (!response.ok) {
|
|
237
|
+
let detail = "";
|
|
238
|
+
try {
|
|
239
|
+
detail = (await response.text()).trim();
|
|
240
|
+
} catch {
|
|
241
|
+
}
|
|
242
|
+
throw new Error(
|
|
243
|
+
`Cloudflare zone lookup failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
const data = await response.json();
|
|
247
|
+
if (!Array.isArray(data.result)) {
|
|
248
|
+
throw new Error("Cloudflare zone lookup response missing result array");
|
|
249
|
+
}
|
|
250
|
+
const zone = data.result.find((z) => z.name === zoneName);
|
|
251
|
+
return zone?.id ?? null;
|
|
252
|
+
}
|
|
253
|
+
async function generateCloudflareEmailRoutingToken(input) {
|
|
254
|
+
const fetchImpl = input.fetchImpl ?? fetch;
|
|
255
|
+
const zoneId = await findCloudflareZoneIdByName(
|
|
256
|
+
input.accessToken,
|
|
257
|
+
input.zoneName,
|
|
258
|
+
fetchImpl
|
|
259
|
+
);
|
|
260
|
+
if (!zoneId) {
|
|
261
|
+
throw new Error(`Cloudflare zone "${input.zoneName}" not found`);
|
|
262
|
+
}
|
|
263
|
+
const groups = await listCloudflarePermissionGroups(
|
|
264
|
+
input.accessToken,
|
|
265
|
+
fetchImpl
|
|
266
|
+
);
|
|
267
|
+
const emailRoutingGroup = groups.find(
|
|
268
|
+
(g) => g.name.toLowerCase().includes("email routing")
|
|
269
|
+
);
|
|
270
|
+
if (!emailRoutingGroup) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
"Cloudflare Email Routing Edit permission group not found for this account."
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
const token = await createCloudflareApiToken({
|
|
276
|
+
name: input.tokenName ?? `nolo-email-routing-${input.zoneName}-${Date.now()}`,
|
|
277
|
+
policies: [buildEmailRoutingPolicy(zoneId, [emailRoutingGroup.id])],
|
|
278
|
+
accessToken: input.accessToken,
|
|
279
|
+
fetchImpl
|
|
280
|
+
});
|
|
281
|
+
return { token, zoneId };
|
|
282
|
+
}
|
|
283
|
+
function buildEmailRoutingPolicy(zoneId, emailRoutingPermissionGroupIds) {
|
|
284
|
+
if (emailRoutingPermissionGroupIds.length === 0) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
"Email routing permission group IDs are required. Resolve them with listCloudflarePermissionGroups."
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
effect: "allow",
|
|
291
|
+
resources: {
|
|
292
|
+
"com.cloudflare.api.account": "*",
|
|
293
|
+
"com.cloudflare.api.zone": zoneId
|
|
294
|
+
},
|
|
295
|
+
permission_groups: emailRoutingPermissionGroupIds.map((id) => ({ id }))
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// packages/cli/oauth/envFile.ts
|
|
300
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
301
|
+
import { resolve } from "node:path";
|
|
302
|
+
function upsertEnvVariable(filePath, key, value) {
|
|
303
|
+
const normalizedPath = resolve(filePath);
|
|
304
|
+
let content = "";
|
|
305
|
+
if (existsSync(normalizedPath)) {
|
|
306
|
+
content = readFileSync(normalizedPath, "utf8");
|
|
307
|
+
}
|
|
308
|
+
const lines = content.length > 0 ? content.split("\n") : [];
|
|
309
|
+
const keyPrefix = `${key}=`;
|
|
310
|
+
let replaced = false;
|
|
311
|
+
const newLines = lines.map((line) => {
|
|
312
|
+
const trimmed = line.trim();
|
|
313
|
+
if (trimmed.startsWith(keyPrefix) || trimmed.startsWith(`${key} =`)) {
|
|
314
|
+
replaced = true;
|
|
315
|
+
return `${key}=${value}`;
|
|
316
|
+
}
|
|
317
|
+
return line;
|
|
318
|
+
});
|
|
319
|
+
if (!replaced) {
|
|
320
|
+
if (newLines.length > 0 && newLines[newLines.length - 1] !== "") {
|
|
321
|
+
newLines.push("");
|
|
322
|
+
}
|
|
323
|
+
newLines.push(`${key}=${value}`);
|
|
324
|
+
}
|
|
325
|
+
writeFileSync(normalizedPath, newLines.join("\n"), "utf8");
|
|
326
|
+
}
|
|
327
|
+
function parseFlagWithOptionalValue(args, flag) {
|
|
328
|
+
const index = args.indexOf(flag);
|
|
329
|
+
if (index === -1) return void 0;
|
|
330
|
+
const next = args[index + 1];
|
|
331
|
+
if (next && !next.startsWith("--")) {
|
|
332
|
+
return next;
|
|
333
|
+
}
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export {
|
|
338
|
+
runCloudflareOAuthLogin,
|
|
339
|
+
generateCloudflareEmailRoutingToken,
|
|
340
|
+
upsertEnvVariable,
|
|
341
|
+
parseFlagWithOptionalValue
|
|
342
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// packages/core/localOrigins.ts
|
|
2
|
+
var DEFAULT_LOCAL_HOST = "127.0.0.1";
|
|
3
|
+
var DEFAULT_LOCAL_API_PORT = "38123";
|
|
4
|
+
var DEFAULT_LOCAL_API_ORIGIN = `http://${DEFAULT_LOCAL_HOST}:${DEFAULT_LOCAL_API_PORT}`;
|
|
5
|
+
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
6
|
+
"127.0.0.1",
|
|
7
|
+
"localhost",
|
|
8
|
+
"::1"
|
|
9
|
+
]);
|
|
10
|
+
function isLoopbackHostname(hostname) {
|
|
11
|
+
if (typeof hostname !== "string") return false;
|
|
12
|
+
let normalized = hostname.trim().toLowerCase();
|
|
13
|
+
if (!normalized) return false;
|
|
14
|
+
if (normalized.startsWith("[") && normalized.endsWith("]")) {
|
|
15
|
+
normalized = normalized.slice(1, -1);
|
|
16
|
+
}
|
|
17
|
+
return LOOPBACK_HOSTNAMES.has(normalized);
|
|
18
|
+
}
|
|
19
|
+
function isLoopbackUrl(value) {
|
|
20
|
+
if (typeof value !== "string" || !value.trim()) return false;
|
|
21
|
+
try {
|
|
22
|
+
return isLoopbackHostname(new URL(value).hostname);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
var LOCAL_SERVER_URL_PATTERN = /^https?:\/\/(?:(?:\d{1,3}\.){3}\d{1,3}|localhost|nolotus\.local)(?::\d+)?$/i;
|
|
28
|
+
function isLocalServerUrl(value) {
|
|
29
|
+
if (typeof value !== "string") return false;
|
|
30
|
+
return LOCAL_SERVER_URL_PATTERN.test(value.trim());
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
DEFAULT_LOCAL_API_ORIGIN,
|
|
35
|
+
isLoopbackHostname,
|
|
36
|
+
isLoopbackUrl,
|
|
37
|
+
isLocalServerUrl
|
|
38
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
__require,
|
|
39
|
+
__commonJS,
|
|
40
|
+
__export,
|
|
41
|
+
__toESM
|
|
42
|
+
};
|