@shipdit/cli 0.0.2
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/LICENSE +190 -0
- package/README.md +14 -0
- package/dist/index.mjs +4114 -0
- package/package.json +48 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command, CommanderError } from "commander";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { createJiti } from "jiti";
|
|
8
|
+
|
|
9
|
+
//#region src/lib/config.ts
|
|
10
|
+
function readJsonFile(filePath) {
|
|
11
|
+
if (!fs.existsSync(filePath)) return null;
|
|
12
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
13
|
+
}
|
|
14
|
+
function globalConfigDir() {
|
|
15
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
16
|
+
if (xdg) return path.join(xdg, "shipd");
|
|
17
|
+
return path.join(os.homedir(), ".config", "shipd");
|
|
18
|
+
}
|
|
19
|
+
function ensureDir(dir) {
|
|
20
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
function loadGlobalConfig() {
|
|
23
|
+
return readJsonFile(path.join(globalConfigDir(), "config.json")) ?? {};
|
|
24
|
+
}
|
|
25
|
+
function saveGlobalConfig(config) {
|
|
26
|
+
const dir = globalConfigDir();
|
|
27
|
+
ensureDir(dir);
|
|
28
|
+
fs.writeFileSync(path.join(dir, "config.json"), `${JSON.stringify(config, null, 2)}\n`, { mode: 384 });
|
|
29
|
+
}
|
|
30
|
+
function loadCredentials() {
|
|
31
|
+
return readJsonFile(path.join(globalConfigDir(), "credentials.json")) ?? {};
|
|
32
|
+
}
|
|
33
|
+
function saveCredentials(credentials) {
|
|
34
|
+
const dir = globalConfigDir();
|
|
35
|
+
ensureDir(dir);
|
|
36
|
+
fs.writeFileSync(path.join(dir, "credentials.json"), `${JSON.stringify(credentials, null, 2)}\n`, { mode: 384 });
|
|
37
|
+
}
|
|
38
|
+
function clearCredentials() {
|
|
39
|
+
const file = path.join(globalConfigDir(), "credentials.json");
|
|
40
|
+
if (fs.existsSync(file)) fs.unlinkSync(file);
|
|
41
|
+
}
|
|
42
|
+
function findProjectRoot(start = process.cwd()) {
|
|
43
|
+
let current = path.resolve(start);
|
|
44
|
+
while (true) {
|
|
45
|
+
if (fs.existsSync(path.join(current, "shipd.config.ts")) || fs.existsSync(path.join(current, ".shipd", "config.json"))) return current;
|
|
46
|
+
const parent = path.dirname(current);
|
|
47
|
+
if (parent === current) return process.cwd();
|
|
48
|
+
current = parent;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function loadProjectConfig(projectRoot, configPath) {
|
|
52
|
+
return readJsonFile(configPath ?? path.join(projectRoot, ".shipd", "config.json")) ?? {};
|
|
53
|
+
}
|
|
54
|
+
function resolveRuntimeConfig(flags) {
|
|
55
|
+
const cwd = process.cwd();
|
|
56
|
+
const projectRoot = findProjectRoot(cwd);
|
|
57
|
+
const projectConfig = loadProjectConfig(projectRoot, flags.config);
|
|
58
|
+
const globalConfig = loadGlobalConfig();
|
|
59
|
+
const credentials = loadCredentials();
|
|
60
|
+
const ci = flags.ci === true || flags.yes === true || process.env.CI === "1" || process.env.CI === "true" || process.env.SHIPD_CI === "1";
|
|
61
|
+
const defaultConfigFile = fs.existsSync(path.join(projectRoot, "shipd.config.ts")) ? path.join(projectRoot, "shipd.config.ts") : path.join(cwd, "shipd.config.ts");
|
|
62
|
+
return {
|
|
63
|
+
apiUrl: flags.apiUrl ?? process.env.SHIPD_API_URL ?? projectConfig.apiUrl ?? globalConfig.apiUrl ?? credentials.apiUrl ?? "http://localhost:8000",
|
|
64
|
+
appUrl: process.env.SHIPD_APP_URL ?? projectConfig.appUrl ?? globalConfig.appUrl ?? "http://localhost:5173",
|
|
65
|
+
apiKey: process.env.SHIPD_API_KEY ?? credentials.apiKey,
|
|
66
|
+
org: flags.org ?? process.env.SHIPD_ORG ?? projectConfig.org ?? globalConfig.org,
|
|
67
|
+
project: flags.project ?? process.env.SHIPD_PROJECT ?? projectConfig.project ?? globalConfig.project,
|
|
68
|
+
env: flags.env ?? process.env.SHIPD_ENV ?? projectConfig.env ?? globalConfig.env,
|
|
69
|
+
configFile: flags.flagsConfig ? path.resolve(flags.flagsConfig) : projectConfig.configFile ?? defaultConfigFile,
|
|
70
|
+
typesOut: projectConfig.typesOut ?? "src/generated/flags.ts",
|
|
71
|
+
yes: ci,
|
|
72
|
+
json: flags.json === true,
|
|
73
|
+
cwd,
|
|
74
|
+
globalDir: globalConfigDir(),
|
|
75
|
+
projectDir: projectRoot
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/utils/cookie.js
|
|
81
|
+
var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
|
|
82
|
+
var _serialize = (name, value, opt = {}) => {
|
|
83
|
+
if (!validCookieNameRegEx.test(name)) throw new Error("Invalid cookie name");
|
|
84
|
+
let cookie = `${name}=${value}`;
|
|
85
|
+
if (name.startsWith("__Secure-") && !opt.secure) throw new Error("__Secure- Cookie must have Secure attributes");
|
|
86
|
+
if (name.startsWith("__Host-")) {
|
|
87
|
+
if (!opt.secure) throw new Error("__Host- Cookie must have Secure attributes");
|
|
88
|
+
if (opt.path !== "/") throw new Error("__Host- Cookie must have Path attributes with \"/\"");
|
|
89
|
+
if (opt.domain) throw new Error("__Host- Cookie must not have Domain attributes");
|
|
90
|
+
}
|
|
91
|
+
for (const key of [
|
|
92
|
+
"domain",
|
|
93
|
+
"path",
|
|
94
|
+
"sameSite",
|
|
95
|
+
"priority"
|
|
96
|
+
]) if (opt[key] && /[;\r\n]/.test(opt[key])) throw new Error(`${key} must not contain ";", "\\r", or "\\n"`);
|
|
97
|
+
if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
|
|
98
|
+
if (opt.maxAge > 3456e4) throw new Error("Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.");
|
|
99
|
+
cookie += `; Max-Age=${opt.maxAge | 0}`;
|
|
100
|
+
}
|
|
101
|
+
if (opt.domain && opt.prefix !== "host") cookie += `; Domain=${opt.domain}`;
|
|
102
|
+
if (opt.path) cookie += `; Path=${opt.path}`;
|
|
103
|
+
if (opt.expires) {
|
|
104
|
+
if (opt.expires.getTime() - Date.now() > 3456e7) throw new Error("Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.");
|
|
105
|
+
cookie += `; Expires=${opt.expires.toUTCString()}`;
|
|
106
|
+
}
|
|
107
|
+
if (opt.httpOnly) cookie += "; HttpOnly";
|
|
108
|
+
if (opt.secure) cookie += "; Secure";
|
|
109
|
+
if (opt.sameSite) cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
|
|
110
|
+
if (opt.priority) cookie += `; Priority=${opt.priority.charAt(0).toUpperCase() + opt.priority.slice(1)}`;
|
|
111
|
+
if (opt.partitioned) {
|
|
112
|
+
if (!opt.secure) throw new Error("Partitioned Cookie must have Secure attributes");
|
|
113
|
+
cookie += "; Partitioned";
|
|
114
|
+
}
|
|
115
|
+
return cookie;
|
|
116
|
+
};
|
|
117
|
+
var serialize = (name, value, opt) => {
|
|
118
|
+
value = encodeURIComponent(value);
|
|
119
|
+
return _serialize(name, value, opt);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/client/utils.js
|
|
124
|
+
var mergePath = (base, path) => {
|
|
125
|
+
base = base.replace(/\/+$/, "");
|
|
126
|
+
base = base + "/";
|
|
127
|
+
path = path.replace(/^\/+/, "");
|
|
128
|
+
return base + path;
|
|
129
|
+
};
|
|
130
|
+
var replaceUrlParam = (urlString, params) => {
|
|
131
|
+
for (const [k, v] of Object.entries(params)) {
|
|
132
|
+
const reg = new RegExp("/:" + k + "(?:{[^/]+})?\\??(?=/|$)");
|
|
133
|
+
urlString = urlString.replace(reg, v ? `/${v}` : "");
|
|
134
|
+
}
|
|
135
|
+
return urlString;
|
|
136
|
+
};
|
|
137
|
+
var buildSearchParams = (query) => {
|
|
138
|
+
const searchParams = new URLSearchParams();
|
|
139
|
+
for (const [k, v] of Object.entries(query)) {
|
|
140
|
+
if (v === void 0) continue;
|
|
141
|
+
if (Array.isArray(v)) for (const v2 of v) searchParams.append(k, v2);
|
|
142
|
+
else searchParams.set(k, v);
|
|
143
|
+
}
|
|
144
|
+
return searchParams;
|
|
145
|
+
};
|
|
146
|
+
var replaceUrlProtocol = (urlString, protocol) => {
|
|
147
|
+
switch (protocol) {
|
|
148
|
+
case "ws": return urlString.replace(/^http/, "ws");
|
|
149
|
+
case "http": return urlString.replace(/^ws/, "http");
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
var removeIndexString = (urlString) => {
|
|
153
|
+
if (/^https?:\/\/[^\/]+?\/index(?=\?|$)/.test(urlString)) return urlString.replace(/\/index(?=\?|$)/, "/");
|
|
154
|
+
return urlString.replace(/\/index(?=\?|$)/, "");
|
|
155
|
+
};
|
|
156
|
+
function isObject(item) {
|
|
157
|
+
return typeof item === "object" && item !== null && !Array.isArray(item);
|
|
158
|
+
}
|
|
159
|
+
function deepMerge(target, source) {
|
|
160
|
+
if (!isObject(target) && !isObject(source)) return source;
|
|
161
|
+
const merged = { ...target };
|
|
162
|
+
for (const key in source) {
|
|
163
|
+
const value = source[key];
|
|
164
|
+
if (isObject(merged[key]) && isObject(value)) merged[key] = deepMerge(merged[key], value);
|
|
165
|
+
else merged[key] = value;
|
|
166
|
+
}
|
|
167
|
+
return merged;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/client/client.js
|
|
172
|
+
var createProxy = (callback, path) => {
|
|
173
|
+
return new Proxy(() => {}, {
|
|
174
|
+
get(_obj, key) {
|
|
175
|
+
if (typeof key !== "string" || key === "then") return;
|
|
176
|
+
return createProxy(callback, [...path, key]);
|
|
177
|
+
},
|
|
178
|
+
apply(_1, _2, args) {
|
|
179
|
+
return callback({
|
|
180
|
+
path,
|
|
181
|
+
args
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
var ClientRequestImpl = class {
|
|
187
|
+
url;
|
|
188
|
+
method;
|
|
189
|
+
buildSearchParams;
|
|
190
|
+
queryParams = void 0;
|
|
191
|
+
pathParams = {};
|
|
192
|
+
rBody;
|
|
193
|
+
cType = void 0;
|
|
194
|
+
constructor(url, method, options) {
|
|
195
|
+
this.url = url;
|
|
196
|
+
this.method = method;
|
|
197
|
+
this.buildSearchParams = options.buildSearchParams;
|
|
198
|
+
}
|
|
199
|
+
fetch = async (args, opt) => {
|
|
200
|
+
if (args) {
|
|
201
|
+
if (args.query) this.queryParams = this.buildSearchParams(args.query);
|
|
202
|
+
if (args.form) {
|
|
203
|
+
const form = new FormData();
|
|
204
|
+
for (const [k, v] of Object.entries(args.form)) {
|
|
205
|
+
if (v === void 0) continue;
|
|
206
|
+
if (Array.isArray(v)) for (const v2 of v) form.append(k, v2);
|
|
207
|
+
else form.append(k, v);
|
|
208
|
+
}
|
|
209
|
+
this.rBody = form;
|
|
210
|
+
}
|
|
211
|
+
if (args.json) {
|
|
212
|
+
this.rBody = JSON.stringify(args.json);
|
|
213
|
+
this.cType = "application/json";
|
|
214
|
+
}
|
|
215
|
+
if (args.param) this.pathParams = args.param;
|
|
216
|
+
}
|
|
217
|
+
let methodUpperCase = this.method.toUpperCase();
|
|
218
|
+
const headerValues = {
|
|
219
|
+
...args?.header,
|
|
220
|
+
...typeof opt?.headers === "function" ? await opt.headers() : opt?.headers
|
|
221
|
+
};
|
|
222
|
+
if (args?.cookie) {
|
|
223
|
+
const cookies = [];
|
|
224
|
+
for (const [key, value] of Object.entries(args.cookie)) cookies.push(serialize(key, value, { path: "/" }));
|
|
225
|
+
headerValues["Cookie"] = cookies.join(",");
|
|
226
|
+
}
|
|
227
|
+
if (this.cType) headerValues["Content-Type"] = this.cType;
|
|
228
|
+
const headers = new Headers(headerValues ?? void 0);
|
|
229
|
+
let url = this.url;
|
|
230
|
+
url = removeIndexString(url);
|
|
231
|
+
url = replaceUrlParam(url, this.pathParams);
|
|
232
|
+
if (this.queryParams) url = url + "?" + this.queryParams.toString();
|
|
233
|
+
methodUpperCase = this.method.toUpperCase();
|
|
234
|
+
const setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD");
|
|
235
|
+
return (opt?.fetch || fetch)(url, {
|
|
236
|
+
body: setBody ? this.rBody : void 0,
|
|
237
|
+
method: methodUpperCase,
|
|
238
|
+
headers,
|
|
239
|
+
...opt?.init
|
|
240
|
+
});
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
var hc = (baseUrl, options) => createProxy(function proxyCallback(opts) {
|
|
244
|
+
const buildSearchParamsOption = options?.buildSearchParams ?? buildSearchParams;
|
|
245
|
+
const parts = [...opts.path];
|
|
246
|
+
const lastParts = parts.slice(-3).reverse();
|
|
247
|
+
if (lastParts[0] === "toString") {
|
|
248
|
+
if (lastParts[1] === "name") return lastParts[2] || "";
|
|
249
|
+
return proxyCallback.toString();
|
|
250
|
+
}
|
|
251
|
+
if (lastParts[0] === "valueOf") {
|
|
252
|
+
if (lastParts[1] === "name") return lastParts[2] || "";
|
|
253
|
+
return proxyCallback;
|
|
254
|
+
}
|
|
255
|
+
let method = "";
|
|
256
|
+
if (/^\$/.test(lastParts[0])) {
|
|
257
|
+
const last = parts.pop();
|
|
258
|
+
if (last) method = last.replace(/^\$/, "");
|
|
259
|
+
}
|
|
260
|
+
const path = parts.join("/");
|
|
261
|
+
const url = mergePath(baseUrl, path);
|
|
262
|
+
if (method === "url" || method === "path") {
|
|
263
|
+
let result = url;
|
|
264
|
+
if (opts.args[0]) {
|
|
265
|
+
if (opts.args[0].param) result = replaceUrlParam(url, opts.args[0].param);
|
|
266
|
+
if (opts.args[0].query) result = result + "?" + buildSearchParamsOption(opts.args[0].query).toString();
|
|
267
|
+
}
|
|
268
|
+
result = removeIndexString(result);
|
|
269
|
+
if (method === "url") return new URL(result);
|
|
270
|
+
return result.slice(baseUrl.replace(/\/+$/, "").length).replace(/^\/?/, "/");
|
|
271
|
+
}
|
|
272
|
+
if (method === "ws") {
|
|
273
|
+
const webSocketUrl = replaceUrlProtocol(opts.args[0] && opts.args[0].param ? replaceUrlParam(url, opts.args[0].param) : url, "ws");
|
|
274
|
+
const targetUrl = new URL(webSocketUrl);
|
|
275
|
+
const queryParams = opts.args[0]?.query;
|
|
276
|
+
if (queryParams) Object.entries(queryParams).forEach(([key, value]) => {
|
|
277
|
+
if (Array.isArray(value)) value.forEach((item) => targetUrl.searchParams.append(key, item));
|
|
278
|
+
else targetUrl.searchParams.set(key, value);
|
|
279
|
+
});
|
|
280
|
+
const establishWebSocket = (...args) => {
|
|
281
|
+
if (options?.webSocket !== void 0 && typeof options.webSocket === "function") return options.webSocket(...args);
|
|
282
|
+
return new WebSocket(...args);
|
|
283
|
+
};
|
|
284
|
+
return establishWebSocket(targetUrl.toString());
|
|
285
|
+
}
|
|
286
|
+
const req = new ClientRequestImpl(url, method, { buildSearchParams: buildSearchParamsOption });
|
|
287
|
+
if (method) {
|
|
288
|
+
options ??= {};
|
|
289
|
+
const reqOptions = { ...opts.args[1] };
|
|
290
|
+
const baseHeaders = options.headers;
|
|
291
|
+
const reqHeaders = reqOptions.headers;
|
|
292
|
+
if (baseHeaders && reqHeaders) reqOptions.headers = async () => ({
|
|
293
|
+
...typeof baseHeaders === "function" ? await baseHeaders() : baseHeaders,
|
|
294
|
+
...typeof reqHeaders === "function" ? await reqHeaders() : reqHeaders
|
|
295
|
+
});
|
|
296
|
+
const args = deepMerge(options, reqOptions);
|
|
297
|
+
return req.fetch(opts.args[0], args);
|
|
298
|
+
}
|
|
299
|
+
return req;
|
|
300
|
+
}, []);
|
|
301
|
+
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region ../api-client/dist/index.mjs
|
|
304
|
+
const t$2 = [
|
|
305
|
+
`unauthenticated`,
|
|
306
|
+
`forbidden`,
|
|
307
|
+
`not_found`,
|
|
308
|
+
`conflict`,
|
|
309
|
+
`validation_error`,
|
|
310
|
+
`internal`
|
|
311
|
+
];
|
|
312
|
+
function n$2(e) {
|
|
313
|
+
if (typeof e != `object` || !e || !(`error` in e)) return !1;
|
|
314
|
+
let t = e.error;
|
|
315
|
+
if (typeof t != `object` || !t) return !1;
|
|
316
|
+
let n = t;
|
|
317
|
+
return typeof n.code == `string` && typeof n.message == `string` && typeof n.requestId == `string`;
|
|
318
|
+
}
|
|
319
|
+
var r$1 = class e extends Error {
|
|
320
|
+
code;
|
|
321
|
+
status;
|
|
322
|
+
requestId;
|
|
323
|
+
details;
|
|
324
|
+
constructor(e) {
|
|
325
|
+
super(e.message), this.name = `ShipdApiError`, this.code = e.code, this.status = e.status, this.requestId = e.requestId, this.details = e.details;
|
|
326
|
+
}
|
|
327
|
+
static fromResponse(r, i) {
|
|
328
|
+
return n$2(i) ? new e({
|
|
329
|
+
code: t$2.includes(i.error.code) ? i.error.code : `unknown`,
|
|
330
|
+
message: i.error.message,
|
|
331
|
+
status: r,
|
|
332
|
+
requestId: i.error.requestId,
|
|
333
|
+
details: i.error.details
|
|
334
|
+
}) : new e({
|
|
335
|
+
code: `unknown`,
|
|
336
|
+
message: `Request failed with status ${r}`,
|
|
337
|
+
status: r,
|
|
338
|
+
requestId: `unknown`,
|
|
339
|
+
details: i
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
async function i$1(e) {
|
|
344
|
+
let t;
|
|
345
|
+
try {
|
|
346
|
+
t = await e.json();
|
|
347
|
+
} catch {
|
|
348
|
+
throw new r$1({
|
|
349
|
+
code: `internal`,
|
|
350
|
+
message: `Invalid JSON response`,
|
|
351
|
+
status: e.status,
|
|
352
|
+
requestId: `unknown`
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (!e.ok) throw r$1.fromResponse(e.status, t);
|
|
356
|
+
if (typeof t != `object` || !t || !(`data` in t)) throw new r$1({
|
|
357
|
+
code: `internal`,
|
|
358
|
+
message: `Malformed success response`,
|
|
359
|
+
status: e.status,
|
|
360
|
+
requestId: `unknown`,
|
|
361
|
+
details: t
|
|
362
|
+
});
|
|
363
|
+
return t.data;
|
|
364
|
+
}
|
|
365
|
+
const a$1 = (...t) => hc(...t);
|
|
366
|
+
const o$1 = (...t) => hc(...t);
|
|
367
|
+
const s$1 = (...t) => hc(...t);
|
|
368
|
+
const c$2 = (...t) => hc(...t);
|
|
369
|
+
const l$2 = (...t) => hc(...t);
|
|
370
|
+
const u$1 = (...t) => hc(...t);
|
|
371
|
+
const d$1 = (...t) => hc(...t);
|
|
372
|
+
const f$1 = (...t) => hc(...t);
|
|
373
|
+
const p$1 = (...t) => hc(...t);
|
|
374
|
+
function m$1(e) {
|
|
375
|
+
return `${e.replace(/\/+$/, ``)}/api/v1/rpc`;
|
|
376
|
+
}
|
|
377
|
+
function h$1(e) {
|
|
378
|
+
return {
|
|
379
|
+
...e.fetch ? { fetch: e.fetch } : {},
|
|
380
|
+
init: { credentials: e.client === `dashboard` ? `include` : `same-origin` },
|
|
381
|
+
headers: async () => {
|
|
382
|
+
let t = new Headers(await e.getHeaders?.());
|
|
383
|
+
return t.set(`x-shipd-client`, e.client), Object.fromEntries(t.entries());
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
async function g$1(e, t) {
|
|
388
|
+
return i$1(await e({ json: t }));
|
|
389
|
+
}
|
|
390
|
+
function _$1(e) {
|
|
391
|
+
let t = m$1(e.baseUrl), n = h$1(e), r = a$1(t, n), i = o$1(t, n), _ = s$1(t, n), v = c$2(t, n), y = l$2(t, n), b = u$1(t, n), x = d$1(t, n), S = f$1(t, n), C = p$1(t, n);
|
|
392
|
+
return {
|
|
393
|
+
me: { get: (e = {}) => g$1(r.me.$post, e) },
|
|
394
|
+
project: {
|
|
395
|
+
list: (e = {}) => g$1(i.project.list.$post, e),
|
|
396
|
+
create: (e) => g$1(i.project.create.$post, e),
|
|
397
|
+
update: (e) => g$1(i.project.update.$post, e),
|
|
398
|
+
archive: (e) => g$1(i.project.archive.$post, e)
|
|
399
|
+
},
|
|
400
|
+
environment: {
|
|
401
|
+
list: (e) => g$1(_.environment.list.$post, e),
|
|
402
|
+
create: (e) => g$1(_.environment.create.$post, e),
|
|
403
|
+
update: (e) => g$1(_.environment.update.$post, e),
|
|
404
|
+
archive: (e) => g$1(_.environment.archive.$post, e)
|
|
405
|
+
},
|
|
406
|
+
flag: {
|
|
407
|
+
list: (e) => g$1(v.flag.list.$post, e),
|
|
408
|
+
get: (e) => g$1(v.flag.get.$post, e),
|
|
409
|
+
create: (e) => g$1(v.flag.create.$post, e),
|
|
410
|
+
update: (e) => g$1(v.flag.update.$post, e),
|
|
411
|
+
archive: (e) => g$1(v.flag.archive.$post, e),
|
|
412
|
+
updateEnvironment: (e) => g$1(v.flag.updateEnvironment.$post, e),
|
|
413
|
+
toggleEnvironment: (e) => g$1(v.flag.toggleEnvironment.$post, e),
|
|
414
|
+
pull: (e) => g$1(v.flag.pull.$post, e),
|
|
415
|
+
diff: (e) => g$1(v.flag.diff.$post, e),
|
|
416
|
+
push: (e) => g$1(v.flag.push.$post, e)
|
|
417
|
+
},
|
|
418
|
+
apiKey: {
|
|
419
|
+
list: (e = {}) => g$1(y.apiKey.list.$post, e),
|
|
420
|
+
create: (e) => g$1(y.apiKey.create.$post, e),
|
|
421
|
+
revoke: (e) => g$1(y.apiKey.revoke.$post, e)
|
|
422
|
+
},
|
|
423
|
+
sdkKey: {
|
|
424
|
+
list: (e = {}) => g$1(b.sdkKey.list.$post, e),
|
|
425
|
+
create: (e) => g$1(b.sdkKey.create.$post, e),
|
|
426
|
+
revoke: (e) => g$1(b.sdkKey.revoke.$post, e)
|
|
427
|
+
},
|
|
428
|
+
evaluatedEntity: {
|
|
429
|
+
list: (e) => g$1(x.evaluatedEntity.list.$post, e),
|
|
430
|
+
get: (e) => g$1(x.evaluatedEntity.get.$post, e),
|
|
431
|
+
delete: (e) => g$1(x.evaluatedEntity.delete.$post, e)
|
|
432
|
+
},
|
|
433
|
+
snapshot: { publish: (e) => g$1(S.snapshot.publish.$post, e) },
|
|
434
|
+
device: { authorize: (e) => g$1(C.device.authorize.$post, e) },
|
|
435
|
+
raw: {
|
|
436
|
+
me: r,
|
|
437
|
+
project: i,
|
|
438
|
+
environment: _,
|
|
439
|
+
flag: v,
|
|
440
|
+
apiKey: y,
|
|
441
|
+
sdkKey: b,
|
|
442
|
+
evaluatedEntity: x,
|
|
443
|
+
snapshot: S,
|
|
444
|
+
device: C
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
//#endregion
|
|
450
|
+
//#region ../../node_modules/.pnpm/@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fetch+fetch@1.3.1_@openteleme_39d811f210df3a5f20302036ab91db01/node_modules/@better-auth/core/dist/utils/error-codes.mjs
|
|
451
|
+
function defineErrorCodes(codes) {
|
|
452
|
+
return Object.fromEntries(Object.entries(codes).map(([key, value]) => [key, {
|
|
453
|
+
code: key,
|
|
454
|
+
message: value,
|
|
455
|
+
toString: () => key
|
|
456
|
+
}]));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region ../../node_modules/.pnpm/better-call@1.3.7_zod@4.4.3/node_modules/better-call/dist/error.mjs
|
|
461
|
+
function isErrorStackTraceLimitWritable() {
|
|
462
|
+
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
463
|
+
if (desc === void 0) return Object.isExtensible(Error);
|
|
464
|
+
return Object.prototype.hasOwnProperty.call(desc, "writable") ? desc.writable : desc.set !== void 0;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Hide internal stack frames from the error stack trace.
|
|
468
|
+
*/
|
|
469
|
+
function hideInternalStackFrames(stack) {
|
|
470
|
+
const lines = stack.split("\n at ");
|
|
471
|
+
if (lines.length <= 1) return stack;
|
|
472
|
+
lines.splice(1, 1);
|
|
473
|
+
return lines.join("\n at ");
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Creates a custom error class that hides stack frames.
|
|
477
|
+
*/
|
|
478
|
+
function makeErrorForHideStackFrame(Base, clazz) {
|
|
479
|
+
class HideStackFramesError extends Base {
|
|
480
|
+
#hiddenStack;
|
|
481
|
+
constructor(...args) {
|
|
482
|
+
if (isErrorStackTraceLimitWritable()) {
|
|
483
|
+
const limit = Error.stackTraceLimit;
|
|
484
|
+
Error.stackTraceLimit = 0;
|
|
485
|
+
super(...args);
|
|
486
|
+
Error.stackTraceLimit = limit;
|
|
487
|
+
} else super(...args);
|
|
488
|
+
const stack = (/* @__PURE__ */ new Error()).stack;
|
|
489
|
+
if (stack) this.#hiddenStack = hideInternalStackFrames(stack.replace(/^Error/, this.name));
|
|
490
|
+
}
|
|
491
|
+
get errorStack() {
|
|
492
|
+
return this.#hiddenStack;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
Object.defineProperty(HideStackFramesError.prototype, "constructor", {
|
|
496
|
+
get() {
|
|
497
|
+
return clazz;
|
|
498
|
+
},
|
|
499
|
+
enumerable: false,
|
|
500
|
+
configurable: true
|
|
501
|
+
});
|
|
502
|
+
return HideStackFramesError;
|
|
503
|
+
}
|
|
504
|
+
const statusCodes = {
|
|
505
|
+
OK: 200,
|
|
506
|
+
CREATED: 201,
|
|
507
|
+
ACCEPTED: 202,
|
|
508
|
+
NO_CONTENT: 204,
|
|
509
|
+
MULTIPLE_CHOICES: 300,
|
|
510
|
+
MOVED_PERMANENTLY: 301,
|
|
511
|
+
FOUND: 302,
|
|
512
|
+
SEE_OTHER: 303,
|
|
513
|
+
NOT_MODIFIED: 304,
|
|
514
|
+
TEMPORARY_REDIRECT: 307,
|
|
515
|
+
BAD_REQUEST: 400,
|
|
516
|
+
UNAUTHORIZED: 401,
|
|
517
|
+
PAYMENT_REQUIRED: 402,
|
|
518
|
+
FORBIDDEN: 403,
|
|
519
|
+
NOT_FOUND: 404,
|
|
520
|
+
METHOD_NOT_ALLOWED: 405,
|
|
521
|
+
NOT_ACCEPTABLE: 406,
|
|
522
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
523
|
+
REQUEST_TIMEOUT: 408,
|
|
524
|
+
CONFLICT: 409,
|
|
525
|
+
GONE: 410,
|
|
526
|
+
LENGTH_REQUIRED: 411,
|
|
527
|
+
PRECONDITION_FAILED: 412,
|
|
528
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
529
|
+
URI_TOO_LONG: 414,
|
|
530
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
531
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
532
|
+
EXPECTATION_FAILED: 417,
|
|
533
|
+
"I'M_A_TEAPOT": 418,
|
|
534
|
+
MISDIRECTED_REQUEST: 421,
|
|
535
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
536
|
+
LOCKED: 423,
|
|
537
|
+
FAILED_DEPENDENCY: 424,
|
|
538
|
+
TOO_EARLY: 425,
|
|
539
|
+
UPGRADE_REQUIRED: 426,
|
|
540
|
+
PRECONDITION_REQUIRED: 428,
|
|
541
|
+
TOO_MANY_REQUESTS: 429,
|
|
542
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
543
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
544
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
545
|
+
NOT_IMPLEMENTED: 501,
|
|
546
|
+
BAD_GATEWAY: 502,
|
|
547
|
+
SERVICE_UNAVAILABLE: 503,
|
|
548
|
+
GATEWAY_TIMEOUT: 504,
|
|
549
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
550
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
551
|
+
INSUFFICIENT_STORAGE: 507,
|
|
552
|
+
LOOP_DETECTED: 508,
|
|
553
|
+
NOT_EXTENDED: 510,
|
|
554
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
555
|
+
};
|
|
556
|
+
var InternalAPIError = class extends Error {
|
|
557
|
+
constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = typeof status === "number" ? status : statusCodes[status]) {
|
|
558
|
+
super(body?.message, body?.cause ? { cause: body.cause } : void 0);
|
|
559
|
+
this.status = status;
|
|
560
|
+
this.body = body;
|
|
561
|
+
this.headers = headers;
|
|
562
|
+
this.statusCode = statusCode;
|
|
563
|
+
this.name = "APIError";
|
|
564
|
+
this.status = status;
|
|
565
|
+
this.headers = headers;
|
|
566
|
+
this.statusCode = statusCode;
|
|
567
|
+
this.body = body;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);
|
|
571
|
+
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region ../../node_modules/.pnpm/@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fetch+fetch@1.3.1_@openteleme_39d811f210df3a5f20302036ab91db01/node_modules/@better-auth/core/dist/error/index.mjs
|
|
574
|
+
var BetterAuthError = class extends Error {
|
|
575
|
+
constructor(message, options) {
|
|
576
|
+
super(message, options);
|
|
577
|
+
this.name = "BetterAuthError";
|
|
578
|
+
this.message = message;
|
|
579
|
+
this.stack = "";
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
//#endregion
|
|
584
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/access/access.mjs
|
|
585
|
+
function unknownResourceResponse(requestedResource) {
|
|
586
|
+
return {
|
|
587
|
+
success: false,
|
|
588
|
+
error: `You are not allowed to access resource: ${requestedResource}`
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
function unauthorizedResourceResponse(requestedResource) {
|
|
592
|
+
return {
|
|
593
|
+
success: false,
|
|
594
|
+
error: `unauthorized to access resource "${requestedResource}"`
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function normalizeConnector(connector) {
|
|
598
|
+
return connector === "OR" ? "OR" : "AND";
|
|
599
|
+
}
|
|
600
|
+
function isActionList(actions) {
|
|
601
|
+
return Array.isArray(actions);
|
|
602
|
+
}
|
|
603
|
+
function normalizeActionRequest(requestedActions) {
|
|
604
|
+
if (isActionList(requestedActions)) return {
|
|
605
|
+
actions: requestedActions,
|
|
606
|
+
connector: "AND"
|
|
607
|
+
};
|
|
608
|
+
if (!requestedActions || typeof requestedActions !== "object") throw new BetterAuthError("Invalid access control request");
|
|
609
|
+
const { actions, connector } = requestedActions;
|
|
610
|
+
if (!isActionList(actions)) return {
|
|
611
|
+
actions: [],
|
|
612
|
+
connector: normalizeConnector(connector)
|
|
613
|
+
};
|
|
614
|
+
return {
|
|
615
|
+
actions,
|
|
616
|
+
connector: normalizeConnector(connector)
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
function hasAllowedAction(allowedActions, requestedAction) {
|
|
620
|
+
return typeof requestedAction === "string" && allowedActions.includes(requestedAction);
|
|
621
|
+
}
|
|
622
|
+
function isResourceAuthorized(allowedActions, { actions, connector }) {
|
|
623
|
+
if (actions.length === 0) return false;
|
|
624
|
+
if (connector === "OR") return actions.some((requestedAction) => hasAllowedAction(allowedActions, requestedAction));
|
|
625
|
+
return actions.every((requestedAction) => hasAllowedAction(allowedActions, requestedAction));
|
|
626
|
+
}
|
|
627
|
+
function role(statements) {
|
|
628
|
+
return {
|
|
629
|
+
authorize(request, connector = "AND") {
|
|
630
|
+
let hasAuthorizedResource = false;
|
|
631
|
+
for (const [requestedResource, requestedActions] of Object.entries(request)) {
|
|
632
|
+
const allowedActions = statements[requestedResource];
|
|
633
|
+
if (!allowedActions) {
|
|
634
|
+
if (connector === "AND") return unknownResourceResponse(requestedResource);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const isAuthorized = isResourceAuthorized(allowedActions, normalizeActionRequest(requestedActions));
|
|
638
|
+
if (isAuthorized) hasAuthorizedResource = true;
|
|
639
|
+
if (isAuthorized && connector === "OR") return { success: true };
|
|
640
|
+
if (!isAuthorized && connector === "AND") return unauthorizedResourceResponse(requestedResource);
|
|
641
|
+
}
|
|
642
|
+
if (hasAuthorizedResource) return { success: true };
|
|
643
|
+
return {
|
|
644
|
+
success: false,
|
|
645
|
+
error: "Not authorized"
|
|
646
|
+
};
|
|
647
|
+
},
|
|
648
|
+
statements
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function createAccessControl(s) {
|
|
652
|
+
return {
|
|
653
|
+
newRole(statements) {
|
|
654
|
+
return role(statements);
|
|
655
|
+
},
|
|
656
|
+
statements: s
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/package.mjs
|
|
662
|
+
var version = "1.6.26";
|
|
663
|
+
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/version.mjs
|
|
666
|
+
const PACKAGE_VERSION$1 = version;
|
|
667
|
+
|
|
668
|
+
//#endregion
|
|
669
|
+
//#region ../../node_modules/.pnpm/@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fetch+fetch@1.3.1_@openteleme_39d811f210df3a5f20302036ab91db01/node_modules/@better-auth/core/dist/utils/url.mjs
|
|
670
|
+
/**
|
|
671
|
+
* Schemes that execute or embed code when navigated to or accepted as a
|
|
672
|
+
* redirect target. These are never safe as an OAuth `redirect_uri` or as a
|
|
673
|
+
* client-side navigation target (`window.location.href`, `location.assign`, ...).
|
|
674
|
+
*/
|
|
675
|
+
const DANGEROUS_URL_SCHEMES = [
|
|
676
|
+
"javascript:",
|
|
677
|
+
"data:",
|
|
678
|
+
"vbscript:"
|
|
679
|
+
];
|
|
680
|
+
/**
|
|
681
|
+
* Returns `false` only when `value` is an absolute URL using a dangerous scheme
|
|
682
|
+
* (`javascript:`, `data:`, `vbscript:`). Relative URLs (e.g. `/dashboard`) and
|
|
683
|
+
* safe absolute schemes (`http`, `https`, custom app schemes such as
|
|
684
|
+
* `myapp://`) return `true`.
|
|
685
|
+
*
|
|
686
|
+
* Use this to guard browser navigation sinks and any redirect target that may
|
|
687
|
+
* originate from untrusted input. It is intentionally narrow: it blocks code
|
|
688
|
+
* execution schemes without rejecting relative paths or mobile deep links.
|
|
689
|
+
*/
|
|
690
|
+
function isSafeUrlScheme(value) {
|
|
691
|
+
let parsed;
|
|
692
|
+
try {
|
|
693
|
+
parsed = new URL(value);
|
|
694
|
+
} catch {
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
return !DANGEROUS_URL_SCHEMES.includes(parsed.protocol);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
//#endregion
|
|
701
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/admin/access/statement.mjs
|
|
702
|
+
const defaultStatements$1 = {
|
|
703
|
+
user: [
|
|
704
|
+
"create",
|
|
705
|
+
"list",
|
|
706
|
+
"set-role",
|
|
707
|
+
"ban",
|
|
708
|
+
"impersonate",
|
|
709
|
+
"impersonate-admins",
|
|
710
|
+
"delete",
|
|
711
|
+
"set-password",
|
|
712
|
+
"set-email",
|
|
713
|
+
"get",
|
|
714
|
+
"update"
|
|
715
|
+
],
|
|
716
|
+
session: [
|
|
717
|
+
"list",
|
|
718
|
+
"revoke",
|
|
719
|
+
"delete"
|
|
720
|
+
]
|
|
721
|
+
};
|
|
722
|
+
const defaultAc$1 = createAccessControl(defaultStatements$1);
|
|
723
|
+
const adminAc$1 = defaultAc$1.newRole({
|
|
724
|
+
user: [
|
|
725
|
+
"create",
|
|
726
|
+
"list",
|
|
727
|
+
"set-role",
|
|
728
|
+
"ban",
|
|
729
|
+
"impersonate",
|
|
730
|
+
"delete",
|
|
731
|
+
"set-password",
|
|
732
|
+
"set-email",
|
|
733
|
+
"get",
|
|
734
|
+
"update"
|
|
735
|
+
],
|
|
736
|
+
session: [
|
|
737
|
+
"list",
|
|
738
|
+
"revoke",
|
|
739
|
+
"delete"
|
|
740
|
+
]
|
|
741
|
+
});
|
|
742
|
+
const userAc = defaultAc$1.newRole({
|
|
743
|
+
user: [],
|
|
744
|
+
session: []
|
|
745
|
+
});
|
|
746
|
+
const defaultRoles$1 = {
|
|
747
|
+
admin: adminAc$1,
|
|
748
|
+
user: userAc
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
//#endregion
|
|
752
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/admin/error-codes.mjs
|
|
753
|
+
const ADMIN_ERROR_CODES = defineErrorCodes({
|
|
754
|
+
FAILED_TO_CREATE_USER: "Failed to create user",
|
|
755
|
+
USER_ALREADY_EXISTS: "User already exists.",
|
|
756
|
+
USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: "User already exists. Use another email.",
|
|
757
|
+
YOU_CANNOT_BAN_YOURSELF: "You cannot ban yourself",
|
|
758
|
+
YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE: "You are not allowed to change users role",
|
|
759
|
+
YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS: "You are not allowed to create users",
|
|
760
|
+
YOU_ARE_NOT_ALLOWED_TO_LIST_USERS: "You are not allowed to list users",
|
|
761
|
+
YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS: "You are not allowed to list users sessions",
|
|
762
|
+
YOU_ARE_NOT_ALLOWED_TO_BAN_USERS: "You are not allowed to ban users",
|
|
763
|
+
YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS: "You are not allowed to impersonate users",
|
|
764
|
+
YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS: "You are not allowed to revoke users sessions",
|
|
765
|
+
YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS: "You are not allowed to delete users",
|
|
766
|
+
YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD: "You are not allowed to set users password",
|
|
767
|
+
BANNED_USER: "You have been banned from this application",
|
|
768
|
+
YOU_ARE_NOT_ALLOWED_TO_GET_USER: "You are not allowed to get user",
|
|
769
|
+
NO_DATA_TO_UPDATE: "No data to update",
|
|
770
|
+
YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS: "You are not allowed to update users",
|
|
771
|
+
YOU_CANNOT_REMOVE_YOURSELF: "You cannot remove yourself",
|
|
772
|
+
YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE: "You are not allowed to set a non-existent role value",
|
|
773
|
+
YOU_CANNOT_IMPERSONATE_ADMINS: "You cannot impersonate admins",
|
|
774
|
+
INVALID_ROLE_TYPE: "Invalid role type",
|
|
775
|
+
YOU_ARE_NOT_ALLOWED_TO_SET_USERS_EMAIL: "You are not allowed to update users email",
|
|
776
|
+
PASSWORD_CANNOT_BE_UPDATED_VIA_UPDATE_USER: "Password cannot be updated through update-user. Use the set-user-password endpoint instead"
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
//#endregion
|
|
780
|
+
//#region ../../node_modules/.pnpm/@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fetch+fetch@1.3.1_@openteleme_39d811f210df3a5f20302036ab91db01/node_modules/@better-auth/core/dist/env/env-impl.mjs
|
|
781
|
+
const _envShim = Object.create(null);
|
|
782
|
+
const _getEnv = (useShim) => globalThis.process?.env || globalThis.Deno?.env.toObject() || globalThis.__env__ || (useShim ? _envShim : globalThis);
|
|
783
|
+
const env = new Proxy(_envShim, {
|
|
784
|
+
get(_, prop) {
|
|
785
|
+
return _getEnv()[prop] ?? _envShim[prop];
|
|
786
|
+
},
|
|
787
|
+
has(_, prop) {
|
|
788
|
+
return prop in _getEnv() || prop in _envShim;
|
|
789
|
+
},
|
|
790
|
+
set(_, prop, value) {
|
|
791
|
+
const env = _getEnv(true);
|
|
792
|
+
env[prop] = value;
|
|
793
|
+
return true;
|
|
794
|
+
},
|
|
795
|
+
deleteProperty(_, prop) {
|
|
796
|
+
if (!prop) return false;
|
|
797
|
+
const env = _getEnv(true);
|
|
798
|
+
delete env[prop];
|
|
799
|
+
return true;
|
|
800
|
+
},
|
|
801
|
+
ownKeys() {
|
|
802
|
+
const env = _getEnv(true);
|
|
803
|
+
return Object.keys(env);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
const nodeENV = env.NODE_ENV ?? "";
|
|
807
|
+
/**
|
|
808
|
+
* Get environment variable with fallback
|
|
809
|
+
*/
|
|
810
|
+
function getEnvVar(key, fallback) {
|
|
811
|
+
if (typeof process !== "undefined" && process.env) return process.env[key] ?? fallback;
|
|
812
|
+
if (typeof Deno !== "undefined") return Deno.env.get(key) ?? fallback;
|
|
813
|
+
if (typeof Bun !== "undefined") return Bun.env[key] ?? fallback;
|
|
814
|
+
return fallback;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Common environment variables used in Better Auth
|
|
818
|
+
*/
|
|
819
|
+
const ENV = Object.freeze({
|
|
820
|
+
get BETTER_AUTH_SECRET() {
|
|
821
|
+
return getEnvVar("BETTER_AUTH_SECRET");
|
|
822
|
+
},
|
|
823
|
+
get AUTH_SECRET() {
|
|
824
|
+
return getEnvVar("AUTH_SECRET");
|
|
825
|
+
},
|
|
826
|
+
get BETTER_AUTH_TELEMETRY() {
|
|
827
|
+
return getEnvVar("BETTER_AUTH_TELEMETRY");
|
|
828
|
+
},
|
|
829
|
+
get BETTER_AUTH_TELEMETRY_ID() {
|
|
830
|
+
return getEnvVar("BETTER_AUTH_TELEMETRY_ID");
|
|
831
|
+
},
|
|
832
|
+
get NODE_ENV() {
|
|
833
|
+
return getEnvVar("NODE_ENV", "development");
|
|
834
|
+
},
|
|
835
|
+
get PACKAGE_VERSION() {
|
|
836
|
+
return getEnvVar("PACKAGE_VERSION", "0.0.0");
|
|
837
|
+
},
|
|
838
|
+
get BETTER_AUTH_TELEMETRY_ENDPOINT() {
|
|
839
|
+
return getEnvVar("BETTER_AUTH_TELEMETRY_ENDPOINT", "");
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/utils/url.mjs
|
|
845
|
+
const SLASH_CHAR_CODE = "/".charCodeAt(0);
|
|
846
|
+
function trimTrailingSlashes(value) {
|
|
847
|
+
let end = value.length;
|
|
848
|
+
while (end > 0 && value.charCodeAt(end - 1) === SLASH_CHAR_CODE) end--;
|
|
849
|
+
return end === value.length ? value : value.slice(0, end);
|
|
850
|
+
}
|
|
851
|
+
function checkHasPath(url) {
|
|
852
|
+
try {
|
|
853
|
+
return (trimTrailingSlashes(new URL(url).pathname) || "/") !== "/";
|
|
854
|
+
} catch {
|
|
855
|
+
throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function assertHasProtocol(url) {
|
|
859
|
+
try {
|
|
860
|
+
const parsedUrl = new URL(url);
|
|
861
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new BetterAuthError(`Invalid base URL: ${url}. URL must include 'http://' or 'https://'`);
|
|
862
|
+
} catch (error) {
|
|
863
|
+
if (error instanceof BetterAuthError) throw error;
|
|
864
|
+
throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`, { cause: error });
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
function withPath(url, path = "/api/auth") {
|
|
868
|
+
assertHasProtocol(url);
|
|
869
|
+
if (checkHasPath(url)) return url;
|
|
870
|
+
const trimmedUrl = trimTrailingSlashes(url);
|
|
871
|
+
if (!path || path === "/") return trimmedUrl;
|
|
872
|
+
path = path.startsWith("/") ? path : `/${path}`;
|
|
873
|
+
return `${trimmedUrl}${path}`;
|
|
874
|
+
}
|
|
875
|
+
function validateProxyHeader(header, type) {
|
|
876
|
+
if (!header || header.trim() === "") return false;
|
|
877
|
+
if (type === "proto") return header === "http" || header === "https";
|
|
878
|
+
if (type === "host") {
|
|
879
|
+
if ([
|
|
880
|
+
/\.\./,
|
|
881
|
+
/\0/,
|
|
882
|
+
/[\s]/,
|
|
883
|
+
/^[.]/,
|
|
884
|
+
/[<>'"]/,
|
|
885
|
+
/javascript:/i,
|
|
886
|
+
/file:/i,
|
|
887
|
+
/data:/i
|
|
888
|
+
].some((pattern) => pattern.test(header))) return false;
|
|
889
|
+
return /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*(:[0-9]{1,5})?$/.test(header) || /^(\d{1,3}\.){3}\d{1,3}(:[0-9]{1,5})?$/.test(header) || /^\[[0-9a-fA-F:]+\](:[0-9]{1,5})?$/.test(header) || /^localhost(:[0-9]{1,5})?$/i.test(header);
|
|
890
|
+
}
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
function getBaseURL(url, path, request, loadEnv, trustedProxyHeaders) {
|
|
894
|
+
if (url) return withPath(url, path);
|
|
895
|
+
if (loadEnv !== false) {
|
|
896
|
+
const fromEnv = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL || (env.BASE_URL !== "/" ? env.BASE_URL : void 0);
|
|
897
|
+
if (fromEnv) return withPath(fromEnv, path);
|
|
898
|
+
}
|
|
899
|
+
const fromRequest = request?.headers.get("x-forwarded-host");
|
|
900
|
+
const fromRequestProto = request?.headers.get("x-forwarded-proto");
|
|
901
|
+
if (fromRequest && fromRequestProto && trustedProxyHeaders) {
|
|
902
|
+
if (validateProxyHeader(fromRequestProto, "proto") && validateProxyHeader(fromRequest, "host")) try {
|
|
903
|
+
return withPath(`${fromRequestProto}://${fromRequest}`, path);
|
|
904
|
+
} catch (_error) {}
|
|
905
|
+
}
|
|
906
|
+
if (request) {
|
|
907
|
+
const url = getOrigin(request.url);
|
|
908
|
+
if (!url) throw new BetterAuthError("Could not get origin from request. Please provide a valid base URL.");
|
|
909
|
+
return withPath(url, path);
|
|
910
|
+
}
|
|
911
|
+
if (typeof window !== "undefined" && window.location) return withPath(window.location.origin, path);
|
|
912
|
+
}
|
|
913
|
+
function getOrigin(url) {
|
|
914
|
+
try {
|
|
915
|
+
const parsedUrl = new URL(url);
|
|
916
|
+
return parsedUrl.origin === "null" ? null : parsedUrl.origin;
|
|
917
|
+
} catch {
|
|
918
|
+
return null;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
//#endregion
|
|
923
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/admin/has-permission.mjs
|
|
924
|
+
const hasPermission = (input) => {
|
|
925
|
+
if (input.userId && input.options?.adminUserIds?.includes(input.userId)) return true;
|
|
926
|
+
if (!input.permissions) return false;
|
|
927
|
+
const roles = (input.role || input.options?.defaultRole || "user").split(",");
|
|
928
|
+
const acRoles = input.options?.roles || defaultRoles$1;
|
|
929
|
+
for (const role of roles) if ((acRoles[role]?.authorize(input.permissions))?.success) return true;
|
|
930
|
+
return false;
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
//#endregion
|
|
934
|
+
//#region ../../node_modules/.pnpm/defu@6.1.7/node_modules/defu/dist/defu.mjs
|
|
935
|
+
function isPlainObject$1(value) {
|
|
936
|
+
if (value === null || typeof value !== "object") return false;
|
|
937
|
+
const prototype = Object.getPrototypeOf(value);
|
|
938
|
+
if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) return false;
|
|
939
|
+
if (Symbol.iterator in value) return false;
|
|
940
|
+
if (Symbol.toStringTag in value) return Object.prototype.toString.call(value) === "[object Module]";
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
function _defu(baseObject, defaults, namespace = ".", merger) {
|
|
944
|
+
if (!isPlainObject$1(defaults)) return _defu(baseObject, {}, namespace, merger);
|
|
945
|
+
const object = { ...defaults };
|
|
946
|
+
for (const key of Object.keys(baseObject)) {
|
|
947
|
+
if (key === "__proto__" || key === "constructor") continue;
|
|
948
|
+
const value = baseObject[key];
|
|
949
|
+
if (value === null || value === void 0) continue;
|
|
950
|
+
if (merger && merger(object, key, value, namespace)) continue;
|
|
951
|
+
if (Array.isArray(value) && Array.isArray(object[key])) object[key] = [...value, ...object[key]];
|
|
952
|
+
else if (isPlainObject$1(value) && isPlainObject$1(object[key])) object[key] = _defu(value, object[key], (namespace ? `${namespace}.` : "") + key.toString(), merger);
|
|
953
|
+
else object[key] = value;
|
|
954
|
+
}
|
|
955
|
+
return object;
|
|
956
|
+
}
|
|
957
|
+
function createDefu(merger) {
|
|
958
|
+
return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
|
|
959
|
+
}
|
|
960
|
+
const defu = createDefu();
|
|
961
|
+
const defuFn = createDefu((object, key, currentValue) => {
|
|
962
|
+
if (object[key] !== void 0 && typeof currentValue === "function") {
|
|
963
|
+
object[key] = currentValue(object[key]);
|
|
964
|
+
return true;
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
const defuArrayFn = createDefu((object, key, currentValue) => {
|
|
968
|
+
if (Array.isArray(object[key]) && typeof currentValue === "function") {
|
|
969
|
+
object[key] = currentValue(object[key]);
|
|
970
|
+
return true;
|
|
971
|
+
}
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
//#endregion
|
|
975
|
+
//#region ../../node_modules/.pnpm/@better-fetch+fetch@1.3.1/node_modules/@better-fetch/fetch/dist/index.js
|
|
976
|
+
var __defProp = Object.defineProperty;
|
|
977
|
+
var __defProps = Object.defineProperties;
|
|
978
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
979
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
980
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
981
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
982
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
|
|
983
|
+
enumerable: true,
|
|
984
|
+
configurable: true,
|
|
985
|
+
writable: true,
|
|
986
|
+
value
|
|
987
|
+
}) : obj[key] = value;
|
|
988
|
+
var __spreadValues = (a, b) => {
|
|
989
|
+
for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
|
990
|
+
if (__getOwnPropSymbols) {
|
|
991
|
+
for (var prop of __getOwnPropSymbols(b)) if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
|
992
|
+
}
|
|
993
|
+
return a;
|
|
994
|
+
};
|
|
995
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
996
|
+
var BetterFetchError = class extends Error {
|
|
997
|
+
constructor(status, statusText, error) {
|
|
998
|
+
super(statusText || status.toString(), { cause: error });
|
|
999
|
+
this.status = status;
|
|
1000
|
+
this.statusText = statusText;
|
|
1001
|
+
this.error = error;
|
|
1002
|
+
Error.captureStackTrace(this, this.constructor);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
var initializePlugins = async (url, options) => {
|
|
1006
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1007
|
+
let opts = options || {};
|
|
1008
|
+
const hooks = {
|
|
1009
|
+
onRequest: [options == null ? void 0 : options.onRequest],
|
|
1010
|
+
onResponse: [options == null ? void 0 : options.onResponse],
|
|
1011
|
+
onSuccess: [options == null ? void 0 : options.onSuccess],
|
|
1012
|
+
onError: [options == null ? void 0 : options.onError],
|
|
1013
|
+
onRetry: [options == null ? void 0 : options.onRetry]
|
|
1014
|
+
};
|
|
1015
|
+
if (!options || !(options == null ? void 0 : options.plugins)) return {
|
|
1016
|
+
url,
|
|
1017
|
+
options: opts,
|
|
1018
|
+
hooks
|
|
1019
|
+
};
|
|
1020
|
+
for (const plugin of (options == null ? void 0 : options.plugins) || []) {
|
|
1021
|
+
if (plugin.init) {
|
|
1022
|
+
const pluginRes = await ((_a = plugin.init) == null ? void 0 : _a.call(plugin, url.toString(), options));
|
|
1023
|
+
opts = pluginRes.options || opts;
|
|
1024
|
+
url = pluginRes.url;
|
|
1025
|
+
}
|
|
1026
|
+
hooks.onRequest.push((_b = plugin.hooks) == null ? void 0 : _b.onRequest);
|
|
1027
|
+
hooks.onResponse.push((_c = plugin.hooks) == null ? void 0 : _c.onResponse);
|
|
1028
|
+
hooks.onSuccess.push((_d = plugin.hooks) == null ? void 0 : _d.onSuccess);
|
|
1029
|
+
hooks.onError.push((_e = plugin.hooks) == null ? void 0 : _e.onError);
|
|
1030
|
+
hooks.onRetry.push((_f = plugin.hooks) == null ? void 0 : _f.onRetry);
|
|
1031
|
+
}
|
|
1032
|
+
return {
|
|
1033
|
+
url,
|
|
1034
|
+
options: opts,
|
|
1035
|
+
hooks
|
|
1036
|
+
};
|
|
1037
|
+
};
|
|
1038
|
+
var LinearRetryStrategy = class {
|
|
1039
|
+
constructor(options) {
|
|
1040
|
+
this.options = options;
|
|
1041
|
+
}
|
|
1042
|
+
shouldAttemptRetry(attempt, response) {
|
|
1043
|
+
if (this.options.shouldRetry) return Promise.resolve(attempt < this.options.attempts && this.options.shouldRetry(response));
|
|
1044
|
+
return Promise.resolve(attempt < this.options.attempts);
|
|
1045
|
+
}
|
|
1046
|
+
getDelay() {
|
|
1047
|
+
return this.options.delay;
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
var ExponentialRetryStrategy = class {
|
|
1051
|
+
constructor(options) {
|
|
1052
|
+
this.options = options;
|
|
1053
|
+
}
|
|
1054
|
+
shouldAttemptRetry(attempt, response) {
|
|
1055
|
+
if (this.options.shouldRetry) return Promise.resolve(attempt < this.options.attempts && this.options.shouldRetry(response));
|
|
1056
|
+
return Promise.resolve(attempt < this.options.attempts);
|
|
1057
|
+
}
|
|
1058
|
+
getDelay(attempt) {
|
|
1059
|
+
return Math.min(this.options.maxDelay, this.options.baseDelay * 2 ** attempt);
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
function createRetryStrategy(options) {
|
|
1063
|
+
if (typeof options === "number") return new LinearRetryStrategy({
|
|
1064
|
+
type: "linear",
|
|
1065
|
+
attempts: options,
|
|
1066
|
+
delay: 1e3
|
|
1067
|
+
});
|
|
1068
|
+
switch (options.type) {
|
|
1069
|
+
case "linear": return new LinearRetryStrategy(options);
|
|
1070
|
+
case "exponential": return new ExponentialRetryStrategy(options);
|
|
1071
|
+
default: throw new Error("Invalid retry strategy");
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
var getAuthHeader = async (options) => {
|
|
1075
|
+
const headers = {};
|
|
1076
|
+
const getValue = async (value) => typeof value === "function" ? await value() : value;
|
|
1077
|
+
if (options == null ? void 0 : options.auth) {
|
|
1078
|
+
if (options.auth.type === "Bearer") {
|
|
1079
|
+
const token = await getValue(options.auth.token);
|
|
1080
|
+
if (!token) return headers;
|
|
1081
|
+
headers["authorization"] = `Bearer ${token}`;
|
|
1082
|
+
} else if (options.auth.type === "Basic") {
|
|
1083
|
+
const [username, password] = await Promise.all([getValue(options.auth.username), getValue(options.auth.password)]);
|
|
1084
|
+
if (!username || !password) return headers;
|
|
1085
|
+
headers["authorization"] = `Basic ${btoa(`${username}:${password}`)}`;
|
|
1086
|
+
} else if (options.auth.type === "Custom") {
|
|
1087
|
+
const [prefix, value] = await Promise.all([getValue(options.auth.prefix), getValue(options.auth.value)]);
|
|
1088
|
+
if (!value) return headers;
|
|
1089
|
+
headers["authorization"] = `${prefix != null ? prefix : ""} ${value}`;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return headers;
|
|
1093
|
+
};
|
|
1094
|
+
var JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
1095
|
+
function detectResponseType(request) {
|
|
1096
|
+
const _contentType = request.headers.get("content-type");
|
|
1097
|
+
const textTypes = /* @__PURE__ */ new Set([
|
|
1098
|
+
"image/svg",
|
|
1099
|
+
"application/xml",
|
|
1100
|
+
"application/xhtml",
|
|
1101
|
+
"application/html"
|
|
1102
|
+
]);
|
|
1103
|
+
if (!_contentType) return "json";
|
|
1104
|
+
const contentType = _contentType.split(";").shift() || "";
|
|
1105
|
+
if (JSON_RE.test(contentType)) return "json";
|
|
1106
|
+
if (textTypes.has(contentType) || contentType.startsWith("text/")) return "text";
|
|
1107
|
+
return "blob";
|
|
1108
|
+
}
|
|
1109
|
+
function isJSONParsable(value) {
|
|
1110
|
+
try {
|
|
1111
|
+
JSON.parse(value);
|
|
1112
|
+
return true;
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
return false;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
function isJSONSerializable(value) {
|
|
1118
|
+
if (value === void 0) return false;
|
|
1119
|
+
const t = typeof value;
|
|
1120
|
+
if (t === "string" || t === "number" || t === "boolean" || t === null) return true;
|
|
1121
|
+
if (t !== "object") return false;
|
|
1122
|
+
if (Array.isArray(value)) return true;
|
|
1123
|
+
if (value.buffer) return false;
|
|
1124
|
+
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
1125
|
+
}
|
|
1126
|
+
function jsonParse(text) {
|
|
1127
|
+
try {
|
|
1128
|
+
return JSON.parse(text);
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
return text;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
function isFunction(value) {
|
|
1134
|
+
return typeof value === "function";
|
|
1135
|
+
}
|
|
1136
|
+
function getFetch(options) {
|
|
1137
|
+
if (options == null ? void 0 : options.customFetchImpl) return options.customFetchImpl;
|
|
1138
|
+
if (typeof globalThis !== "undefined" && isFunction(globalThis.fetch)) return globalThis.fetch;
|
|
1139
|
+
if (typeof window !== "undefined" && isFunction(window.fetch)) return window.fetch;
|
|
1140
|
+
throw new Error("No fetch implementation found");
|
|
1141
|
+
}
|
|
1142
|
+
function mergeHeaders(...sources) {
|
|
1143
|
+
const merged = {};
|
|
1144
|
+
for (const source of sources) {
|
|
1145
|
+
if (!source) continue;
|
|
1146
|
+
if (source instanceof Headers) source.forEach((value, key) => {
|
|
1147
|
+
merged[key] = value;
|
|
1148
|
+
});
|
|
1149
|
+
else {
|
|
1150
|
+
const entries = Array.isArray(source) ? source : Object.entries(source);
|
|
1151
|
+
for (const [key, value] of entries) if (value !== null && value !== void 0) merged[key] = value;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
return merged;
|
|
1155
|
+
}
|
|
1156
|
+
async function getHeaders(opts) {
|
|
1157
|
+
const headers = new Headers(mergeHeaders(opts == null ? void 0 : opts.headers, await getAuthHeader(opts)));
|
|
1158
|
+
if (!headers.has("content-type")) {
|
|
1159
|
+
const contentType = detectContentType(opts == null ? void 0 : opts.body);
|
|
1160
|
+
if (contentType) headers.set("content-type", contentType);
|
|
1161
|
+
}
|
|
1162
|
+
return headers;
|
|
1163
|
+
}
|
|
1164
|
+
function detectContentType(body) {
|
|
1165
|
+
if (isJSONSerializable(body)) return "application/json";
|
|
1166
|
+
return null;
|
|
1167
|
+
}
|
|
1168
|
+
function getMediaType(headers) {
|
|
1169
|
+
const contentType = headers.get("content-type");
|
|
1170
|
+
return contentType ? contentType.split(";")[0].trim().toLowerCase() : null;
|
|
1171
|
+
}
|
|
1172
|
+
function getBody(options, headers) {
|
|
1173
|
+
const { body } = options;
|
|
1174
|
+
if (!body) return null;
|
|
1175
|
+
if (!isJSONSerializable(body)) return body;
|
|
1176
|
+
if (typeof body === "string") return body;
|
|
1177
|
+
if (getMediaType(headers) === "application/x-www-form-urlencoded") return new URLSearchParams(body).toString();
|
|
1178
|
+
return JSON.stringify(body);
|
|
1179
|
+
}
|
|
1180
|
+
function getMethod$1(url, options) {
|
|
1181
|
+
var _a;
|
|
1182
|
+
if (options == null ? void 0 : options.method) return options.method.toUpperCase();
|
|
1183
|
+
if (url.startsWith("@")) {
|
|
1184
|
+
const pMethod = (_a = url.split("@")[1]) == null ? void 0 : _a.split("/")[0];
|
|
1185
|
+
if (!methods.includes(pMethod)) return (options == null ? void 0 : options.body) ? "POST" : "GET";
|
|
1186
|
+
return pMethod.toUpperCase();
|
|
1187
|
+
}
|
|
1188
|
+
return (options == null ? void 0 : options.body) ? "POST" : "GET";
|
|
1189
|
+
}
|
|
1190
|
+
function getTimeout(options, controller) {
|
|
1191
|
+
let abortTimeout;
|
|
1192
|
+
if (!(options == null ? void 0 : options.signal) && (options == null ? void 0 : options.timeout)) abortTimeout = setTimeout(() => controller == null ? void 0 : controller.abort(), options == null ? void 0 : options.timeout);
|
|
1193
|
+
return {
|
|
1194
|
+
abortTimeout,
|
|
1195
|
+
clearTimeout: () => {
|
|
1196
|
+
if (abortTimeout) clearTimeout(abortTimeout);
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
var ValidationError = class _ValidationError extends Error {
|
|
1201
|
+
constructor(issues, message) {
|
|
1202
|
+
super(message || JSON.stringify(issues, null, 2));
|
|
1203
|
+
this.issues = issues;
|
|
1204
|
+
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
1207
|
+
async function parseStandardSchema(schema, input) {
|
|
1208
|
+
const result = await schema["~standard"].validate(input);
|
|
1209
|
+
if (result.issues) throw new ValidationError(result.issues);
|
|
1210
|
+
return result.value;
|
|
1211
|
+
}
|
|
1212
|
+
var methods = [
|
|
1213
|
+
"get",
|
|
1214
|
+
"post",
|
|
1215
|
+
"put",
|
|
1216
|
+
"patch",
|
|
1217
|
+
"delete"
|
|
1218
|
+
];
|
|
1219
|
+
var applySchemaPlugin = (config) => ({
|
|
1220
|
+
id: "apply-schema",
|
|
1221
|
+
name: "Apply Schema",
|
|
1222
|
+
version: "1.0.0",
|
|
1223
|
+
async init(url, options) {
|
|
1224
|
+
var _a, _b, _c, _d;
|
|
1225
|
+
const schema = ((_b = (_a = config.plugins) == null ? void 0 : _a.find((plugin) => {
|
|
1226
|
+
var _a2;
|
|
1227
|
+
return ((_a2 = plugin.schema) == null ? void 0 : _a2.config) ? url.startsWith(plugin.schema.config.baseURL || "") || url.startsWith(plugin.schema.config.prefix || "") : false;
|
|
1228
|
+
})) == null ? void 0 : _b.schema) || config.schema;
|
|
1229
|
+
if (schema) {
|
|
1230
|
+
let urlKey = url;
|
|
1231
|
+
if ((_c = schema.config) == null ? void 0 : _c.prefix) {
|
|
1232
|
+
if (urlKey.startsWith(schema.config.prefix)) {
|
|
1233
|
+
urlKey = urlKey.replace(schema.config.prefix, "");
|
|
1234
|
+
if (schema.config.baseURL) url = url.replace(schema.config.prefix, schema.config.baseURL);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
if ((_d = schema.config) == null ? void 0 : _d.baseURL) {
|
|
1238
|
+
if (urlKey.startsWith(schema.config.baseURL)) urlKey = urlKey.replace(schema.config.baseURL, "");
|
|
1239
|
+
}
|
|
1240
|
+
if (urlKey.startsWith("/") && urlKey.charAt(1) === "@") urlKey = urlKey.substring(1);
|
|
1241
|
+
const keySchema = schema.schema[urlKey];
|
|
1242
|
+
if (keySchema) {
|
|
1243
|
+
let validatedHeaders = options == null ? void 0 : options.headers;
|
|
1244
|
+
if (keySchema.headers && !(options == null ? void 0 : options.disableValidation)) {
|
|
1245
|
+
const normalizedHeaders = {};
|
|
1246
|
+
if (options == null ? void 0 : options.headers) {
|
|
1247
|
+
if (options.headers instanceof Headers) options.headers.forEach((value, key) => {
|
|
1248
|
+
normalizedHeaders[key.toLowerCase()] = value;
|
|
1249
|
+
});
|
|
1250
|
+
else if (typeof options.headers === "object") {
|
|
1251
|
+
for (const [key, value] of Object.entries(options.headers)) if (value !== null && value !== void 0) normalizedHeaders[key.toLowerCase()] = value;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
const validated = await parseStandardSchema(keySchema.headers, normalizedHeaders);
|
|
1255
|
+
const finalHeaders = {};
|
|
1256
|
+
for (const [key, value] of Object.entries(validated)) finalHeaders[key.toLowerCase()] = value;
|
|
1257
|
+
validatedHeaders = finalHeaders;
|
|
1258
|
+
}
|
|
1259
|
+
let opts = __spreadProps(__spreadValues({}, options), {
|
|
1260
|
+
method: keySchema.method,
|
|
1261
|
+
output: keySchema.output,
|
|
1262
|
+
headers: validatedHeaders
|
|
1263
|
+
});
|
|
1264
|
+
if (!(options == null ? void 0 : options.disableValidation)) opts = __spreadProps(__spreadValues({}, opts), {
|
|
1265
|
+
body: keySchema.input ? await parseStandardSchema(keySchema.input, options == null ? void 0 : options.body) : options == null ? void 0 : options.body,
|
|
1266
|
+
params: keySchema.params ? await parseStandardSchema(keySchema.params, options == null ? void 0 : options.params) : options == null ? void 0 : options.params,
|
|
1267
|
+
query: keySchema.query ? await parseStandardSchema(keySchema.query, options == null ? void 0 : options.query) : options == null ? void 0 : options.query
|
|
1268
|
+
});
|
|
1269
|
+
return {
|
|
1270
|
+
url,
|
|
1271
|
+
options: opts
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return {
|
|
1276
|
+
url,
|
|
1277
|
+
options
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
var createFetch = (config) => {
|
|
1282
|
+
async function $fetch(url, options) {
|
|
1283
|
+
const opts = __spreadProps(__spreadValues(__spreadValues({}, config), options), {
|
|
1284
|
+
headers: mergeHeaders(config == null ? void 0 : config.headers, options == null ? void 0 : options.headers),
|
|
1285
|
+
plugins: [
|
|
1286
|
+
...(config == null ? void 0 : config.plugins) || [],
|
|
1287
|
+
applySchemaPlugin(config || {}),
|
|
1288
|
+
...(options == null ? void 0 : options.plugins) || []
|
|
1289
|
+
]
|
|
1290
|
+
});
|
|
1291
|
+
if (config == null ? void 0 : config.catchAllError) try {
|
|
1292
|
+
return await betterFetch(url, opts);
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
return {
|
|
1295
|
+
data: null,
|
|
1296
|
+
error: {
|
|
1297
|
+
status: 500,
|
|
1298
|
+
statusText: "Fetch Error",
|
|
1299
|
+
message: "Fetch related error. Captured by catchAllError option. See error property for more details.",
|
|
1300
|
+
error
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
return await betterFetch(url, opts);
|
|
1305
|
+
}
|
|
1306
|
+
return $fetch;
|
|
1307
|
+
};
|
|
1308
|
+
var isReservedPathSegment = (value) => value === "." || value === "..";
|
|
1309
|
+
function encodePathSegment(segment, pathParams) {
|
|
1310
|
+
let pathSegment = segment;
|
|
1311
|
+
for (const [key, value] of pathParams) pathSegment = pathSegment.replace(key, value);
|
|
1312
|
+
if (isReservedPathSegment(pathSegment)) throw new TypeError("Path parameters cannot be reserved path segments");
|
|
1313
|
+
return encodeURIComponent(pathSegment);
|
|
1314
|
+
}
|
|
1315
|
+
function getURL2(url, option) {
|
|
1316
|
+
const { baseURL, params, query } = option || {
|
|
1317
|
+
query: {},
|
|
1318
|
+
params: {},
|
|
1319
|
+
baseURL: ""
|
|
1320
|
+
};
|
|
1321
|
+
let basePath = url.startsWith("http") ? url.split("/").slice(0, 3).join("/") : baseURL || "";
|
|
1322
|
+
if (url.startsWith("@")) {
|
|
1323
|
+
const m = url.toString().split("@")[1].split("/")[0];
|
|
1324
|
+
if (methods.includes(m)) url = url.replace(`@${m}/`, "/");
|
|
1325
|
+
}
|
|
1326
|
+
if (!basePath.endsWith("/")) basePath += "/";
|
|
1327
|
+
let [path, urlQuery] = url.replace(basePath, "").split("?");
|
|
1328
|
+
const queryParams = new URLSearchParams(urlQuery);
|
|
1329
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
1330
|
+
if (value == null) continue;
|
|
1331
|
+
let serializedValue;
|
|
1332
|
+
if (typeof value === "string") serializedValue = value;
|
|
1333
|
+
else if (Array.isArray(value)) {
|
|
1334
|
+
for (const val of value) queryParams.append(key, val);
|
|
1335
|
+
continue;
|
|
1336
|
+
} else serializedValue = JSON.stringify(value);
|
|
1337
|
+
queryParams.set(key, serializedValue);
|
|
1338
|
+
}
|
|
1339
|
+
const pathParams = /* @__PURE__ */ new Map();
|
|
1340
|
+
if (params) {
|
|
1341
|
+
if (Array.isArray(params)) {
|
|
1342
|
+
const paramPaths = path.split("/").filter((p) => p.startsWith(":"));
|
|
1343
|
+
for (const [index, key] of paramPaths.entries()) {
|
|
1344
|
+
const value = params[index];
|
|
1345
|
+
pathParams.set(key, String(value));
|
|
1346
|
+
}
|
|
1347
|
+
} else for (const [key, value] of Object.entries(params)) pathParams.set(`:${key}`, String(value));
|
|
1348
|
+
}
|
|
1349
|
+
path = path.split("/").map((segment) => encodePathSegment(segment, pathParams)).join("/");
|
|
1350
|
+
path = path.replace(/^\/+/, "");
|
|
1351
|
+
let queryParamString = queryParams.toString();
|
|
1352
|
+
queryParamString = queryParamString.length > 0 ? `?${queryParamString}`.replace(/\+/g, "%20") : "";
|
|
1353
|
+
if (!basePath.startsWith("http")) return `${basePath}${path}${queryParamString}`;
|
|
1354
|
+
return new URL(`${path}${queryParamString}`, basePath);
|
|
1355
|
+
}
|
|
1356
|
+
var betterFetch = async (url, options) => {
|
|
1357
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1358
|
+
const { hooks, url: __url, options: opts } = await initializePlugins(url, options);
|
|
1359
|
+
const fetch = getFetch(opts);
|
|
1360
|
+
const controller = new AbortController();
|
|
1361
|
+
const signal = (_a = opts.signal) != null ? _a : controller.signal;
|
|
1362
|
+
const _url = getURL2(__url, opts);
|
|
1363
|
+
const headers = await getHeaders(opts);
|
|
1364
|
+
const body = getBody(opts, headers);
|
|
1365
|
+
const method = getMethod$1(__url, opts);
|
|
1366
|
+
const context = __spreadProps(__spreadValues({}, opts), {
|
|
1367
|
+
url: _url,
|
|
1368
|
+
headers,
|
|
1369
|
+
body,
|
|
1370
|
+
method,
|
|
1371
|
+
signal
|
|
1372
|
+
});
|
|
1373
|
+
for (const onRequest of hooks.onRequest) if (onRequest) {
|
|
1374
|
+
const res = await onRequest(context);
|
|
1375
|
+
if (typeof res === "object" && res !== null) Object.assign(context, res);
|
|
1376
|
+
}
|
|
1377
|
+
if ("pipeTo" in context && typeof context.pipeTo === "function" || typeof ((_b = options == null ? void 0 : options.body) == null ? void 0 : _b.pipe) === "function") {
|
|
1378
|
+
if (!("duplex" in context)) context.duplex = "half";
|
|
1379
|
+
}
|
|
1380
|
+
const { clearTimeout: clearTimeout2 } = getTimeout(opts, controller);
|
|
1381
|
+
let response = await fetch(context.url, context);
|
|
1382
|
+
clearTimeout2();
|
|
1383
|
+
const responseContext = {
|
|
1384
|
+
response,
|
|
1385
|
+
request: context
|
|
1386
|
+
};
|
|
1387
|
+
for (const onResponse of hooks.onResponse) if (onResponse) {
|
|
1388
|
+
const r = await onResponse(__spreadProps(__spreadValues({}, responseContext), { response: ((_c = options == null ? void 0 : options.hookOptions) == null ? void 0 : _c.cloneResponse) ? response.clone() : response }));
|
|
1389
|
+
if (r instanceof Response) response = r;
|
|
1390
|
+
else if (typeof r === "object" && r !== null) response = r.response;
|
|
1391
|
+
}
|
|
1392
|
+
if (response.ok) {
|
|
1393
|
+
if (!(context.method !== "HEAD")) return {
|
|
1394
|
+
data: "",
|
|
1395
|
+
error: null
|
|
1396
|
+
};
|
|
1397
|
+
const responseType = detectResponseType(response);
|
|
1398
|
+
const successContext = {
|
|
1399
|
+
data: null,
|
|
1400
|
+
response,
|
|
1401
|
+
request: context
|
|
1402
|
+
};
|
|
1403
|
+
if (responseType === "json" || responseType === "text") {
|
|
1404
|
+
const text = await response.text();
|
|
1405
|
+
successContext.data = await ((_d = context.jsonParser) != null ? _d : jsonParse)(text);
|
|
1406
|
+
} else successContext.data = await response[responseType]();
|
|
1407
|
+
if (context == null ? void 0 : context.output) {
|
|
1408
|
+
if (context.output && !context.disableValidation) successContext.data = await parseStandardSchema(context.output, successContext.data);
|
|
1409
|
+
}
|
|
1410
|
+
for (const onSuccess of hooks.onSuccess) if (onSuccess) await onSuccess(__spreadProps(__spreadValues({}, successContext), { response: ((_e = options == null ? void 0 : options.hookOptions) == null ? void 0 : _e.cloneResponse) ? response.clone() : response }));
|
|
1411
|
+
if (options == null ? void 0 : options.throw) return successContext.data;
|
|
1412
|
+
return {
|
|
1413
|
+
data: successContext.data,
|
|
1414
|
+
error: null
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
const parser = (_f = options == null ? void 0 : options.jsonParser) != null ? _f : jsonParse;
|
|
1418
|
+
const responseText = await response.text();
|
|
1419
|
+
const isJSONResponse = isJSONParsable(responseText);
|
|
1420
|
+
const errorObject = isJSONResponse ? await parser(responseText) : null;
|
|
1421
|
+
const errorContext = {
|
|
1422
|
+
response,
|
|
1423
|
+
responseText,
|
|
1424
|
+
request: context,
|
|
1425
|
+
error: __spreadProps(__spreadValues({}, errorObject), {
|
|
1426
|
+
status: response.status,
|
|
1427
|
+
statusText: response.statusText
|
|
1428
|
+
})
|
|
1429
|
+
};
|
|
1430
|
+
for (const onError of hooks.onError) if (onError) await onError(__spreadProps(__spreadValues({}, errorContext), { response: ((_g = options == null ? void 0 : options.hookOptions) == null ? void 0 : _g.cloneResponse) ? response.clone() : response }));
|
|
1431
|
+
if (options == null ? void 0 : options.retry) {
|
|
1432
|
+
const retryStrategy = createRetryStrategy(options.retry);
|
|
1433
|
+
const _retryAttempt = (_h = options.retryAttempt) != null ? _h : 0;
|
|
1434
|
+
if (await retryStrategy.shouldAttemptRetry(_retryAttempt, response)) {
|
|
1435
|
+
for (const onRetry of hooks.onRetry) if (onRetry) await onRetry(responseContext);
|
|
1436
|
+
const delay = retryStrategy.getDelay(_retryAttempt);
|
|
1437
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1438
|
+
return await betterFetch(url, __spreadProps(__spreadValues({}, options), { retryAttempt: _retryAttempt + 1 }));
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
if (options == null ? void 0 : options.throw) throw new BetterFetchError(response.status, response.statusText, isJSONResponse ? errorObject : responseText);
|
|
1442
|
+
return {
|
|
1443
|
+
data: null,
|
|
1444
|
+
error: __spreadProps(__spreadValues({}, errorObject), {
|
|
1445
|
+
status: response.status,
|
|
1446
|
+
statusText: response.statusText
|
|
1447
|
+
})
|
|
1448
|
+
};
|
|
1449
|
+
};
|
|
1450
|
+
|
|
1451
|
+
//#endregion
|
|
1452
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/parser.mjs
|
|
1453
|
+
const PROTO_POLLUTION_PATTERNS = {
|
|
1454
|
+
proto: /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,
|
|
1455
|
+
constructor: /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,
|
|
1456
|
+
protoShort: /"__proto__"\s*:/,
|
|
1457
|
+
constructorShort: /"constructor"\s*:/
|
|
1458
|
+
};
|
|
1459
|
+
const JSON_SIGNATURE = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
1460
|
+
const SPECIAL_VALUES = {
|
|
1461
|
+
true: true,
|
|
1462
|
+
false: false,
|
|
1463
|
+
null: null,
|
|
1464
|
+
undefined: void 0,
|
|
1465
|
+
nan: NaN,
|
|
1466
|
+
infinity: Number.POSITIVE_INFINITY,
|
|
1467
|
+
"-infinity": Number.NEGATIVE_INFINITY
|
|
1468
|
+
};
|
|
1469
|
+
const ISO_DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,7}))?(?:Z|([+-])(\d{2}):(\d{2}))$/;
|
|
1470
|
+
function isValidDate(date) {
|
|
1471
|
+
return date instanceof Date && !isNaN(date.getTime());
|
|
1472
|
+
}
|
|
1473
|
+
function parseISODate(value) {
|
|
1474
|
+
const match = ISO_DATE_REGEX.exec(value);
|
|
1475
|
+
if (!match) return null;
|
|
1476
|
+
const [, year, month, day, hour, minute, second, ms, offsetSign, offsetHour, offsetMinute] = match;
|
|
1477
|
+
const date = new Date(Date.UTC(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10), parseInt(hour, 10), parseInt(minute, 10), parseInt(second, 10), ms ? parseInt(ms.padEnd(3, "0"), 10) : 0));
|
|
1478
|
+
if (offsetSign) {
|
|
1479
|
+
const offset = (parseInt(offsetHour, 10) * 60 + parseInt(offsetMinute, 10)) * (offsetSign === "+" ? -1 : 1);
|
|
1480
|
+
date.setUTCMinutes(date.getUTCMinutes() + offset);
|
|
1481
|
+
}
|
|
1482
|
+
return isValidDate(date) ? date : null;
|
|
1483
|
+
}
|
|
1484
|
+
function betterJSONParse(value, options = {}) {
|
|
1485
|
+
const { strict = false, warnings = false, reviver, parseDates = true } = options;
|
|
1486
|
+
if (typeof value !== "string") return value;
|
|
1487
|
+
const trimmed = value.trim();
|
|
1488
|
+
const lowerValue = trimmed.toLowerCase();
|
|
1489
|
+
if (lowerValue.length <= 9 && lowerValue in SPECIAL_VALUES) return SPECIAL_VALUES[lowerValue];
|
|
1490
|
+
if (!JSON_SIGNATURE.test(trimmed)) {
|
|
1491
|
+
if (strict) throw new SyntaxError("[better-json] Invalid JSON");
|
|
1492
|
+
return value;
|
|
1493
|
+
}
|
|
1494
|
+
if (Object.entries(PROTO_POLLUTION_PATTERNS).some(([key, pattern]) => {
|
|
1495
|
+
const matches = pattern.test(trimmed);
|
|
1496
|
+
if (matches && warnings) console.warn(`[better-json] Detected potential prototype pollution attempt using ${key} pattern`);
|
|
1497
|
+
return matches;
|
|
1498
|
+
}) && strict) throw new Error("[better-json] Potential prototype pollution attempt detected");
|
|
1499
|
+
try {
|
|
1500
|
+
const secureReviver = (key, value) => {
|
|
1501
|
+
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
|
|
1502
|
+
if (warnings) console.warn(`[better-json] Dropping "${key}" key to prevent prototype pollution`);
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
if (parseDates && typeof value === "string") {
|
|
1506
|
+
const date = parseISODate(value);
|
|
1507
|
+
if (date) return date;
|
|
1508
|
+
}
|
|
1509
|
+
return reviver ? reviver(key, value) : value;
|
|
1510
|
+
};
|
|
1511
|
+
return JSON.parse(trimmed, secureReviver);
|
|
1512
|
+
} catch (error) {
|
|
1513
|
+
if (strict) throw error;
|
|
1514
|
+
return value;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
function parseJSON(value, options = { strict: true }) {
|
|
1518
|
+
return betterJSONParse(value, options);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
//#endregion
|
|
1522
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/organization/access/statement.mjs
|
|
1523
|
+
const defaultStatements = {
|
|
1524
|
+
organization: ["update", "delete"],
|
|
1525
|
+
member: [
|
|
1526
|
+
"create",
|
|
1527
|
+
"update",
|
|
1528
|
+
"delete"
|
|
1529
|
+
],
|
|
1530
|
+
invitation: ["create", "cancel"],
|
|
1531
|
+
team: [
|
|
1532
|
+
"create",
|
|
1533
|
+
"update",
|
|
1534
|
+
"delete"
|
|
1535
|
+
],
|
|
1536
|
+
ac: [
|
|
1537
|
+
"create",
|
|
1538
|
+
"read",
|
|
1539
|
+
"update",
|
|
1540
|
+
"delete"
|
|
1541
|
+
]
|
|
1542
|
+
};
|
|
1543
|
+
const defaultAc = createAccessControl(defaultStatements);
|
|
1544
|
+
const adminAc = defaultAc.newRole({
|
|
1545
|
+
organization: ["update"],
|
|
1546
|
+
invitation: ["create", "cancel"],
|
|
1547
|
+
member: [
|
|
1548
|
+
"create",
|
|
1549
|
+
"update",
|
|
1550
|
+
"delete"
|
|
1551
|
+
],
|
|
1552
|
+
team: [
|
|
1553
|
+
"create",
|
|
1554
|
+
"update",
|
|
1555
|
+
"delete"
|
|
1556
|
+
],
|
|
1557
|
+
ac: [
|
|
1558
|
+
"create",
|
|
1559
|
+
"read",
|
|
1560
|
+
"update",
|
|
1561
|
+
"delete"
|
|
1562
|
+
]
|
|
1563
|
+
});
|
|
1564
|
+
const ownerAc = defaultAc.newRole({
|
|
1565
|
+
organization: ["update", "delete"],
|
|
1566
|
+
member: [
|
|
1567
|
+
"create",
|
|
1568
|
+
"update",
|
|
1569
|
+
"delete"
|
|
1570
|
+
],
|
|
1571
|
+
invitation: ["create", "cancel"],
|
|
1572
|
+
team: [
|
|
1573
|
+
"create",
|
|
1574
|
+
"update",
|
|
1575
|
+
"delete"
|
|
1576
|
+
],
|
|
1577
|
+
ac: [
|
|
1578
|
+
"create",
|
|
1579
|
+
"read",
|
|
1580
|
+
"update",
|
|
1581
|
+
"delete"
|
|
1582
|
+
]
|
|
1583
|
+
});
|
|
1584
|
+
const memberAc = defaultAc.newRole({
|
|
1585
|
+
organization: [],
|
|
1586
|
+
member: [],
|
|
1587
|
+
invitation: [],
|
|
1588
|
+
team: [],
|
|
1589
|
+
ac: ["read"]
|
|
1590
|
+
});
|
|
1591
|
+
const defaultRoles = {
|
|
1592
|
+
admin: adminAc,
|
|
1593
|
+
owner: ownerAc,
|
|
1594
|
+
member: memberAc
|
|
1595
|
+
};
|
|
1596
|
+
|
|
1597
|
+
//#endregion
|
|
1598
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/organization/permission.mjs
|
|
1599
|
+
const hasPermissionFn = (input, acRoles) => {
|
|
1600
|
+
if (!input.permissions) return false;
|
|
1601
|
+
const roles = input.role.split(",");
|
|
1602
|
+
const creatorRole = input.options.creatorRole || "owner";
|
|
1603
|
+
const isCreator = roles.includes(creatorRole);
|
|
1604
|
+
const allowCreatorsAllPermissions = input.allowCreatorAllPermissions || false;
|
|
1605
|
+
if (isCreator && allowCreatorsAllPermissions) return true;
|
|
1606
|
+
for (const role of roles) if ((acRoles[role]?.authorize(input.permissions))?.success) return true;
|
|
1607
|
+
return false;
|
|
1608
|
+
};
|
|
1609
|
+
|
|
1610
|
+
//#endregion
|
|
1611
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/organization/error-codes.mjs
|
|
1612
|
+
const ORGANIZATION_ERROR_CODES = defineErrorCodes({
|
|
1613
|
+
YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION: "You are not allowed to create a new organization",
|
|
1614
|
+
YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS: "You have reached the maximum number of organizations",
|
|
1615
|
+
ORGANIZATION_ALREADY_EXISTS: "Organization already exists",
|
|
1616
|
+
ORGANIZATION_SLUG_ALREADY_TAKEN: "Organization slug already taken",
|
|
1617
|
+
ORGANIZATION_NOT_FOUND: "Organization not found",
|
|
1618
|
+
USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION: "User is not a member of the organization",
|
|
1619
|
+
YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION: "You are not allowed to update this organization",
|
|
1620
|
+
YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION: "You are not allowed to delete this organization",
|
|
1621
|
+
NO_ACTIVE_ORGANIZATION: "No active organization",
|
|
1622
|
+
USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION: "User is already a member of this organization",
|
|
1623
|
+
MEMBER_NOT_FOUND: "Member not found",
|
|
1624
|
+
ROLE_NOT_FOUND: "Role not found",
|
|
1625
|
+
YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM: "You are not allowed to create a new team",
|
|
1626
|
+
TEAM_ALREADY_EXISTS: "Team already exists",
|
|
1627
|
+
TEAM_NOT_FOUND: "Team not found",
|
|
1628
|
+
YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER: "You cannot leave the organization as the only owner",
|
|
1629
|
+
YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER: "You cannot leave the organization without an owner",
|
|
1630
|
+
YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER: "You are not allowed to delete this member",
|
|
1631
|
+
YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION: "You are not allowed to invite users to this organization",
|
|
1632
|
+
USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION: "User is already invited to this organization",
|
|
1633
|
+
INVITATION_NOT_FOUND: "Invitation not found",
|
|
1634
|
+
YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION: "You are not the recipient of the invitation",
|
|
1635
|
+
EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION: "Email verification required before accepting or rejecting invitation",
|
|
1636
|
+
EMAIL_VERIFICATION_REQUIRED_FOR_INVITATION: "Email verification required to view or list invitations for the session email",
|
|
1637
|
+
YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION: "You are not allowed to cancel this invitation",
|
|
1638
|
+
INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION: "Inviter is no longer a member of the organization",
|
|
1639
|
+
YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE: "You are not allowed to invite a user with this role",
|
|
1640
|
+
FAILED_TO_RETRIEVE_INVITATION: "Failed to retrieve invitation",
|
|
1641
|
+
YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS: "You have reached the maximum number of teams",
|
|
1642
|
+
UNABLE_TO_REMOVE_LAST_TEAM: "Unable to remove last team",
|
|
1643
|
+
YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER: "You are not allowed to update this member",
|
|
1644
|
+
ORGANIZATION_MEMBERSHIP_LIMIT_REACHED: "Organization membership limit reached",
|
|
1645
|
+
YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to create teams in this organization",
|
|
1646
|
+
YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to delete teams in this organization",
|
|
1647
|
+
YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM: "You are not allowed to update this team",
|
|
1648
|
+
YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM: "You are not allowed to delete this team",
|
|
1649
|
+
INVITATION_LIMIT_REACHED: "Invitation limit reached",
|
|
1650
|
+
TEAM_MEMBER_LIMIT_REACHED: "Team member limit reached",
|
|
1651
|
+
USER_IS_NOT_A_MEMBER_OF_THE_TEAM: "User is not a member of the team",
|
|
1652
|
+
YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM: "You are not allowed to list the members of this team",
|
|
1653
|
+
YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM: "You do not have an active team",
|
|
1654
|
+
YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER: "You are not allowed to create a new member",
|
|
1655
|
+
YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER: "You are not allowed to remove a team member",
|
|
1656
|
+
YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION: "You are not allowed to access this organization as an owner",
|
|
1657
|
+
YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION: "You are not a member of this organization",
|
|
1658
|
+
MISSING_AC_INSTANCE: "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information",
|
|
1659
|
+
YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE: "You must be in an organization to create a role",
|
|
1660
|
+
YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE: "You are not allowed to create a role",
|
|
1661
|
+
YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE: "You are not allowed to update a role",
|
|
1662
|
+
YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE: "You are not allowed to delete a role",
|
|
1663
|
+
YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE: "You are not allowed to read a role",
|
|
1664
|
+
YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE: "You are not allowed to list a role",
|
|
1665
|
+
YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE: "You are not allowed to get a role",
|
|
1666
|
+
TOO_MANY_ROLES: "This organization has too many roles",
|
|
1667
|
+
INVALID_RESOURCE: "The provided permission includes an invalid resource",
|
|
1668
|
+
ROLE_NAME_IS_ALREADY_TAKEN: "That role name is already taken",
|
|
1669
|
+
CANNOT_DELETE_A_PRE_DEFINED_ROLE: "Cannot delete a pre-defined role",
|
|
1670
|
+
ROLE_IS_ASSIGNED_TO_MEMBERS: "Cannot delete a role that is assigned to members. Please reassign the members to a different role first",
|
|
1671
|
+
INVALID_TEAM_ID: "Team id contains a reserved character"
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1674
|
+
//#endregion
|
|
1675
|
+
//#region ../auth/dist/rbac.mjs
|
|
1676
|
+
const t$1 = createAccessControl({
|
|
1677
|
+
organization: [`update`, `delete`],
|
|
1678
|
+
member: [
|
|
1679
|
+
`create`,
|
|
1680
|
+
`update`,
|
|
1681
|
+
`delete`
|
|
1682
|
+
],
|
|
1683
|
+
project: [
|
|
1684
|
+
`create`,
|
|
1685
|
+
`read`,
|
|
1686
|
+
`update`,
|
|
1687
|
+
`archive`
|
|
1688
|
+
],
|
|
1689
|
+
environment: [
|
|
1690
|
+
`create`,
|
|
1691
|
+
`read`,
|
|
1692
|
+
`update`,
|
|
1693
|
+
`archive`,
|
|
1694
|
+
`set_production`
|
|
1695
|
+
],
|
|
1696
|
+
flag: [
|
|
1697
|
+
`read`,
|
|
1698
|
+
`create`,
|
|
1699
|
+
`update`,
|
|
1700
|
+
`archive`
|
|
1701
|
+
],
|
|
1702
|
+
flag_state: [`update`],
|
|
1703
|
+
flag_production: [`toggle`],
|
|
1704
|
+
apiKey: [
|
|
1705
|
+
`create`,
|
|
1706
|
+
`read`,
|
|
1707
|
+
`revoke`
|
|
1708
|
+
],
|
|
1709
|
+
sdk_key: [
|
|
1710
|
+
`create`,
|
|
1711
|
+
`read`,
|
|
1712
|
+
`revoke`
|
|
1713
|
+
],
|
|
1714
|
+
evaluated_entity: [`read`, `delete`]
|
|
1715
|
+
});
|
|
1716
|
+
const n$1 = {
|
|
1717
|
+
viewer: t$1.newRole({
|
|
1718
|
+
project: [`read`],
|
|
1719
|
+
environment: [`read`],
|
|
1720
|
+
flag: [`read`],
|
|
1721
|
+
evaluated_entity: [`read`]
|
|
1722
|
+
}),
|
|
1723
|
+
editor: t$1.newRole({
|
|
1724
|
+
project: [`read`, `update`],
|
|
1725
|
+
environment: [`read`],
|
|
1726
|
+
flag: [
|
|
1727
|
+
`read`,
|
|
1728
|
+
`create`,
|
|
1729
|
+
`update`,
|
|
1730
|
+
`archive`
|
|
1731
|
+
],
|
|
1732
|
+
flag_state: [`update`],
|
|
1733
|
+
apiKey: [`read`],
|
|
1734
|
+
sdk_key: [`read`],
|
|
1735
|
+
evaluated_entity: [`read`]
|
|
1736
|
+
}),
|
|
1737
|
+
admin: t$1.newRole({
|
|
1738
|
+
organization: [`update`],
|
|
1739
|
+
member: [`create`, `update`],
|
|
1740
|
+
project: [
|
|
1741
|
+
`create`,
|
|
1742
|
+
`read`,
|
|
1743
|
+
`update`,
|
|
1744
|
+
`archive`
|
|
1745
|
+
],
|
|
1746
|
+
environment: [
|
|
1747
|
+
`create`,
|
|
1748
|
+
`read`,
|
|
1749
|
+
`update`,
|
|
1750
|
+
`archive`,
|
|
1751
|
+
`set_production`
|
|
1752
|
+
],
|
|
1753
|
+
flag: [
|
|
1754
|
+
`read`,
|
|
1755
|
+
`create`,
|
|
1756
|
+
`update`,
|
|
1757
|
+
`archive`
|
|
1758
|
+
],
|
|
1759
|
+
flag_state: [`update`],
|
|
1760
|
+
flag_production: [`toggle`],
|
|
1761
|
+
apiKey: [
|
|
1762
|
+
`create`,
|
|
1763
|
+
`read`,
|
|
1764
|
+
`revoke`
|
|
1765
|
+
],
|
|
1766
|
+
sdk_key: [
|
|
1767
|
+
`create`,
|
|
1768
|
+
`read`,
|
|
1769
|
+
`revoke`
|
|
1770
|
+
],
|
|
1771
|
+
evaluated_entity: [`read`, `delete`]
|
|
1772
|
+
}),
|
|
1773
|
+
owner: t$1.newRole({
|
|
1774
|
+
organization: [`update`, `delete`],
|
|
1775
|
+
member: [
|
|
1776
|
+
`create`,
|
|
1777
|
+
`update`,
|
|
1778
|
+
`delete`
|
|
1779
|
+
],
|
|
1780
|
+
project: [
|
|
1781
|
+
`create`,
|
|
1782
|
+
`read`,
|
|
1783
|
+
`update`,
|
|
1784
|
+
`archive`
|
|
1785
|
+
],
|
|
1786
|
+
environment: [
|
|
1787
|
+
`create`,
|
|
1788
|
+
`read`,
|
|
1789
|
+
`update`,
|
|
1790
|
+
`archive`,
|
|
1791
|
+
`set_production`
|
|
1792
|
+
],
|
|
1793
|
+
flag: [
|
|
1794
|
+
`read`,
|
|
1795
|
+
`create`,
|
|
1796
|
+
`update`,
|
|
1797
|
+
`archive`
|
|
1798
|
+
],
|
|
1799
|
+
flag_state: [`update`],
|
|
1800
|
+
flag_production: [`toggle`],
|
|
1801
|
+
apiKey: [
|
|
1802
|
+
`create`,
|
|
1803
|
+
`read`,
|
|
1804
|
+
`revoke`
|
|
1805
|
+
],
|
|
1806
|
+
sdk_key: [
|
|
1807
|
+
`create`,
|
|
1808
|
+
`read`,
|
|
1809
|
+
`revoke`
|
|
1810
|
+
],
|
|
1811
|
+
evaluated_entity: [`read`, `delete`]
|
|
1812
|
+
})
|
|
1813
|
+
};
|
|
1814
|
+
|
|
1815
|
+
//#endregion
|
|
1816
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/broadcast-channel.mjs
|
|
1817
|
+
const kBroadcastChannel = Symbol.for("better-auth:broadcast-channel");
|
|
1818
|
+
const now$1 = () => Math.floor(Date.now() / 1e3);
|
|
1819
|
+
var WindowBroadcastChannel = class {
|
|
1820
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1821
|
+
name;
|
|
1822
|
+
constructor(name = "better-auth.message") {
|
|
1823
|
+
this.name = name;
|
|
1824
|
+
}
|
|
1825
|
+
subscribe(listener) {
|
|
1826
|
+
this.listeners.add(listener);
|
|
1827
|
+
return () => {
|
|
1828
|
+
this.listeners.delete(listener);
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
post(message) {
|
|
1832
|
+
if (typeof window === "undefined") return;
|
|
1833
|
+
try {
|
|
1834
|
+
localStorage.setItem(this.name, JSON.stringify({
|
|
1835
|
+
...message,
|
|
1836
|
+
timestamp: now$1()
|
|
1837
|
+
}));
|
|
1838
|
+
} catch {}
|
|
1839
|
+
}
|
|
1840
|
+
setup() {
|
|
1841
|
+
if (typeof window === "undefined" || typeof window.addEventListener === "undefined") return () => {};
|
|
1842
|
+
const handler = (event) => {
|
|
1843
|
+
if (event.key !== this.name) return;
|
|
1844
|
+
const message = JSON.parse(event.newValue ?? "{}");
|
|
1845
|
+
if (message?.event !== "session" || !message?.data) return;
|
|
1846
|
+
this.listeners.forEach((listener) => listener(message));
|
|
1847
|
+
};
|
|
1848
|
+
window.addEventListener("storage", handler);
|
|
1849
|
+
return () => {
|
|
1850
|
+
window.removeEventListener("storage", handler);
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1854
|
+
function getGlobalBroadcastChannel(name = "better-auth.message") {
|
|
1855
|
+
if (!globalThis[kBroadcastChannel]) globalThis[kBroadcastChannel] = new WindowBroadcastChannel(name);
|
|
1856
|
+
return globalThis[kBroadcastChannel];
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
//#endregion
|
|
1860
|
+
//#region ../../node_modules/.pnpm/nanostores@1.4.2/node_modules/nanostores/clean-stores/index.js
|
|
1861
|
+
const clean = Symbol("clean");
|
|
1862
|
+
|
|
1863
|
+
//#endregion
|
|
1864
|
+
//#region ../../node_modules/.pnpm/nanostores@1.4.2/node_modules/nanostores/atom/index.js
|
|
1865
|
+
let listenerQueue = [];
|
|
1866
|
+
let lqIndex = 0;
|
|
1867
|
+
let batchSeen = null;
|
|
1868
|
+
const QUEUE_ITEMS_PER_LISTENER = 4;
|
|
1869
|
+
const nanostoresGlobal = globalThis.nanostoresGlobal ||= { epoch: 0 };
|
|
1870
|
+
let drainQueue = () => {
|
|
1871
|
+
for (lqIndex = 0; lqIndex < listenerQueue.length; lqIndex += QUEUE_ITEMS_PER_LISTENER) listenerQueue[lqIndex](listenerQueue[lqIndex + 1].value, listenerQueue[lqIndex + 2], listenerQueue[lqIndex + 3]);
|
|
1872
|
+
listenerQueue.length = 0;
|
|
1873
|
+
};
|
|
1874
|
+
const atom = /* @__NO_SIDE_EFFECTS__ */ (initialValue) => {
|
|
1875
|
+
let listeners = [];
|
|
1876
|
+
let $atom = {
|
|
1877
|
+
get() {
|
|
1878
|
+
if (!$atom.lc) $atom.listen(() => {})();
|
|
1879
|
+
return $atom.value;
|
|
1880
|
+
},
|
|
1881
|
+
init: initialValue,
|
|
1882
|
+
lc: 0,
|
|
1883
|
+
listen(listener) {
|
|
1884
|
+
$atom.lc = listeners.push(listener);
|
|
1885
|
+
return () => {
|
|
1886
|
+
for (let i = lqIndex + QUEUE_ITEMS_PER_LISTENER; i < listenerQueue.length;) if (listenerQueue[i] === listener) listenerQueue.splice(i, QUEUE_ITEMS_PER_LISTENER);
|
|
1887
|
+
else i += QUEUE_ITEMS_PER_LISTENER;
|
|
1888
|
+
let index = listeners.indexOf(listener);
|
|
1889
|
+
if (~index) {
|
|
1890
|
+
listeners.splice(index, 1);
|
|
1891
|
+
if (!--$atom.lc) $atom.off();
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
},
|
|
1895
|
+
notify(oldValue, changedKey) {
|
|
1896
|
+
nanostoresGlobal.epoch++;
|
|
1897
|
+
let runListenerQueue = !listenerQueue.length && !batchSeen;
|
|
1898
|
+
for (let listener of listeners) {
|
|
1899
|
+
if (batchSeen?.has(listener)) continue;
|
|
1900
|
+
batchSeen?.add(listener);
|
|
1901
|
+
listenerQueue.push(listener, $atom, oldValue, batchSeen ? void 0 : changedKey);
|
|
1902
|
+
}
|
|
1903
|
+
if (runListenerQueue) drainQueue();
|
|
1904
|
+
},
|
|
1905
|
+
off() {},
|
|
1906
|
+
set(newValue) {
|
|
1907
|
+
let oldValue = $atom.value;
|
|
1908
|
+
if (oldValue !== newValue) {
|
|
1909
|
+
$atom.value = newValue;
|
|
1910
|
+
$atom.notify(oldValue);
|
|
1911
|
+
}
|
|
1912
|
+
},
|
|
1913
|
+
subscribe(listener) {
|
|
1914
|
+
let unbind = $atom.listen(listener);
|
|
1915
|
+
listener($atom.value);
|
|
1916
|
+
return unbind;
|
|
1917
|
+
},
|
|
1918
|
+
value: initialValue
|
|
1919
|
+
};
|
|
1920
|
+
if (process.env.NODE_ENV !== "production") $atom[clean] = () => {
|
|
1921
|
+
listeners = [];
|
|
1922
|
+
$atom.lc = 0;
|
|
1923
|
+
$atom.off();
|
|
1924
|
+
};
|
|
1925
|
+
return $atom;
|
|
1926
|
+
};
|
|
1927
|
+
|
|
1928
|
+
//#endregion
|
|
1929
|
+
//#region ../../node_modules/.pnpm/nanostores@1.4.2/node_modules/nanostores/lifecycle/index.js
|
|
1930
|
+
const SET = 2;
|
|
1931
|
+
const MOUNT = 5;
|
|
1932
|
+
const UNMOUNT = 6;
|
|
1933
|
+
const REVERT_MUTATION = 10;
|
|
1934
|
+
let on = (object, listener, eventKey, mutateStore) => {
|
|
1935
|
+
object.events = object.events || {};
|
|
1936
|
+
if (!object.events[eventKey + REVERT_MUTATION]) object.events[eventKey + REVERT_MUTATION] = mutateStore((eventProps) => {
|
|
1937
|
+
object.events[eventKey].reduceRight((event, l) => (l(event), event), {
|
|
1938
|
+
shared: {},
|
|
1939
|
+
...eventProps
|
|
1940
|
+
});
|
|
1941
|
+
});
|
|
1942
|
+
object.events[eventKey] = object.events[eventKey] || [];
|
|
1943
|
+
object.events[eventKey].push(listener);
|
|
1944
|
+
return () => {
|
|
1945
|
+
let currentListeners = object.events[eventKey];
|
|
1946
|
+
let index = currentListeners.indexOf(listener);
|
|
1947
|
+
currentListeners.splice(index, 1);
|
|
1948
|
+
if (!currentListeners.length) {
|
|
1949
|
+
delete object.events[eventKey];
|
|
1950
|
+
object.events[eventKey + REVERT_MUTATION]();
|
|
1951
|
+
delete object.events[eventKey + REVERT_MUTATION];
|
|
1952
|
+
}
|
|
1953
|
+
};
|
|
1954
|
+
};
|
|
1955
|
+
let onSet = ($store, listener) => on($store, listener, SET, (runListeners) => {
|
|
1956
|
+
let originSet = $store.set;
|
|
1957
|
+
let originSetKey = $store.setKey;
|
|
1958
|
+
if ($store.setKey) $store.setKey = (changed, changedValue) => {
|
|
1959
|
+
let isAborted;
|
|
1960
|
+
let abort = () => {
|
|
1961
|
+
isAborted = true;
|
|
1962
|
+
};
|
|
1963
|
+
runListeners({
|
|
1964
|
+
abort,
|
|
1965
|
+
changed,
|
|
1966
|
+
newValue: {
|
|
1967
|
+
...$store.value,
|
|
1968
|
+
[changed]: changedValue
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
if (!isAborted) return originSetKey(changed, changedValue);
|
|
1972
|
+
};
|
|
1973
|
+
$store.set = (newValue) => {
|
|
1974
|
+
let isAborted;
|
|
1975
|
+
let abort = () => {
|
|
1976
|
+
isAborted = true;
|
|
1977
|
+
};
|
|
1978
|
+
runListeners({
|
|
1979
|
+
abort,
|
|
1980
|
+
newValue
|
|
1981
|
+
});
|
|
1982
|
+
if (!isAborted) return originSet(newValue);
|
|
1983
|
+
};
|
|
1984
|
+
return () => {
|
|
1985
|
+
$store.set = originSet;
|
|
1986
|
+
$store.setKey = originSetKey;
|
|
1987
|
+
};
|
|
1988
|
+
});
|
|
1989
|
+
const STORE_UNMOUNT_DELAY = 1e3;
|
|
1990
|
+
let onMount = ($store, initialize) => {
|
|
1991
|
+
let listener = (payload) => {
|
|
1992
|
+
let destroy = initialize(payload);
|
|
1993
|
+
if (destroy) $store.events[UNMOUNT].push(destroy);
|
|
1994
|
+
};
|
|
1995
|
+
return on($store, listener, MOUNT, (runListeners) => {
|
|
1996
|
+
let originListen = $store.listen;
|
|
1997
|
+
$store.listen = (...args) => {
|
|
1998
|
+
if (!$store.lc && !$store.active) {
|
|
1999
|
+
$store.active = true;
|
|
2000
|
+
runListeners();
|
|
2001
|
+
}
|
|
2002
|
+
return originListen(...args);
|
|
2003
|
+
};
|
|
2004
|
+
let originOff = $store.off;
|
|
2005
|
+
$store.events[UNMOUNT] = [];
|
|
2006
|
+
$store.off = () => {
|
|
2007
|
+
originOff();
|
|
2008
|
+
setTimeout(() => {
|
|
2009
|
+
if ($store.active && !$store.lc) {
|
|
2010
|
+
$store.active = false;
|
|
2011
|
+
for (let destroy of $store.events[UNMOUNT]) destroy();
|
|
2012
|
+
$store.events[UNMOUNT] = [];
|
|
2013
|
+
}
|
|
2014
|
+
}, STORE_UNMOUNT_DELAY);
|
|
2015
|
+
};
|
|
2016
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2017
|
+
let originClean = $store[clean];
|
|
2018
|
+
$store[clean] = () => {
|
|
2019
|
+
for (let destroy of $store.events[UNMOUNT]) destroy();
|
|
2020
|
+
$store.events[UNMOUNT] = [];
|
|
2021
|
+
$store.active = false;
|
|
2022
|
+
originClean();
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
return () => {
|
|
2026
|
+
$store.listen = originListen;
|
|
2027
|
+
$store.off = originOff;
|
|
2028
|
+
};
|
|
2029
|
+
});
|
|
2030
|
+
};
|
|
2031
|
+
|
|
2032
|
+
//#endregion
|
|
2033
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/equality.mjs
|
|
2034
|
+
function isPlainObject(value) {
|
|
2035
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2036
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2037
|
+
return prototype === Object.prototype || prototype === null;
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Deep structural equality for JSON-serializable values.
|
|
2041
|
+
* Handles: primitives, null, arrays, and plain objects.
|
|
2042
|
+
* Short-circuits on referential equality at every recursion level.
|
|
2043
|
+
*/
|
|
2044
|
+
function isJsonEqual(a, b) {
|
|
2045
|
+
if (a === b) return true;
|
|
2046
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2047
|
+
if (a.length !== b.length) return false;
|
|
2048
|
+
for (let i = 0; i < a.length; i++) if (!isJsonEqual(a[i], b[i])) return false;
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
2051
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
2052
|
+
const keysA = Object.keys(a);
|
|
2053
|
+
const keysB = Object.keys(b);
|
|
2054
|
+
if (keysA.length !== keysB.length) return false;
|
|
2055
|
+
for (const key of keysA) if (!(key in b) || !isJsonEqual(a[key], b[key])) return false;
|
|
2056
|
+
return true;
|
|
2057
|
+
}
|
|
2058
|
+
return false;
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Attach an equality gate to a nanostores atom via `onSet`.
|
|
2062
|
+
* When `isEqual(currentValue, newValue)` returns true, the `set()` call
|
|
2063
|
+
* is aborted: no listeners fire, no framework re-renders occur.
|
|
2064
|
+
*
|
|
2065
|
+
* Returns the unsubscribe function from `onSet`.
|
|
2066
|
+
*/
|
|
2067
|
+
function withEquality(store, isEqual) {
|
|
2068
|
+
return onSet(store, ({ newValue, abort }) => {
|
|
2069
|
+
if (isEqual(store.value, newValue)) abort();
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
//#endregion
|
|
2074
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/focus-manager.mjs
|
|
2075
|
+
const kFocusManager = Symbol.for("better-auth:focus-manager");
|
|
2076
|
+
var WindowFocusManager = class {
|
|
2077
|
+
listeners = /* @__PURE__ */ new Set();
|
|
2078
|
+
subscribe(listener) {
|
|
2079
|
+
this.listeners.add(listener);
|
|
2080
|
+
return () => {
|
|
2081
|
+
this.listeners.delete(listener);
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
setFocused(focused) {
|
|
2085
|
+
this.listeners.forEach((listener) => listener(focused));
|
|
2086
|
+
}
|
|
2087
|
+
setup() {
|
|
2088
|
+
if (typeof window === "undefined" || typeof document === "undefined" || typeof window.addEventListener === "undefined") return () => {};
|
|
2089
|
+
const visibilityHandler = () => {
|
|
2090
|
+
if (document.visibilityState === "visible") this.setFocused(true);
|
|
2091
|
+
};
|
|
2092
|
+
document.addEventListener("visibilitychange", visibilityHandler, false);
|
|
2093
|
+
return () => {
|
|
2094
|
+
document.removeEventListener("visibilitychange", visibilityHandler, false);
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
};
|
|
2098
|
+
function getGlobalFocusManager() {
|
|
2099
|
+
if (!globalThis[kFocusManager]) globalThis[kFocusManager] = new WindowFocusManager();
|
|
2100
|
+
return globalThis[kFocusManager];
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
//#endregion
|
|
2104
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/online-manager.mjs
|
|
2105
|
+
const kOnlineManager = Symbol.for("better-auth:online-manager");
|
|
2106
|
+
var WindowOnlineManager = class {
|
|
2107
|
+
listeners = /* @__PURE__ */ new Set();
|
|
2108
|
+
isOnline = typeof navigator !== "undefined" ? navigator.onLine : true;
|
|
2109
|
+
subscribe(listener) {
|
|
2110
|
+
this.listeners.add(listener);
|
|
2111
|
+
return () => {
|
|
2112
|
+
this.listeners.delete(listener);
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
setOnline(online) {
|
|
2116
|
+
this.isOnline = online;
|
|
2117
|
+
this.listeners.forEach((listener) => listener(online));
|
|
2118
|
+
}
|
|
2119
|
+
setup() {
|
|
2120
|
+
if (typeof window === "undefined" || typeof window.addEventListener === "undefined") return () => {};
|
|
2121
|
+
const onOnline = () => this.setOnline(true);
|
|
2122
|
+
const onOffline = () => this.setOnline(false);
|
|
2123
|
+
window.addEventListener("online", onOnline, false);
|
|
2124
|
+
window.addEventListener("offline", onOffline, false);
|
|
2125
|
+
return () => {
|
|
2126
|
+
window.removeEventListener("online", onOnline, false);
|
|
2127
|
+
window.removeEventListener("offline", onOffline, false);
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
function getGlobalOnlineManager() {
|
|
2132
|
+
if (!globalThis[kOnlineManager]) globalThis[kOnlineManager] = new WindowOnlineManager();
|
|
2133
|
+
return globalThis[kOnlineManager];
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
//#endregion
|
|
2137
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/query.mjs
|
|
2138
|
+
const isServer$1 = () => typeof window === "undefined";
|
|
2139
|
+
function isAuthQueryStateEqual(a, b) {
|
|
2140
|
+
return isJsonEqual(a.data, b.data) && a.error === b.error && a.isPending === b.isPending && a.isRefetching === b.isRefetching && a.refetch === b.refetch;
|
|
2141
|
+
}
|
|
2142
|
+
const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
2143
|
+
const value = /* @__PURE__ */ atom({
|
|
2144
|
+
data: null,
|
|
2145
|
+
error: null,
|
|
2146
|
+
isPending: true,
|
|
2147
|
+
isRefetching: false,
|
|
2148
|
+
refetch: (queryParams) => fn(queryParams)
|
|
2149
|
+
});
|
|
2150
|
+
withEquality(value, isAuthQueryStateEqual);
|
|
2151
|
+
const fn = async (queryParams) => {
|
|
2152
|
+
return new Promise((resolve) => {
|
|
2153
|
+
const opts = typeof options === "function" ? options({
|
|
2154
|
+
data: value.get().data,
|
|
2155
|
+
error: value.get().error,
|
|
2156
|
+
isPending: value.get().isPending
|
|
2157
|
+
}) : options;
|
|
2158
|
+
$fetch(path, {
|
|
2159
|
+
...opts,
|
|
2160
|
+
query: {
|
|
2161
|
+
...opts?.query,
|
|
2162
|
+
...queryParams?.query
|
|
2163
|
+
},
|
|
2164
|
+
async onSuccess(context) {
|
|
2165
|
+
const current = value.get();
|
|
2166
|
+
const stableData = current.data != null && context.data != null && isJsonEqual(current.data, context.data) ? current.data : context.data;
|
|
2167
|
+
value.set({
|
|
2168
|
+
data: stableData,
|
|
2169
|
+
error: null,
|
|
2170
|
+
isPending: false,
|
|
2171
|
+
isRefetching: false,
|
|
2172
|
+
refetch: value.value.refetch
|
|
2173
|
+
});
|
|
2174
|
+
await opts?.onSuccess?.(context);
|
|
2175
|
+
},
|
|
2176
|
+
async onError(context) {
|
|
2177
|
+
const { request } = context;
|
|
2178
|
+
const retryAttempts = typeof request.retry === "number" ? request.retry : request.retry?.attempts;
|
|
2179
|
+
const retryAttempt = request.retryAttempt || 0;
|
|
2180
|
+
if (retryAttempts && retryAttempt < retryAttempts) return;
|
|
2181
|
+
const isUnauthorized = context.error.status === 401;
|
|
2182
|
+
value.set({
|
|
2183
|
+
error: context.error,
|
|
2184
|
+
data: isUnauthorized ? null : value.get().data,
|
|
2185
|
+
isPending: false,
|
|
2186
|
+
isRefetching: false,
|
|
2187
|
+
refetch: value.value.refetch
|
|
2188
|
+
});
|
|
2189
|
+
await opts?.onError?.(context);
|
|
2190
|
+
},
|
|
2191
|
+
async onRequest(context) {
|
|
2192
|
+
const currentValue = value.get();
|
|
2193
|
+
value.set({
|
|
2194
|
+
isPending: currentValue.data === null,
|
|
2195
|
+
data: currentValue.data,
|
|
2196
|
+
error: null,
|
|
2197
|
+
isRefetching: true,
|
|
2198
|
+
refetch: value.value.refetch
|
|
2199
|
+
});
|
|
2200
|
+
await opts?.onRequest?.(context);
|
|
2201
|
+
}
|
|
2202
|
+
}).catch((error) => {
|
|
2203
|
+
value.set({
|
|
2204
|
+
error,
|
|
2205
|
+
data: value.get().data,
|
|
2206
|
+
isPending: false,
|
|
2207
|
+
isRefetching: false,
|
|
2208
|
+
refetch: value.value.refetch
|
|
2209
|
+
});
|
|
2210
|
+
}).finally(() => {
|
|
2211
|
+
resolve(void 0);
|
|
2212
|
+
});
|
|
2213
|
+
});
|
|
2214
|
+
};
|
|
2215
|
+
initializedAtom = Array.isArray(initializedAtom) ? initializedAtom : [initializedAtom];
|
|
2216
|
+
let isMountFetchPending = false;
|
|
2217
|
+
let isMounted = false;
|
|
2218
|
+
let shouldRefetchAfterPending = false;
|
|
2219
|
+
const fetchOnMount = () => {
|
|
2220
|
+
if (isMountFetchPending) {
|
|
2221
|
+
shouldRefetchAfterPending = true;
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
isMountFetchPending = true;
|
|
2225
|
+
fn().finally(() => {
|
|
2226
|
+
isMountFetchPending = false;
|
|
2227
|
+
const shouldRefetch = shouldRefetchAfterPending && isMounted;
|
|
2228
|
+
shouldRefetchAfterPending = false;
|
|
2229
|
+
if (shouldRefetch) fetchOnMount();
|
|
2230
|
+
});
|
|
2231
|
+
};
|
|
2232
|
+
onMount(value, () => {
|
|
2233
|
+
if (isServer$1()) return;
|
|
2234
|
+
isMounted = true;
|
|
2235
|
+
let isInitialized = false;
|
|
2236
|
+
let timeoutId;
|
|
2237
|
+
const cleanups = initializedAtom.map((initAtom) => initAtom.listen(() => {
|
|
2238
|
+
if (isInitialized) fn();
|
|
2239
|
+
else {
|
|
2240
|
+
isInitialized = true;
|
|
2241
|
+
clearTimeout(timeoutId);
|
|
2242
|
+
fetchOnMount();
|
|
2243
|
+
}
|
|
2244
|
+
}));
|
|
2245
|
+
timeoutId = setTimeout(() => {
|
|
2246
|
+
isInitialized = true;
|
|
2247
|
+
fetchOnMount();
|
|
2248
|
+
}, 0);
|
|
2249
|
+
return () => {
|
|
2250
|
+
isMounted = false;
|
|
2251
|
+
for (const cleanup of cleanups) cleanup();
|
|
2252
|
+
clearTimeout(timeoutId);
|
|
2253
|
+
};
|
|
2254
|
+
});
|
|
2255
|
+
return value;
|
|
2256
|
+
};
|
|
2257
|
+
|
|
2258
|
+
//#endregion
|
|
2259
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/session-refresh.mjs
|
|
2260
|
+
const now = () => Math.floor(Date.now() / 1e3);
|
|
2261
|
+
/**
|
|
2262
|
+
* Rate limit: don't refetch on focus if a session request was made within this many seconds
|
|
2263
|
+
*/
|
|
2264
|
+
const FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;
|
|
2265
|
+
function createSessionRefreshManager(opts) {
|
|
2266
|
+
const { fetchSession, shouldPollSession = () => true, sessionSignal, options = {} } = opts;
|
|
2267
|
+
const refetchInterval = options.sessionOptions?.refetchInterval ?? 0;
|
|
2268
|
+
const refetchOnWindowFocus = options.sessionOptions?.refetchOnWindowFocus ?? true;
|
|
2269
|
+
const refetchWhenOffline = options.sessionOptions?.refetchWhenOffline ?? false;
|
|
2270
|
+
const state = {
|
|
2271
|
+
isInitialized: false,
|
|
2272
|
+
lastSessionRequest: 0
|
|
2273
|
+
};
|
|
2274
|
+
const shouldRefetch = () => {
|
|
2275
|
+
return refetchWhenOffline || getGlobalOnlineManager().isOnline;
|
|
2276
|
+
};
|
|
2277
|
+
const triggerRefetch = (event) => {
|
|
2278
|
+
if (!shouldRefetch()) return;
|
|
2279
|
+
if (event?.event === "storage") {
|
|
2280
|
+
fetchSession();
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
if (event?.event === "poll") {
|
|
2284
|
+
state.lastSessionRequest = now();
|
|
2285
|
+
fetchSession();
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
if (event?.event === "visibilitychange") {
|
|
2289
|
+
if (now() - state.lastSessionRequest < FOCUS_REFETCH_RATE_LIMIT_SECONDS) return;
|
|
2290
|
+
state.lastSessionRequest = now();
|
|
2291
|
+
fetchSession();
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
fetchSession();
|
|
2295
|
+
};
|
|
2296
|
+
const broadcastSessionUpdate = (trigger) => {
|
|
2297
|
+
getGlobalBroadcastChannel().post({
|
|
2298
|
+
event: "session",
|
|
2299
|
+
data: { trigger },
|
|
2300
|
+
clientId: Math.random().toString(36).substring(7)
|
|
2301
|
+
});
|
|
2302
|
+
};
|
|
2303
|
+
const setupPolling = () => {
|
|
2304
|
+
if (refetchInterval && refetchInterval > 0) state.pollInterval = setInterval(() => {
|
|
2305
|
+
if (shouldPollSession()) triggerRefetch({ event: "poll" });
|
|
2306
|
+
}, refetchInterval * 1e3);
|
|
2307
|
+
};
|
|
2308
|
+
const setupBroadcast = () => {
|
|
2309
|
+
state.unsubscribeBroadcast = getGlobalBroadcastChannel().subscribe(() => {
|
|
2310
|
+
triggerRefetch({ event: "storage" });
|
|
2311
|
+
});
|
|
2312
|
+
};
|
|
2313
|
+
const setupFocusRefetch = () => {
|
|
2314
|
+
if (!refetchOnWindowFocus) return;
|
|
2315
|
+
state.unsubscribeFocus = getGlobalFocusManager().subscribe(() => {
|
|
2316
|
+
triggerRefetch({ event: "visibilitychange" });
|
|
2317
|
+
});
|
|
2318
|
+
};
|
|
2319
|
+
const setupOnlineRefetch = () => {
|
|
2320
|
+
state.unsubscribeOnline = getGlobalOnlineManager().subscribe((online) => {
|
|
2321
|
+
if (online) triggerRefetch({ event: "visibilitychange" });
|
|
2322
|
+
});
|
|
2323
|
+
};
|
|
2324
|
+
const setupSignalSubscription = () => {
|
|
2325
|
+
state.unsubscribeSignal = sessionSignal.listen(() => {
|
|
2326
|
+
fetchSession();
|
|
2327
|
+
});
|
|
2328
|
+
};
|
|
2329
|
+
const init = () => {
|
|
2330
|
+
if (state.isInitialized) return;
|
|
2331
|
+
state.isInitialized = true;
|
|
2332
|
+
setupPolling();
|
|
2333
|
+
setupBroadcast();
|
|
2334
|
+
setupFocusRefetch();
|
|
2335
|
+
setupOnlineRefetch();
|
|
2336
|
+
setupSignalSubscription();
|
|
2337
|
+
state.cleanupBroadcastSetup = getGlobalBroadcastChannel().setup();
|
|
2338
|
+
state.cleanupFocusSetup = getGlobalFocusManager().setup();
|
|
2339
|
+
state.cleanupOnlineSetup = getGlobalOnlineManager().setup();
|
|
2340
|
+
};
|
|
2341
|
+
const cleanup = () => {
|
|
2342
|
+
if (!state.isInitialized) return;
|
|
2343
|
+
if (state.pollInterval) {
|
|
2344
|
+
clearInterval(state.pollInterval);
|
|
2345
|
+
state.pollInterval = void 0;
|
|
2346
|
+
}
|
|
2347
|
+
if (state.unsubscribeBroadcast) {
|
|
2348
|
+
state.unsubscribeBroadcast();
|
|
2349
|
+
state.unsubscribeBroadcast = void 0;
|
|
2350
|
+
}
|
|
2351
|
+
if (state.unsubscribeFocus) {
|
|
2352
|
+
state.unsubscribeFocus();
|
|
2353
|
+
state.unsubscribeFocus = void 0;
|
|
2354
|
+
}
|
|
2355
|
+
if (state.unsubscribeOnline) {
|
|
2356
|
+
state.unsubscribeOnline();
|
|
2357
|
+
state.unsubscribeOnline = void 0;
|
|
2358
|
+
}
|
|
2359
|
+
if (state.unsubscribeSignal) {
|
|
2360
|
+
state.unsubscribeSignal();
|
|
2361
|
+
state.unsubscribeSignal = void 0;
|
|
2362
|
+
}
|
|
2363
|
+
if (state.cleanupBroadcastSetup) {
|
|
2364
|
+
state.cleanupBroadcastSetup();
|
|
2365
|
+
state.cleanupBroadcastSetup = void 0;
|
|
2366
|
+
}
|
|
2367
|
+
if (state.cleanupFocusSetup) {
|
|
2368
|
+
state.cleanupFocusSetup();
|
|
2369
|
+
state.cleanupFocusSetup = void 0;
|
|
2370
|
+
}
|
|
2371
|
+
if (state.cleanupOnlineSetup) {
|
|
2372
|
+
state.cleanupOnlineSetup();
|
|
2373
|
+
state.cleanupOnlineSetup = void 0;
|
|
2374
|
+
}
|
|
2375
|
+
state.isInitialized = false;
|
|
2376
|
+
state.lastSessionRequest = 0;
|
|
2377
|
+
};
|
|
2378
|
+
return {
|
|
2379
|
+
init,
|
|
2380
|
+
cleanup,
|
|
2381
|
+
triggerRefetch,
|
|
2382
|
+
broadcastSessionUpdate
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
//#endregion
|
|
2387
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/fetch-plugins.mjs
|
|
2388
|
+
const redirectPlugin = {
|
|
2389
|
+
id: "redirect",
|
|
2390
|
+
name: "Redirect",
|
|
2391
|
+
hooks: { onSuccess(context) {
|
|
2392
|
+
if (context.data?.url && context.data?.redirect && isSafeUrlScheme(context.data.url)) {
|
|
2393
|
+
if (typeof window !== "undefined" && window.location) {
|
|
2394
|
+
if (window.location) try {
|
|
2395
|
+
window.location.href = context.data.url;
|
|
2396
|
+
} catch {}
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
} }
|
|
2400
|
+
};
|
|
2401
|
+
|
|
2402
|
+
//#endregion
|
|
2403
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/session-atom.mjs
|
|
2404
|
+
const isServer = () => typeof window === "undefined";
|
|
2405
|
+
/**
|
|
2406
|
+
* Normalize $fetch response: `throw: true` returns data directly,
|
|
2407
|
+
* otherwise `{ data, error }`.
|
|
2408
|
+
*/
|
|
2409
|
+
function normalizeSessionResponse(res) {
|
|
2410
|
+
if (typeof res === "object" && res !== null && "data" in res && "error" in res) return res;
|
|
2411
|
+
return {
|
|
2412
|
+
data: res,
|
|
2413
|
+
error: null
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
function normalizeSessionData(data) {
|
|
2417
|
+
if (!data) return null;
|
|
2418
|
+
if (data.session === null && data.user === null) return null;
|
|
2419
|
+
return data;
|
|
2420
|
+
}
|
|
2421
|
+
function isSessionAtomEqual(a, b) {
|
|
2422
|
+
return isJsonEqual(a.data, b.data) && a.error === b.error && a.isPending === b.isPending && a.isRefetching === b.isRefetching && a.refetch === b.refetch;
|
|
2423
|
+
}
|
|
2424
|
+
function getSessionAtom($fetch, options) {
|
|
2425
|
+
const $signal = /* @__PURE__ */ atom(false);
|
|
2426
|
+
let abortController;
|
|
2427
|
+
const refetch = (queryParams) => fetchSession(queryParams);
|
|
2428
|
+
const session = /* @__PURE__ */ atom({
|
|
2429
|
+
data: null,
|
|
2430
|
+
error: null,
|
|
2431
|
+
isPending: true,
|
|
2432
|
+
isRefetching: false,
|
|
2433
|
+
refetch
|
|
2434
|
+
});
|
|
2435
|
+
withEquality(session, isSessionAtomEqual);
|
|
2436
|
+
const settleAbortedFetch = (controller) => {
|
|
2437
|
+
if (abortController !== controller) return;
|
|
2438
|
+
const current = session.get();
|
|
2439
|
+
abortController = void 0;
|
|
2440
|
+
if (!current.isPending && !current.isRefetching) return;
|
|
2441
|
+
session.set({
|
|
2442
|
+
...current,
|
|
2443
|
+
isPending: false,
|
|
2444
|
+
isRefetching: false,
|
|
2445
|
+
refetch
|
|
2446
|
+
});
|
|
2447
|
+
};
|
|
2448
|
+
const fetchSession = async (queryParams) => {
|
|
2449
|
+
abortController?.abort();
|
|
2450
|
+
const controller = new AbortController();
|
|
2451
|
+
abortController = controller;
|
|
2452
|
+
const current = session.get();
|
|
2453
|
+
session.set({
|
|
2454
|
+
...current,
|
|
2455
|
+
isPending: current.data === null,
|
|
2456
|
+
isRefetching: true,
|
|
2457
|
+
error: null,
|
|
2458
|
+
refetch
|
|
2459
|
+
});
|
|
2460
|
+
try {
|
|
2461
|
+
const res = await $fetch("/get-session", {
|
|
2462
|
+
method: "GET",
|
|
2463
|
+
query: queryParams?.query,
|
|
2464
|
+
signal: controller.signal
|
|
2465
|
+
});
|
|
2466
|
+
if (controller.signal.aborted) {
|
|
2467
|
+
settleAbortedFetch(controller);
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
let { data, error } = normalizeSessionResponse(res);
|
|
2471
|
+
if (data?.needsRefresh) try {
|
|
2472
|
+
const refreshRes = await $fetch("/get-session", {
|
|
2473
|
+
method: "POST",
|
|
2474
|
+
signal: controller.signal
|
|
2475
|
+
});
|
|
2476
|
+
if (controller.signal.aborted) {
|
|
2477
|
+
settleAbortedFetch(controller);
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
({data, error} = normalizeSessionResponse(refreshRes));
|
|
2481
|
+
} catch {
|
|
2482
|
+
if (controller.signal.aborted) {
|
|
2483
|
+
settleAbortedFetch(controller);
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
if (error) {
|
|
2488
|
+
const latest = session.get();
|
|
2489
|
+
const isUnauthorized = error?.status === 401;
|
|
2490
|
+
session.set({
|
|
2491
|
+
data: isUnauthorized ? null : latest.data,
|
|
2492
|
+
error,
|
|
2493
|
+
isPending: false,
|
|
2494
|
+
isRefetching: false,
|
|
2495
|
+
refetch
|
|
2496
|
+
});
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2499
|
+
const sessionData = normalizeSessionData(data);
|
|
2500
|
+
const current = session.get();
|
|
2501
|
+
const stableData = current.data != null && sessionData != null && isJsonEqual(current.data, sessionData) ? current.data : sessionData;
|
|
2502
|
+
session.set({
|
|
2503
|
+
data: stableData,
|
|
2504
|
+
error: null,
|
|
2505
|
+
isPending: false,
|
|
2506
|
+
isRefetching: false,
|
|
2507
|
+
refetch
|
|
2508
|
+
});
|
|
2509
|
+
} catch (fetchError) {
|
|
2510
|
+
if (controller.signal.aborted) {
|
|
2511
|
+
settleAbortedFetch(controller);
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
const latest = session.get();
|
|
2515
|
+
session.set({
|
|
2516
|
+
data: latest.data,
|
|
2517
|
+
error: fetchError,
|
|
2518
|
+
isPending: false,
|
|
2519
|
+
isRefetching: false,
|
|
2520
|
+
refetch
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
let broadcastSessionUpdate = () => {};
|
|
2525
|
+
onMount(session, () => {
|
|
2526
|
+
let timeoutId;
|
|
2527
|
+
if (!isServer()) timeoutId = setTimeout(() => {
|
|
2528
|
+
fetchSession();
|
|
2529
|
+
}, 0);
|
|
2530
|
+
const refreshManager = createSessionRefreshManager({
|
|
2531
|
+
fetchSession,
|
|
2532
|
+
shouldPollSession: () => session.get().data != null,
|
|
2533
|
+
sessionSignal: $signal,
|
|
2534
|
+
options
|
|
2535
|
+
});
|
|
2536
|
+
refreshManager.init();
|
|
2537
|
+
broadcastSessionUpdate = refreshManager.broadcastSessionUpdate;
|
|
2538
|
+
return () => {
|
|
2539
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
2540
|
+
const controller = abortController;
|
|
2541
|
+
controller?.abort();
|
|
2542
|
+
if (controller) settleAbortedFetch(controller);
|
|
2543
|
+
refreshManager.cleanup();
|
|
2544
|
+
};
|
|
2545
|
+
});
|
|
2546
|
+
return {
|
|
2547
|
+
session,
|
|
2548
|
+
$sessionSignal: $signal,
|
|
2549
|
+
broadcastSessionUpdate: (trigger) => broadcastSessionUpdate(trigger)
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
//#endregion
|
|
2554
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/config.mjs
|
|
2555
|
+
const resolvePublicAuthUrl = (basePath) => {
|
|
2556
|
+
if (typeof process === "undefined") return void 0;
|
|
2557
|
+
const path = basePath ?? "/api/auth";
|
|
2558
|
+
if (process.env.NEXT_PUBLIC_AUTH_URL) return process.env.NEXT_PUBLIC_AUTH_URL;
|
|
2559
|
+
if (typeof window === "undefined") {
|
|
2560
|
+
if (process.env.NEXTAUTH_URL) try {
|
|
2561
|
+
return process.env.NEXTAUTH_URL;
|
|
2562
|
+
} catch {}
|
|
2563
|
+
if (process.env.VERCEL_URL) try {
|
|
2564
|
+
const protocol = process.env.VERCEL_URL.startsWith("http") ? "" : "https://";
|
|
2565
|
+
return `${new URL(`${protocol}${process.env.VERCEL_URL}`).origin}${path}`;
|
|
2566
|
+
} catch {}
|
|
2567
|
+
}
|
|
2568
|
+
};
|
|
2569
|
+
const getClientConfig = (options, loadEnv) => {
|
|
2570
|
+
const isCredentialsSupported = "credentials" in Request.prototype;
|
|
2571
|
+
const baseURL = getBaseURL(options?.baseURL, options?.basePath, void 0, loadEnv) ?? resolvePublicAuthUrl(options?.basePath) ?? "/api/auth";
|
|
2572
|
+
const pluginsFetchPlugins = options?.plugins?.flatMap((plugin) => plugin.fetchPlugins).filter((pl) => pl !== void 0) || [];
|
|
2573
|
+
const lifeCyclePlugin = {
|
|
2574
|
+
id: "lifecycle-hooks",
|
|
2575
|
+
name: "lifecycle-hooks",
|
|
2576
|
+
hooks: {
|
|
2577
|
+
onSuccess: options?.fetchOptions?.onSuccess,
|
|
2578
|
+
onError: options?.fetchOptions?.onError,
|
|
2579
|
+
onRequest: options?.fetchOptions?.onRequest,
|
|
2580
|
+
onResponse: options?.fetchOptions?.onResponse
|
|
2581
|
+
}
|
|
2582
|
+
};
|
|
2583
|
+
const { onSuccess: _onSuccess, onError: _onError, onRequest: _onRequest, onResponse: _onResponse, ...restOfFetchOptions } = options?.fetchOptions || {};
|
|
2584
|
+
const $fetch = createFetch({
|
|
2585
|
+
baseURL,
|
|
2586
|
+
...isCredentialsSupported ? { credentials: "include" } : {},
|
|
2587
|
+
method: "GET",
|
|
2588
|
+
jsonParser(text) {
|
|
2589
|
+
if (!text) return null;
|
|
2590
|
+
return parseJSON(text, { strict: false });
|
|
2591
|
+
},
|
|
2592
|
+
customFetchImpl: fetch,
|
|
2593
|
+
...restOfFetchOptions,
|
|
2594
|
+
plugins: [
|
|
2595
|
+
lifeCyclePlugin,
|
|
2596
|
+
...restOfFetchOptions.plugins || [],
|
|
2597
|
+
...options?.disableDefaultFetchPlugins ? [] : [redirectPlugin],
|
|
2598
|
+
...pluginsFetchPlugins
|
|
2599
|
+
]
|
|
2600
|
+
});
|
|
2601
|
+
const { $sessionSignal, session, broadcastSessionUpdate } = getSessionAtom($fetch, options);
|
|
2602
|
+
const plugins = options?.plugins || [];
|
|
2603
|
+
let pluginsActions = {};
|
|
2604
|
+
const pluginsAtoms = {
|
|
2605
|
+
$sessionSignal,
|
|
2606
|
+
session
|
|
2607
|
+
};
|
|
2608
|
+
const pluginPathMethods = {
|
|
2609
|
+
"/sign-out": "POST",
|
|
2610
|
+
"/revoke-sessions": "POST",
|
|
2611
|
+
"/revoke-other-sessions": "POST",
|
|
2612
|
+
"/delete-user": "POST"
|
|
2613
|
+
};
|
|
2614
|
+
const atomListeners = [{
|
|
2615
|
+
signal: "$sessionSignal",
|
|
2616
|
+
matcher(path) {
|
|
2617
|
+
return path === "/sign-out" || path === "/update-user" || path === "/update-session" || path === "/sign-up/email" || path === "/sign-in/email" || path === "/delete-user" || path === "/verify-email" || path === "/revoke-sessions" || path === "/revoke-session" || path === "/revoke-other-sessions" || path === "/change-email" || path === "/change-password";
|
|
2618
|
+
},
|
|
2619
|
+
callback(path) {
|
|
2620
|
+
if (path === "/sign-out") broadcastSessionUpdate("signout");
|
|
2621
|
+
else if (path === "/update-user" || path === "/update-session") broadcastSessionUpdate("updateUser");
|
|
2622
|
+
}
|
|
2623
|
+
}];
|
|
2624
|
+
for (const plugin of plugins) {
|
|
2625
|
+
if (plugin.getAtoms) Object.assign(pluginsAtoms, plugin.getAtoms?.($fetch));
|
|
2626
|
+
if (plugin.pathMethods) Object.assign(pluginPathMethods, plugin.pathMethods);
|
|
2627
|
+
if (plugin.atomListeners) atomListeners.push(...plugin.atomListeners);
|
|
2628
|
+
}
|
|
2629
|
+
const $store = {
|
|
2630
|
+
notify: (signal) => {
|
|
2631
|
+
pluginsAtoms[signal].set(!pluginsAtoms[signal].get());
|
|
2632
|
+
},
|
|
2633
|
+
listen: (signal, listener) => {
|
|
2634
|
+
pluginsAtoms[signal].subscribe(listener);
|
|
2635
|
+
},
|
|
2636
|
+
atoms: pluginsAtoms
|
|
2637
|
+
};
|
|
2638
|
+
for (const plugin of plugins) if (plugin.getActions) pluginsActions = defu(plugin.getActions?.($fetch, $store, options) ?? {}, pluginsActions);
|
|
2639
|
+
return {
|
|
2640
|
+
get baseURL() {
|
|
2641
|
+
return baseURL;
|
|
2642
|
+
},
|
|
2643
|
+
pluginsActions,
|
|
2644
|
+
pluginsAtoms,
|
|
2645
|
+
pluginPathMethods,
|
|
2646
|
+
atomListeners,
|
|
2647
|
+
$fetch,
|
|
2648
|
+
$store
|
|
2649
|
+
};
|
|
2650
|
+
};
|
|
2651
|
+
|
|
2652
|
+
//#endregion
|
|
2653
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/utils/is-atom.mjs
|
|
2654
|
+
function isAtom(value) {
|
|
2655
|
+
return typeof value === "object" && value !== null && "get" in value && typeof value.get === "function" && "lc" in value && typeof value.lc === "number";
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
//#endregion
|
|
2659
|
+
//#region ../../node_modules/.pnpm/@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fetch+fetch@1.3.1_@openteleme_39d811f210df3a5f20302036ab91db01/node_modules/@better-auth/core/dist/utils/string.mjs
|
|
2660
|
+
function capitalizeFirstLetter(str) {
|
|
2661
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2662
|
+
}
|
|
2663
|
+
const WORD_PATTERN = /[\p{Ll}\d]+|\p{Lu}+(?!\p{Ll})|\p{Lu}[\p{Ll}\d]+|\p{Lo}+/gu;
|
|
2664
|
+
const APOSTROPHE_PATTERN = /['\u2019]/g;
|
|
2665
|
+
function splitWords(input) {
|
|
2666
|
+
return input.replace(APOSTROPHE_PATTERN, "").match(WORD_PATTERN) ?? [];
|
|
2667
|
+
}
|
|
2668
|
+
function toKebabCase(input) {
|
|
2669
|
+
return splitWords(input).map((word) => word.toLowerCase()).join("-");
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
//#endregion
|
|
2673
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/proxy.mjs
|
|
2674
|
+
function getMethod(path, knownPathMethods, args) {
|
|
2675
|
+
const method = knownPathMethods[path];
|
|
2676
|
+
const { fetchOptions, query: _query, ...body } = args || {};
|
|
2677
|
+
if (method) return method;
|
|
2678
|
+
if (fetchOptions?.method) return fetchOptions.method;
|
|
2679
|
+
if (body && Object.keys(body).length > 0) return "POST";
|
|
2680
|
+
return "GET";
|
|
2681
|
+
}
|
|
2682
|
+
function createDynamicPathProxy(routes, client, knownPathMethods, atoms, atomListeners) {
|
|
2683
|
+
function createProxy(path = []) {
|
|
2684
|
+
return new Proxy(function() {}, {
|
|
2685
|
+
get(_, prop) {
|
|
2686
|
+
if (typeof prop !== "string") return;
|
|
2687
|
+
if (prop === "then" || prop === "catch" || prop === "finally") return;
|
|
2688
|
+
const fullPath = [...path, prop];
|
|
2689
|
+
let current = routes;
|
|
2690
|
+
for (const segment of fullPath) if (current && typeof current === "object" && segment in current) current = current[segment];
|
|
2691
|
+
else {
|
|
2692
|
+
current = void 0;
|
|
2693
|
+
break;
|
|
2694
|
+
}
|
|
2695
|
+
if (typeof current === "function") return current;
|
|
2696
|
+
if (isAtom(current)) return current;
|
|
2697
|
+
return createProxy(fullPath);
|
|
2698
|
+
},
|
|
2699
|
+
apply: async (_, __, args) => {
|
|
2700
|
+
const routePath = "/" + path.map(toKebabCase).join("/");
|
|
2701
|
+
const arg = args[0] || {};
|
|
2702
|
+
const fetchOptions = args[1] || {};
|
|
2703
|
+
const { query, fetchOptions: argFetchOptions, ...body } = arg;
|
|
2704
|
+
const options = {
|
|
2705
|
+
...fetchOptions,
|
|
2706
|
+
...argFetchOptions
|
|
2707
|
+
};
|
|
2708
|
+
const method = getMethod(routePath, knownPathMethods, arg);
|
|
2709
|
+
return await client(routePath, {
|
|
2710
|
+
...options,
|
|
2711
|
+
body: method === "GET" ? void 0 : {
|
|
2712
|
+
...body,
|
|
2713
|
+
...options?.body || {}
|
|
2714
|
+
},
|
|
2715
|
+
query: query || options?.query,
|
|
2716
|
+
method,
|
|
2717
|
+
async onSuccess(context) {
|
|
2718
|
+
await options?.onSuccess?.(context);
|
|
2719
|
+
if (!atomListeners || options.disableSignal) return;
|
|
2720
|
+
/**
|
|
2721
|
+
* We trigger listeners
|
|
2722
|
+
*/
|
|
2723
|
+
const matches = atomListeners.filter((s) => s.matcher(routePath));
|
|
2724
|
+
if (!matches.length) return;
|
|
2725
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2726
|
+
for (const match of matches) {
|
|
2727
|
+
const signal = atoms[match.signal];
|
|
2728
|
+
if (!signal) return;
|
|
2729
|
+
if (visited.has(match.signal)) continue;
|
|
2730
|
+
visited.add(match.signal);
|
|
2731
|
+
/**
|
|
2732
|
+
* To avoid race conditions we set the signal in a setTimeout
|
|
2733
|
+
*/
|
|
2734
|
+
const val = signal.get();
|
|
2735
|
+
setTimeout(() => {
|
|
2736
|
+
signal.set(!val);
|
|
2737
|
+
}, 10);
|
|
2738
|
+
match.callback?.(routePath);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
return createProxy();
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
//#endregion
|
|
2749
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/client/vanilla.mjs
|
|
2750
|
+
function createAuthClient(options) {
|
|
2751
|
+
const { pluginPathMethods, pluginsActions, pluginsAtoms, $fetch, atomListeners, $store } = getClientConfig(options);
|
|
2752
|
+
const resolvedHooks = {};
|
|
2753
|
+
for (const [key, value] of Object.entries(pluginsAtoms)) resolvedHooks[`use${capitalizeFirstLetter(key)}`] = value;
|
|
2754
|
+
return createDynamicPathProxy({
|
|
2755
|
+
...pluginsActions,
|
|
2756
|
+
...resolvedHooks,
|
|
2757
|
+
$fetch,
|
|
2758
|
+
$store
|
|
2759
|
+
}, $fetch, pluginPathMethods, pluginsAtoms, atomListeners);
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
//#endregion
|
|
2763
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/additional-fields/client.mjs
|
|
2764
|
+
const inferAdditionalFields = (schema) => {
|
|
2765
|
+
return {
|
|
2766
|
+
id: "additional-fields-client",
|
|
2767
|
+
version: PACKAGE_VERSION$1,
|
|
2768
|
+
$InferServerPlugin: {}
|
|
2769
|
+
};
|
|
2770
|
+
};
|
|
2771
|
+
|
|
2772
|
+
//#endregion
|
|
2773
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/admin/client.mjs
|
|
2774
|
+
const adminClient = (options) => {
|
|
2775
|
+
const roles = {
|
|
2776
|
+
admin: adminAc$1,
|
|
2777
|
+
user: userAc,
|
|
2778
|
+
...options?.roles
|
|
2779
|
+
};
|
|
2780
|
+
return {
|
|
2781
|
+
id: "admin-client",
|
|
2782
|
+
version: PACKAGE_VERSION$1,
|
|
2783
|
+
$InferServerPlugin: {},
|
|
2784
|
+
getActions: () => ({ admin: { checkRolePermission: (data) => {
|
|
2785
|
+
return hasPermission({
|
|
2786
|
+
role: data.role,
|
|
2787
|
+
options: {
|
|
2788
|
+
ac: options?.ac,
|
|
2789
|
+
roles
|
|
2790
|
+
},
|
|
2791
|
+
permissions: data.permissions
|
|
2792
|
+
});
|
|
2793
|
+
} } }),
|
|
2794
|
+
pathMethods: {
|
|
2795
|
+
"/admin/list-users": "GET",
|
|
2796
|
+
"/admin/impersonate-user": "POST",
|
|
2797
|
+
"/admin/stop-impersonating": "POST"
|
|
2798
|
+
},
|
|
2799
|
+
atomListeners: [{
|
|
2800
|
+
matcher: (path) => path === "/admin/impersonate-user" || path === "/admin/stop-impersonating",
|
|
2801
|
+
signal: "$sessionSignal"
|
|
2802
|
+
}],
|
|
2803
|
+
$ERROR_CODES: ADMIN_ERROR_CODES
|
|
2804
|
+
};
|
|
2805
|
+
};
|
|
2806
|
+
|
|
2807
|
+
//#endregion
|
|
2808
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/device-authorization/client.mjs
|
|
2809
|
+
const deviceAuthorizationClient = () => {
|
|
2810
|
+
return {
|
|
2811
|
+
id: "device-authorization",
|
|
2812
|
+
version: PACKAGE_VERSION$1,
|
|
2813
|
+
$InferServerPlugin: {},
|
|
2814
|
+
pathMethods: {
|
|
2815
|
+
"/device/code": "POST",
|
|
2816
|
+
"/device/token": "POST",
|
|
2817
|
+
"/device": "GET",
|
|
2818
|
+
"/device/approve": "POST",
|
|
2819
|
+
"/device/deny": "POST"
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
};
|
|
2823
|
+
|
|
2824
|
+
//#endregion
|
|
2825
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.26_@opentelemetry+api@1.9.1_drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1_56a4a2a6caec5e04d8eab345894c8059/node_modules/better-auth/dist/plugins/organization/client.mjs
|
|
2826
|
+
/**
|
|
2827
|
+
* Using the same `hasPermissionFn` function, but without the need for a `ctx` parameter or the `organizationId` parameter.
|
|
2828
|
+
*/
|
|
2829
|
+
const clientSideHasPermission = (input) => {
|
|
2830
|
+
return hasPermissionFn(input, input.options.roles || defaultRoles);
|
|
2831
|
+
};
|
|
2832
|
+
const organizationClient = (options) => {
|
|
2833
|
+
const $listOrg = /* @__PURE__ */ atom(false);
|
|
2834
|
+
const $activeOrgSignal = /* @__PURE__ */ atom(false);
|
|
2835
|
+
const $activeMemberSignal = /* @__PURE__ */ atom(false);
|
|
2836
|
+
const $activeMemberRoleSignal = /* @__PURE__ */ atom(false);
|
|
2837
|
+
const roles = {
|
|
2838
|
+
admin: adminAc,
|
|
2839
|
+
member: memberAc,
|
|
2840
|
+
owner: ownerAc,
|
|
2841
|
+
...options?.roles
|
|
2842
|
+
};
|
|
2843
|
+
return {
|
|
2844
|
+
id: "organization",
|
|
2845
|
+
version: PACKAGE_VERSION$1,
|
|
2846
|
+
$InferServerPlugin: {},
|
|
2847
|
+
getActions: ($fetch, _$store, co) => ({
|
|
2848
|
+
$Infer: {
|
|
2849
|
+
ActiveOrganization: {},
|
|
2850
|
+
Organization: {},
|
|
2851
|
+
Invitation: {},
|
|
2852
|
+
Member: {},
|
|
2853
|
+
Team: {}
|
|
2854
|
+
},
|
|
2855
|
+
organization: { checkRolePermission: (data) => {
|
|
2856
|
+
return clientSideHasPermission({
|
|
2857
|
+
role: data.role,
|
|
2858
|
+
options: {
|
|
2859
|
+
ac: options?.ac,
|
|
2860
|
+
roles
|
|
2861
|
+
},
|
|
2862
|
+
permissions: data.permissions
|
|
2863
|
+
});
|
|
2864
|
+
} }
|
|
2865
|
+
}),
|
|
2866
|
+
getAtoms: ($fetch) => {
|
|
2867
|
+
const listOrganizations = useAuthQuery($listOrg, "/organization/list", $fetch, { method: "GET" });
|
|
2868
|
+
const activeOrganization = useAuthQuery([$activeOrgSignal], "/organization/get-full-organization", $fetch, () => ({ method: "GET" }));
|
|
2869
|
+
const activeMember = useAuthQuery([$activeOrgSignal, $activeMemberSignal], "/organization/get-active-member", $fetch, { method: "GET" });
|
|
2870
|
+
const activeMemberRole = useAuthQuery([$activeOrgSignal, $activeMemberRoleSignal], "/organization/get-active-member-role", $fetch, { method: "GET" });
|
|
2871
|
+
return {
|
|
2872
|
+
$listOrg,
|
|
2873
|
+
$activeOrgSignal,
|
|
2874
|
+
$activeMemberSignal,
|
|
2875
|
+
$activeMemberRoleSignal,
|
|
2876
|
+
activeOrganization,
|
|
2877
|
+
listOrganizations,
|
|
2878
|
+
activeMember,
|
|
2879
|
+
activeMemberRole
|
|
2880
|
+
};
|
|
2881
|
+
},
|
|
2882
|
+
pathMethods: {
|
|
2883
|
+
"/organization/get-full-organization": "GET",
|
|
2884
|
+
"/organization/list-user-teams": "GET"
|
|
2885
|
+
},
|
|
2886
|
+
atomListeners: [
|
|
2887
|
+
{
|
|
2888
|
+
matcher(path) {
|
|
2889
|
+
return path === "/organization/create" || path === "/organization/delete" || path === "/organization/update";
|
|
2890
|
+
},
|
|
2891
|
+
signal: "$listOrg"
|
|
2892
|
+
},
|
|
2893
|
+
{
|
|
2894
|
+
matcher(path) {
|
|
2895
|
+
return path === "/sign-out" || path.startsWith("/organization");
|
|
2896
|
+
},
|
|
2897
|
+
signal: "$activeOrgSignal"
|
|
2898
|
+
},
|
|
2899
|
+
{
|
|
2900
|
+
matcher(path) {
|
|
2901
|
+
return path.startsWith("/organization/set-active") || path === "/organization/create" || path === "/organization/delete" || path === "/organization/remove-member" || path === "/organization/leave" || path === "/organization/accept-invitation";
|
|
2902
|
+
},
|
|
2903
|
+
signal: "$sessionSignal"
|
|
2904
|
+
},
|
|
2905
|
+
{
|
|
2906
|
+
matcher(path) {
|
|
2907
|
+
return path.includes("/organization/update-member-role") || path.startsWith("/organization/set-active");
|
|
2908
|
+
},
|
|
2909
|
+
signal: "$activeMemberSignal"
|
|
2910
|
+
},
|
|
2911
|
+
{
|
|
2912
|
+
matcher(path) {
|
|
2913
|
+
return path.includes("/organization/update-member-role") || path.startsWith("/organization/set-active");
|
|
2914
|
+
},
|
|
2915
|
+
signal: "$activeMemberRoleSignal"
|
|
2916
|
+
}
|
|
2917
|
+
],
|
|
2918
|
+
$ERROR_CODES: ORGANIZATION_ERROR_CODES
|
|
2919
|
+
};
|
|
2920
|
+
};
|
|
2921
|
+
|
|
2922
|
+
//#endregion
|
|
2923
|
+
//#region ../../node_modules/.pnpm/@better-auth+api-key@1.6.26_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-f_7fcf2d2039ede21128af994b19d00ab6/node_modules/@better-auth/api-key/dist/version-vgVyvied.mjs
|
|
2924
|
+
const API_KEY_ERROR_CODES = defineErrorCodes({
|
|
2925
|
+
INVALID_METADATA_TYPE: "metadata must be an object or undefined",
|
|
2926
|
+
REFILL_AMOUNT_AND_INTERVAL_REQUIRED: "refillAmount is required when refillInterval is provided",
|
|
2927
|
+
REFILL_INTERVAL_AND_AMOUNT_REQUIRED: "refillInterval is required when refillAmount is provided",
|
|
2928
|
+
USER_BANNED: "User is banned",
|
|
2929
|
+
UNAUTHORIZED_SESSION: "Unauthorized or invalid session",
|
|
2930
|
+
KEY_NOT_FOUND: "API Key not found",
|
|
2931
|
+
KEY_DISABLED: "API Key is disabled",
|
|
2932
|
+
KEY_EXPIRED: "API Key has expired",
|
|
2933
|
+
USAGE_EXCEEDED: "API Key has reached its usage limit",
|
|
2934
|
+
KEY_NOT_RECOVERABLE: "API Key is not recoverable",
|
|
2935
|
+
EXPIRES_IN_IS_TOO_SMALL: "The expiresIn is smaller than the predefined minimum value.",
|
|
2936
|
+
EXPIRES_IN_IS_TOO_LARGE: "The expiresIn is larger than the predefined maximum value.",
|
|
2937
|
+
INVALID_REMAINING: "The remaining count is either too large or too small.",
|
|
2938
|
+
INVALID_PREFIX_LENGTH: "The prefix length is either too large or too small.",
|
|
2939
|
+
INVALID_NAME_LENGTH: "The name length is either too large or too small.",
|
|
2940
|
+
METADATA_DISABLED: "Metadata is disabled.",
|
|
2941
|
+
RATE_LIMIT_EXCEEDED: "Rate limit exceeded.",
|
|
2942
|
+
NO_VALUES_TO_UPDATE: "No values to update.",
|
|
2943
|
+
KEY_DISABLED_EXPIRATION: "Custom key expiration values are disabled.",
|
|
2944
|
+
INVALID_API_KEY: "Invalid API key.",
|
|
2945
|
+
INVALID_USER_ID_FROM_API_KEY: "The user id from the API key is invalid.",
|
|
2946
|
+
INVALID_REFERENCE_ID_FROM_API_KEY: "The reference id from the API key is invalid.",
|
|
2947
|
+
INVALID_API_KEY_GETTER_RETURN_TYPE: "API Key getter returned an invalid key type. Expected string.",
|
|
2948
|
+
SERVER_ONLY_PROPERTY: "The property you're trying to set can only be set from the server auth instance only.",
|
|
2949
|
+
FAILED_TO_UPDATE_API_KEY: "Failed to update API key",
|
|
2950
|
+
NAME_REQUIRED: "API Key name is required.",
|
|
2951
|
+
ORGANIZATION_ID_REQUIRED: "Organization ID is required for organization-owned API keys.",
|
|
2952
|
+
USER_NOT_MEMBER_OF_ORGANIZATION: "You are not a member of the organization that owns this API key.",
|
|
2953
|
+
INSUFFICIENT_API_KEY_PERMISSIONS: "You do not have permission to perform this action on organization API keys.",
|
|
2954
|
+
NO_DEFAULT_API_KEY_CONFIGURATION_FOUND: "No default api-key configuration found.",
|
|
2955
|
+
ORGANIZATION_PLUGIN_REQUIRED: "Organization plugin is required for organization-owned API keys. Please install and configure the organization plugin."
|
|
2956
|
+
});
|
|
2957
|
+
const PACKAGE_VERSION = "1.6.26";
|
|
2958
|
+
|
|
2959
|
+
//#endregion
|
|
2960
|
+
//#region ../../node_modules/.pnpm/@better-auth+api-key@1.6.26_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-f_7fcf2d2039ede21128af994b19d00ab6/node_modules/@better-auth/api-key/dist/client.mjs
|
|
2961
|
+
const apiKeyClient = () => {
|
|
2962
|
+
return {
|
|
2963
|
+
id: "api-key",
|
|
2964
|
+
version: PACKAGE_VERSION,
|
|
2965
|
+
$InferServerPlugin: {},
|
|
2966
|
+
pathMethods: {
|
|
2967
|
+
"/api-key/create": "POST",
|
|
2968
|
+
"/api-key/delete": "POST",
|
|
2969
|
+
"/api-key/delete-all-expired-api-keys": "POST"
|
|
2970
|
+
},
|
|
2971
|
+
$ERROR_CODES: API_KEY_ERROR_CODES
|
|
2972
|
+
};
|
|
2973
|
+
};
|
|
2974
|
+
|
|
2975
|
+
//#endregion
|
|
2976
|
+
//#region ../auth/dist/client.mjs
|
|
2977
|
+
function c$1() {
|
|
2978
|
+
return [
|
|
2979
|
+
apiKeyClient(),
|
|
2980
|
+
adminClient(),
|
|
2981
|
+
deviceAuthorizationClient(),
|
|
2982
|
+
organizationClient({
|
|
2983
|
+
ac: t$1,
|
|
2984
|
+
roles: n$1
|
|
2985
|
+
}),
|
|
2986
|
+
inferAdditionalFields()
|
|
2987
|
+
];
|
|
2988
|
+
}
|
|
2989
|
+
const l$1 = (e) => createAuthClient({
|
|
2990
|
+
baseURL: e.baseURL,
|
|
2991
|
+
basePath: e.basePath,
|
|
2992
|
+
plugins: c$1()
|
|
2993
|
+
});
|
|
2994
|
+
|
|
2995
|
+
//#endregion
|
|
2996
|
+
//#region src/lib/errors.ts
|
|
2997
|
+
var CliError = class extends Error {
|
|
2998
|
+
code;
|
|
2999
|
+
exitCode;
|
|
3000
|
+
details;
|
|
3001
|
+
constructor(code, message, options) {
|
|
3002
|
+
super(message);
|
|
3003
|
+
this.name = "CliError";
|
|
3004
|
+
this.code = code;
|
|
3005
|
+
this.exitCode = options?.exitCode ?? 1;
|
|
3006
|
+
this.details = options?.details;
|
|
3007
|
+
}
|
|
3008
|
+
};
|
|
3009
|
+
function exitCodeForError(error) {
|
|
3010
|
+
if (error instanceof CliError) return error.exitCode;
|
|
3011
|
+
return 1;
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
//#endregion
|
|
3015
|
+
//#region src/lib/client.ts
|
|
3016
|
+
const AUTH_BASE_PATH = "/api/v1/auth";
|
|
3017
|
+
function createCliAuthClient(apiUrl) {
|
|
3018
|
+
return l$1({
|
|
3019
|
+
baseURL: apiUrl,
|
|
3020
|
+
basePath: AUTH_BASE_PATH
|
|
3021
|
+
});
|
|
3022
|
+
}
|
|
3023
|
+
function bearerFetchOptions(sessionToken) {
|
|
3024
|
+
return { headers: { Authorization: `Bearer ${sessionToken}` } };
|
|
3025
|
+
}
|
|
3026
|
+
/**
|
|
3027
|
+
* RPC requires `session.activeOrganizationId`. Used when a caller still has a
|
|
3028
|
+
* user session token (not the management-key path from `shipd login`).
|
|
3029
|
+
*/
|
|
3030
|
+
async function ensureActiveOrganization(input) {
|
|
3031
|
+
const fetchOptions = bearerFetchOptions(input.sessionToken);
|
|
3032
|
+
const listed = await input.auth.organization.list({ fetchOptions });
|
|
3033
|
+
if (listed.error) throw new CliError("unauthenticated", listed.error.message ?? "Failed to list organizations");
|
|
3034
|
+
const orgs = listed.data ?? [];
|
|
3035
|
+
if (input.orgSlug) {
|
|
3036
|
+
const match = orgs.find((org) => org.slug === input.orgSlug || org.id === input.orgSlug);
|
|
3037
|
+
if (!match) throw new CliError("not_found", `Organization not found: ${input.orgSlug}. Join or create it, then retry with --org.`);
|
|
3038
|
+
const activated = await input.auth.organization.setActive({
|
|
3039
|
+
organizationId: match.id,
|
|
3040
|
+
fetchOptions
|
|
3041
|
+
});
|
|
3042
|
+
if (activated.error) throw new CliError("unauthenticated", activated.error.message ?? "Failed to set active organization");
|
|
3043
|
+
return match;
|
|
3044
|
+
}
|
|
3045
|
+
if (orgs.length === 1) {
|
|
3046
|
+
const only = orgs[0];
|
|
3047
|
+
const activated = await input.auth.organization.setActive({
|
|
3048
|
+
organizationId: only.id,
|
|
3049
|
+
fetchOptions
|
|
3050
|
+
});
|
|
3051
|
+
if (activated.error) throw new CliError("unauthenticated", activated.error.message ?? "Failed to set active organization");
|
|
3052
|
+
return only;
|
|
3053
|
+
}
|
|
3054
|
+
if (orgs.length > 1) {
|
|
3055
|
+
const slugs = orgs.map((org) => org.slug).join(", ");
|
|
3056
|
+
throw new CliError("validation_error", `Multiple organizations available (${slugs}). Pass --org <slug> to choose one.`);
|
|
3057
|
+
}
|
|
3058
|
+
const slug = `personal-${Date.now().toString(36)}`;
|
|
3059
|
+
const created = await input.auth.organization.create({
|
|
3060
|
+
name: "Personal",
|
|
3061
|
+
slug,
|
|
3062
|
+
fetchOptions
|
|
3063
|
+
});
|
|
3064
|
+
if (created.error) throw new CliError("unauthenticated", created.error.message ?? "Failed to create a personal organization");
|
|
3065
|
+
const org = created.data;
|
|
3066
|
+
if (!org?.id) throw new CliError("internal", "Organization create returned no organization");
|
|
3067
|
+
await input.auth.organization.setActive({
|
|
3068
|
+
organizationId: org.id,
|
|
3069
|
+
fetchOptions
|
|
3070
|
+
});
|
|
3071
|
+
return org;
|
|
3072
|
+
}
|
|
3073
|
+
async function createCliApiClient(runtime) {
|
|
3074
|
+
const credentials = loadCredentials();
|
|
3075
|
+
const apiKey = runtime.apiKey ?? credentials.apiKey;
|
|
3076
|
+
const sessionToken = apiKey ? void 0 : credentials.sessionToken;
|
|
3077
|
+
if (sessionToken) await ensureActiveOrganization({
|
|
3078
|
+
auth: createCliAuthClient(runtime.apiUrl),
|
|
3079
|
+
sessionToken,
|
|
3080
|
+
orgSlug: runtime.org
|
|
3081
|
+
});
|
|
3082
|
+
const client = _$1({
|
|
3083
|
+
baseUrl: runtime.apiUrl,
|
|
3084
|
+
client: "cli",
|
|
3085
|
+
getHeaders: () => {
|
|
3086
|
+
const headers = new Headers();
|
|
3087
|
+
if (apiKey) headers.set("x-api-key", apiKey);
|
|
3088
|
+
else if (sessionToken) headers.set("Authorization", `Bearer ${sessionToken}`);
|
|
3089
|
+
return headers;
|
|
3090
|
+
}
|
|
3091
|
+
});
|
|
3092
|
+
if (apiKey && runtime.org) {
|
|
3093
|
+
const me = await client.me.get({}).catch(mapApiError);
|
|
3094
|
+
if (me.organization.slug !== runtime.org && me.organization.id !== runtime.org) throw new CliError("validation_error", `Organization mismatch: API key is bound to "${me.organization.slug}", but --org/SHIPD_ORG is "${runtime.org}". Re-login for that org or omit --org.`);
|
|
3095
|
+
}
|
|
3096
|
+
return client;
|
|
3097
|
+
}
|
|
3098
|
+
function mapApiError(error) {
|
|
3099
|
+
if (error instanceof r$1) {
|
|
3100
|
+
const details = error.details;
|
|
3101
|
+
let exitCode = 1;
|
|
3102
|
+
if (error.code === "conflict") exitCode = 3;
|
|
3103
|
+
else if (error.code === "validation_error" && details?.code === "unlinked") exitCode = 4;
|
|
3104
|
+
throw new CliError(error.code, error.message, {
|
|
3105
|
+
exitCode,
|
|
3106
|
+
details: error.details
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
3109
|
+
throw error;
|
|
3110
|
+
}
|
|
3111
|
+
async function resolveProjectId(client, runtime) {
|
|
3112
|
+
const me = await client.me.get({}).catch(mapApiError);
|
|
3113
|
+
let projectId = me.project?.id;
|
|
3114
|
+
if (runtime.project) {
|
|
3115
|
+
const match = (await client.project.list({}).catch(mapApiError)).find((p) => p.slug === runtime.project || p.id === runtime.project);
|
|
3116
|
+
if (!match) throw new CliError("not_found", `Project not found: ${runtime.project}`);
|
|
3117
|
+
projectId = match.id;
|
|
3118
|
+
}
|
|
3119
|
+
if (!projectId) throw new CliError("validation_error", "Project is required. Pass --project, set SHIPD_PROJECT, or use an API key with project metadata.");
|
|
3120
|
+
return {
|
|
3121
|
+
organizationId: me.organization.id,
|
|
3122
|
+
projectId
|
|
3123
|
+
};
|
|
3124
|
+
}
|
|
3125
|
+
async function resolveIds(client, runtime) {
|
|
3126
|
+
const { organizationId, projectId } = await resolveProjectId(client, runtime);
|
|
3127
|
+
let environmentId = (await client.me.get({}).catch(mapApiError)).environment?.id;
|
|
3128
|
+
if (runtime.env) {
|
|
3129
|
+
const match = (await client.environment.list({ projectId }).catch(mapApiError)).find((e) => e.slug === runtime.env || e.id === runtime.env);
|
|
3130
|
+
if (!match) throw new CliError("not_found", `Environment not found: ${runtime.env}`);
|
|
3131
|
+
environmentId = match.id;
|
|
3132
|
+
}
|
|
3133
|
+
if (!environmentId) throw new CliError("validation_error", "Environment is required. Pass --env, set SHIPD_ENV, or use an API key with environment metadata.");
|
|
3134
|
+
return {
|
|
3135
|
+
organizationId,
|
|
3136
|
+
projectId,
|
|
3137
|
+
environmentId
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
//#endregion
|
|
3142
|
+
//#region src/lib/output.ts
|
|
3143
|
+
function getRuntime(command) {
|
|
3144
|
+
const opts = command.optsWithGlobals();
|
|
3145
|
+
return resolveRuntimeConfig(opts);
|
|
3146
|
+
}
|
|
3147
|
+
function printResult(runtime, data, human) {
|
|
3148
|
+
if (runtime.json) {
|
|
3149
|
+
console.log(JSON.stringify(data, null, 2));
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
console.log(human);
|
|
3153
|
+
}
|
|
3154
|
+
async function confirm(runtime, message) {
|
|
3155
|
+
if (runtime.yes) return true;
|
|
3156
|
+
if (!process.stdin.isTTY) return false;
|
|
3157
|
+
process.stderr.write(`${message} [y/N] `);
|
|
3158
|
+
const answer = await new Promise((resolve) => {
|
|
3159
|
+
const onData = (chunk) => {
|
|
3160
|
+
process.stdin.pause();
|
|
3161
|
+
process.stdin.off("data", onData);
|
|
3162
|
+
resolve(String(chunk).trim());
|
|
3163
|
+
};
|
|
3164
|
+
process.stdin.resume();
|
|
3165
|
+
process.stdin.setEncoding("utf8");
|
|
3166
|
+
process.stdin.on("data", onData);
|
|
3167
|
+
});
|
|
3168
|
+
return /^y(es)?$/i.test(answer);
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
//#endregion
|
|
3172
|
+
//#region ../auth/dist/device.mjs
|
|
3173
|
+
function e(e) {
|
|
3174
|
+
return e;
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
//#endregion
|
|
3178
|
+
//#region src/commands/auth.ts
|
|
3179
|
+
const CLIENT_ID = "shipd-cli";
|
|
3180
|
+
const MANAGEMENT_KEY_PREFIX = "shipd_mgmt_";
|
|
3181
|
+
function registerAuthCommands(program) {
|
|
3182
|
+
program.command("login").description("Authenticate via browser device authorization").action(async (_opts, command) => {
|
|
3183
|
+
const runtime = getRuntime(command);
|
|
3184
|
+
const auth = e(createCliAuthClient(runtime.apiUrl));
|
|
3185
|
+
const codeResult = await auth.device.code({ client_id: CLIENT_ID });
|
|
3186
|
+
if (codeResult.error) throw new CliError("unauthenticated", codeResult.error.error_description ?? "Failed to start device authorization");
|
|
3187
|
+
const data = codeResult.data;
|
|
3188
|
+
if (!data) throw new CliError("unauthenticated", "Device authorization returned no data");
|
|
3189
|
+
const verificationUrl = data.verification_uri_complete?.startsWith("http") ? data.verification_uri_complete : new URL(data.verification_uri_complete ?? data.verification_uri, runtime.appUrl).toString();
|
|
3190
|
+
if (runtime.json) console.error(JSON.stringify({
|
|
3191
|
+
user_code: data.user_code,
|
|
3192
|
+
verification_uri: verificationUrl,
|
|
3193
|
+
expires_in: data.expires_in
|
|
3194
|
+
}, null, 2));
|
|
3195
|
+
else {
|
|
3196
|
+
console.log("Open the following URL in your browser and enter the code:\n");
|
|
3197
|
+
console.log(` ${verificationUrl}`);
|
|
3198
|
+
console.log(`\n Code: ${data.user_code}\n`);
|
|
3199
|
+
console.log("Waiting for approval…");
|
|
3200
|
+
}
|
|
3201
|
+
const intervalMs = Math.max((data.interval ?? 5) * 1e3, 1e3);
|
|
3202
|
+
const deadline = Date.now() + (data.expires_in ?? 300) * 1e3;
|
|
3203
|
+
while (Date.now() < deadline) {
|
|
3204
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3205
|
+
const tokenResult = await auth.device.token({
|
|
3206
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
3207
|
+
device_code: data.device_code,
|
|
3208
|
+
client_id: CLIENT_ID
|
|
3209
|
+
});
|
|
3210
|
+
if (tokenResult.error) {
|
|
3211
|
+
const code = tokenResult.error.error;
|
|
3212
|
+
if (code === "authorization_pending" || code === "slow_down") {
|
|
3213
|
+
if (code === "slow_down") await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3214
|
+
continue;
|
|
3215
|
+
}
|
|
3216
|
+
throw new CliError("unauthenticated", tokenResult.error.error_description ?? "Device authorization failed");
|
|
3217
|
+
}
|
|
3218
|
+
const scope = tokenResult.data?.scope?.trim() ?? "";
|
|
3219
|
+
if (!scope.startsWith(MANAGEMENT_KEY_PREFIX)) throw new CliError("unauthenticated", "Device authorization did not return a management API key. Approve org, project, and environment in the browser.");
|
|
3220
|
+
saveCredentials({
|
|
3221
|
+
apiKey: scope,
|
|
3222
|
+
apiUrl: runtime.apiUrl
|
|
3223
|
+
});
|
|
3224
|
+
const me = await (await createCliApiClient({
|
|
3225
|
+
...runtime,
|
|
3226
|
+
apiKey: scope,
|
|
3227
|
+
org: void 0
|
|
3228
|
+
})).me.get({}).catch(mapApiError);
|
|
3229
|
+
saveGlobalConfig({
|
|
3230
|
+
...loadGlobalConfig(),
|
|
3231
|
+
org: me.organization.slug,
|
|
3232
|
+
...me.project ? { project: me.project.slug } : {},
|
|
3233
|
+
...me.environment ? { env: me.environment.slug } : {}
|
|
3234
|
+
});
|
|
3235
|
+
printResult(runtime, {
|
|
3236
|
+
authenticated: true,
|
|
3237
|
+
organization: me.organization,
|
|
3238
|
+
project: me.project,
|
|
3239
|
+
environment: me.environment
|
|
3240
|
+
}, me.project && me.environment ? `Logged in successfully (${me.organization.slug} / ${me.project.slug} / ${me.environment.slug}).` : `Logged in successfully (org: ${me.organization.slug}).`);
|
|
3241
|
+
return;
|
|
3242
|
+
}
|
|
3243
|
+
throw new CliError("unauthenticated", "Device authorization timed out");
|
|
3244
|
+
});
|
|
3245
|
+
program.command("logout").description("Clear stored credentials").action(async (_opts, command) => {
|
|
3246
|
+
const runtime = getRuntime(command);
|
|
3247
|
+
clearCredentials();
|
|
3248
|
+
printResult(runtime, { loggedOut: true }, "Logged out.");
|
|
3249
|
+
});
|
|
3250
|
+
program.command("whoami").description("Show the current authenticated identity").action(async (_opts, command) => {
|
|
3251
|
+
const runtime = getRuntime(command);
|
|
3252
|
+
const me = await (await createCliApiClient(runtime)).me.get({}).catch(mapApiError);
|
|
3253
|
+
if (runtime.json) {
|
|
3254
|
+
console.log(JSON.stringify(me, null, 2));
|
|
3255
|
+
return;
|
|
3256
|
+
}
|
|
3257
|
+
if (me.auth.type === "user") console.log(`User: ${me.auth.name} <${me.auth.email}>`);
|
|
3258
|
+
else console.log(`API key: ${me.auth.keyId}`);
|
|
3259
|
+
console.log(`Organization: ${me.organization.slug} (${me.organization.id})`);
|
|
3260
|
+
if (me.project) console.log(`Project: ${me.project.slug} (${me.project.id})`);
|
|
3261
|
+
if (me.environment) console.log(`Environment: ${me.environment.slug} (${me.environment.id})`);
|
|
3262
|
+
});
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
//#endregion
|
|
3266
|
+
//#region ../contracts/dist/flag.mjs
|
|
3267
|
+
const t = z.enum([
|
|
3268
|
+
`boolean`,
|
|
3269
|
+
`variant`,
|
|
3270
|
+
`number`,
|
|
3271
|
+
`json`
|
|
3272
|
+
]);
|
|
3273
|
+
const n = z.enum([
|
|
3274
|
+
`any`,
|
|
3275
|
+
`code`,
|
|
3276
|
+
`dashboard`
|
|
3277
|
+
]);
|
|
3278
|
+
const r = z.enum([
|
|
3279
|
+
`active`,
|
|
3280
|
+
`deprecated`,
|
|
3281
|
+
`archived`,
|
|
3282
|
+
`deleted`
|
|
3283
|
+
]);
|
|
3284
|
+
const i = /* @__PURE__ */ new Set([`__proto__`]);
|
|
3285
|
+
function a(e) {
|
|
3286
|
+
return i.has(e);
|
|
3287
|
+
}
|
|
3288
|
+
const o = z.string().min(1).refine((e) => e.trim().length > 0, { message: `flag key must not be empty or whitespace-only` }).refine((e) => !a(e), { message: `flag key "__proto__" is reserved` });
|
|
3289
|
+
const s = z.discriminatedUnion(`kind`, [
|
|
3290
|
+
z.object({
|
|
3291
|
+
kind: z.literal(`boolean`),
|
|
3292
|
+
value: z.boolean()
|
|
3293
|
+
}),
|
|
3294
|
+
z.object({
|
|
3295
|
+
kind: z.literal(`variant`),
|
|
3296
|
+
value: z.string()
|
|
3297
|
+
}),
|
|
3298
|
+
z.object({
|
|
3299
|
+
kind: z.literal(`number`),
|
|
3300
|
+
value: z.number()
|
|
3301
|
+
}),
|
|
3302
|
+
z.object({
|
|
3303
|
+
kind: z.literal(`json`),
|
|
3304
|
+
value: z.unknown()
|
|
3305
|
+
}),
|
|
3306
|
+
z.object({ kind: z.literal(`disabled`) })
|
|
3307
|
+
]);
|
|
3308
|
+
const c = z.union([
|
|
3309
|
+
z.object({
|
|
3310
|
+
kind: z.literal(`attribute`),
|
|
3311
|
+
attribute: z.string().min(1),
|
|
3312
|
+
operator: z.enum([
|
|
3313
|
+
`eq`,
|
|
3314
|
+
`neq`,
|
|
3315
|
+
`contains`
|
|
3316
|
+
]),
|
|
3317
|
+
value: z.union([
|
|
3318
|
+
z.string(),
|
|
3319
|
+
z.number(),
|
|
3320
|
+
z.boolean()
|
|
3321
|
+
])
|
|
3322
|
+
}),
|
|
3323
|
+
z.object({
|
|
3324
|
+
kind: z.literal(`attribute`),
|
|
3325
|
+
attribute: z.string().min(1),
|
|
3326
|
+
operator: z.literal(`in`),
|
|
3327
|
+
value: z.array(z.string())
|
|
3328
|
+
}),
|
|
3329
|
+
z.object({
|
|
3330
|
+
kind: z.literal(`percentage`),
|
|
3331
|
+
rollout: z.number().min(0).max(100),
|
|
3332
|
+
seed: z.string().min(1).optional()
|
|
3333
|
+
})
|
|
3334
|
+
]);
|
|
3335
|
+
const l = z.object({
|
|
3336
|
+
id: z.string().min(1),
|
|
3337
|
+
description: z.string().optional(),
|
|
3338
|
+
conditions: z.array(c),
|
|
3339
|
+
serve: s
|
|
3340
|
+
});
|
|
3341
|
+
const u = z.object({ projectId: z.string().min(1) });
|
|
3342
|
+
const d = z.object({
|
|
3343
|
+
projectId: z.string().min(1),
|
|
3344
|
+
key: z.string().min(1)
|
|
3345
|
+
});
|
|
3346
|
+
const f = z.object({
|
|
3347
|
+
projectId: z.string().min(1),
|
|
3348
|
+
key: o,
|
|
3349
|
+
name: z.string().min(1),
|
|
3350
|
+
description: z.string().optional(),
|
|
3351
|
+
type: t,
|
|
3352
|
+
variants: z.array(z.string()).optional(),
|
|
3353
|
+
tags: z.array(z.string()).optional()
|
|
3354
|
+
}).superRefine((e, t) => {
|
|
3355
|
+
e.type === `variant` && (e.variants?.length ?? 0) === 0 && t.addIssue({
|
|
3356
|
+
code: `custom`,
|
|
3357
|
+
path: [`variants`],
|
|
3358
|
+
message: `variant flag requires a non-empty variants array`
|
|
3359
|
+
});
|
|
3360
|
+
});
|
|
3361
|
+
const p = z.object({
|
|
3362
|
+
flagId: z.string().min(1),
|
|
3363
|
+
key: o.optional(),
|
|
3364
|
+
name: z.string().min(1).optional(),
|
|
3365
|
+
description: z.string().nullable().optional(),
|
|
3366
|
+
type: t.optional(),
|
|
3367
|
+
variants: z.array(z.string()).nullable().optional(),
|
|
3368
|
+
tags: z.array(z.string()).optional()
|
|
3369
|
+
});
|
|
3370
|
+
const m = z.object({ flagId: z.string().min(1) });
|
|
3371
|
+
const h = z.object({
|
|
3372
|
+
flagId: z.string().min(1),
|
|
3373
|
+
environmentId: z.string().min(1),
|
|
3374
|
+
enabled: z.boolean().optional(),
|
|
3375
|
+
rules: z.array(l).optional(),
|
|
3376
|
+
fallthrough: s.optional()
|
|
3377
|
+
});
|
|
3378
|
+
const g = z.object({
|
|
3379
|
+
flagId: z.string().min(1),
|
|
3380
|
+
environmentId: z.string().min(1),
|
|
3381
|
+
enabled: z.boolean()
|
|
3382
|
+
});
|
|
3383
|
+
const _ = z.enum([`active`, `deprecated`]);
|
|
3384
|
+
function v(e) {
|
|
3385
|
+
let t = Object.getPrototypeOf(e);
|
|
3386
|
+
return t === Object.prototype || t === null;
|
|
3387
|
+
}
|
|
3388
|
+
function y(e, t) {
|
|
3389
|
+
if (e === null) return !0;
|
|
3390
|
+
switch (typeof e) {
|
|
3391
|
+
case `boolean`:
|
|
3392
|
+
case `string`: return !0;
|
|
3393
|
+
case `number`: return Number.isFinite(e);
|
|
3394
|
+
case `object`: {
|
|
3395
|
+
let n = t ?? /* @__PURE__ */ new WeakSet();
|
|
3396
|
+
return !n.has(e) && (n.add(e), Array.isArray(e) ? e.every((e) => y(e, n)) : !v(e) || Object.getOwnPropertySymbols(e).length > 0 ? !1 : Object.keys(e).every((t) => y(e[t], n)));
|
|
3397
|
+
}
|
|
3398
|
+
default: return !1;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
const b = z.custom(y, { message: `default must be JSON-serializable` });
|
|
3402
|
+
function x(e, t) {
|
|
3403
|
+
switch (e.type) {
|
|
3404
|
+
case `boolean`:
|
|
3405
|
+
typeof e.default != `boolean` && t.addIssue({
|
|
3406
|
+
code: `custom`,
|
|
3407
|
+
path: [`default`],
|
|
3408
|
+
message: `boolean flag default must be a boolean`
|
|
3409
|
+
});
|
|
3410
|
+
break;
|
|
3411
|
+
case `number`:
|
|
3412
|
+
(typeof e.default != `number` || !Number.isFinite(e.default)) && t.addIssue({
|
|
3413
|
+
code: `custom`,
|
|
3414
|
+
path: [`default`],
|
|
3415
|
+
message: `number flag default must be a finite number`
|
|
3416
|
+
});
|
|
3417
|
+
break;
|
|
3418
|
+
case `variant`: {
|
|
3419
|
+
let n = e.variants ?? [];
|
|
3420
|
+
n.length === 0 && t.addIssue({
|
|
3421
|
+
code: `custom`,
|
|
3422
|
+
path: [`variants`],
|
|
3423
|
+
message: `variant flag requires a non-empty variants array`
|
|
3424
|
+
}), (typeof e.default != `string` || !n.includes(e.default)) && t.addIssue({
|
|
3425
|
+
code: `custom`,
|
|
3426
|
+
path: [`default`],
|
|
3427
|
+
message: `variant default must be one of: ${n.join(`, `) || `(none)`}`
|
|
3428
|
+
});
|
|
3429
|
+
break;
|
|
3430
|
+
}
|
|
3431
|
+
case `json`: b.safeParse(e.default).success || t.addIssue({
|
|
3432
|
+
code: `custom`,
|
|
3433
|
+
path: [`default`],
|
|
3434
|
+
message: `json flag default must be JSON-serializable`
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
const S = z.object({
|
|
3439
|
+
key: o,
|
|
3440
|
+
type: t,
|
|
3441
|
+
default: z.unknown(),
|
|
3442
|
+
description: z.string().optional(),
|
|
3443
|
+
tags: z.array(z.string()).default([]),
|
|
3444
|
+
lifecycle: _.default(`active`),
|
|
3445
|
+
variants: z.array(z.string()).optional(),
|
|
3446
|
+
disabled: z.boolean().optional()
|
|
3447
|
+
});
|
|
3448
|
+
const C = S.superRefine(x);
|
|
3449
|
+
const w = S.extend({
|
|
3450
|
+
version: z.number().int().positive(),
|
|
3451
|
+
environmentVersion: z.number().int().positive().optional(),
|
|
3452
|
+
managedBy: n
|
|
3453
|
+
}).superRefine(x);
|
|
3454
|
+
const T = z.object({
|
|
3455
|
+
version: z.number().int().positive(),
|
|
3456
|
+
environmentVersion: z.number().int().positive().optional()
|
|
3457
|
+
});
|
|
3458
|
+
const E = z.object({
|
|
3459
|
+
projectId: z.string().min(1),
|
|
3460
|
+
environmentId: z.string().min(1)
|
|
3461
|
+
});
|
|
3462
|
+
const D = z.object({
|
|
3463
|
+
projectId: z.string(),
|
|
3464
|
+
environmentId: z.string(),
|
|
3465
|
+
flags: z.array(w)
|
|
3466
|
+
});
|
|
3467
|
+
function O(e, t) {
|
|
3468
|
+
let n = /* @__PURE__ */ new Set();
|
|
3469
|
+
for (let [r, i] of e.entries()) n.has(i.key) && t.addIssue({
|
|
3470
|
+
code: `custom`,
|
|
3471
|
+
path: [
|
|
3472
|
+
`flags`,
|
|
3473
|
+
r,
|
|
3474
|
+
`key`
|
|
3475
|
+
],
|
|
3476
|
+
message: `duplicate flag key "${i.key}"`
|
|
3477
|
+
}), n.add(i.key);
|
|
3478
|
+
}
|
|
3479
|
+
const k = z.object({
|
|
3480
|
+
projectId: z.string().min(1),
|
|
3481
|
+
environmentId: z.string().min(1),
|
|
3482
|
+
flags: z.array(C)
|
|
3483
|
+
}).superRefine((e, t) => O(e.flags, t));
|
|
3484
|
+
const A = z.object({
|
|
3485
|
+
key: z.string(),
|
|
3486
|
+
op: z.enum([
|
|
3487
|
+
`add`,
|
|
3488
|
+
`update`,
|
|
3489
|
+
`remove`,
|
|
3490
|
+
`unlinked`
|
|
3491
|
+
]),
|
|
3492
|
+
before: w.optional(),
|
|
3493
|
+
after: C.optional(),
|
|
3494
|
+
message: z.string().optional()
|
|
3495
|
+
});
|
|
3496
|
+
const j = z.object({
|
|
3497
|
+
projectId: z.string(),
|
|
3498
|
+
environmentId: z.string(),
|
|
3499
|
+
changes: z.array(A),
|
|
3500
|
+
remoteOnly: z.array(w).default([])
|
|
3501
|
+
});
|
|
3502
|
+
const M = z.object({
|
|
3503
|
+
projectId: z.string().min(1),
|
|
3504
|
+
environmentId: z.string().min(1),
|
|
3505
|
+
flags: z.array(C),
|
|
3506
|
+
apply: z.boolean().default(!1),
|
|
3507
|
+
prune: z.boolean().default(!1),
|
|
3508
|
+
force: z.boolean().default(!1),
|
|
3509
|
+
adopt: z.boolean().default(!1),
|
|
3510
|
+
expectedVersions: z.record(z.string(), T).optional()
|
|
3511
|
+
}).superRefine((e, t) => O(e.flags, t));
|
|
3512
|
+
const N = z.object({
|
|
3513
|
+
projectId: z.string(),
|
|
3514
|
+
environmentId: z.string(),
|
|
3515
|
+
applied: z.boolean(),
|
|
3516
|
+
changes: z.array(A),
|
|
3517
|
+
remoteOnly: z.array(w).default([]),
|
|
3518
|
+
forced: z.boolean().default(!1),
|
|
3519
|
+
adopted: z.boolean().default(!1)
|
|
3520
|
+
});
|
|
3521
|
+
|
|
3522
|
+
//#endregion
|
|
3523
|
+
//#region src/lib/local-config.ts
|
|
3524
|
+
const localFlagsArraySchema = z.array(C).superRefine((flags, ctx) => {
|
|
3525
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3526
|
+
for (const [index, flag] of flags.entries()) {
|
|
3527
|
+
if (seen.has(flag.key)) ctx.addIssue({
|
|
3528
|
+
code: "custom",
|
|
3529
|
+
path: [index, "key"],
|
|
3530
|
+
message: `duplicate flag key "${flag.key}"`
|
|
3531
|
+
});
|
|
3532
|
+
seen.add(flag.key);
|
|
3533
|
+
}
|
|
3534
|
+
});
|
|
3535
|
+
async function loadLocalFlags(configFile) {
|
|
3536
|
+
const absolute = path.resolve(configFile);
|
|
3537
|
+
if (!fs.existsSync(absolute)) throw new CliError("not_found", `Config file not found: ${absolute}`);
|
|
3538
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
3539
|
+
let loaded;
|
|
3540
|
+
try {
|
|
3541
|
+
loaded = await jiti.import(absolute);
|
|
3542
|
+
} catch (error) {
|
|
3543
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3544
|
+
throw new CliError("validation_error", `Failed to load config ${absolute}: ${message}`);
|
|
3545
|
+
}
|
|
3546
|
+
const config = loaded.default ?? loaded;
|
|
3547
|
+
if (!config.flags || typeof config.flags !== "object") throw new CliError("validation_error", "shipd.config.ts must export defineFlags(...) result");
|
|
3548
|
+
const candidates = Object.entries(config.flags).map(([key, flag]) => ({
|
|
3549
|
+
key,
|
|
3550
|
+
type: flag.type,
|
|
3551
|
+
default: flag.default,
|
|
3552
|
+
description: flag.description,
|
|
3553
|
+
tags: flag.tags ?? [],
|
|
3554
|
+
lifecycle: flag.lifecycle ?? "active",
|
|
3555
|
+
variants: flag.variants,
|
|
3556
|
+
disabled: flag.disabled
|
|
3557
|
+
}));
|
|
3558
|
+
const parsed = localFlagsArraySchema.safeParse(candidates);
|
|
3559
|
+
if (!parsed.success) {
|
|
3560
|
+
const detail = parsed.error.issues.map((issue) => `${issue.path.join(".") || "flags"}: ${issue.message}`).join("; ");
|
|
3561
|
+
throw new CliError("validation_error", `Invalid flag definitions: ${detail}`);
|
|
3562
|
+
}
|
|
3563
|
+
return parsed.data.map((flag) => ({
|
|
3564
|
+
key: flag.key,
|
|
3565
|
+
type: flag.type,
|
|
3566
|
+
default: flag.default,
|
|
3567
|
+
description: flag.description,
|
|
3568
|
+
tags: flag.tags,
|
|
3569
|
+
lifecycle: flag.lifecycle,
|
|
3570
|
+
variants: flag.variants,
|
|
3571
|
+
disabled: flag.disabled
|
|
3572
|
+
}));
|
|
3573
|
+
}
|
|
3574
|
+
function serializeValue(value) {
|
|
3575
|
+
return JSON.stringify(value, null, 2).replace(/\n/g, "\n ");
|
|
3576
|
+
}
|
|
3577
|
+
function generateShipdConfigSource(flags) {
|
|
3578
|
+
return `import { defineFlags } from "shipdit/config";
|
|
3579
|
+
|
|
3580
|
+
/**
|
|
3581
|
+
* Generated by \`shipd pull\`. This file is regenerated on pull — edit carefully.
|
|
3582
|
+
* \`shipd push\` syncs definitions (project-global) and defaults for the target env.
|
|
3583
|
+
*/
|
|
3584
|
+
export default defineFlags({
|
|
3585
|
+
${flags.map((flag) => {
|
|
3586
|
+
const lines = [` ${JSON.stringify(flag.key)}: {`, ` type: ${JSON.stringify(flag.type)},`];
|
|
3587
|
+
if (flag.type === "variant" && flag.variants) lines.push(` variants: ${JSON.stringify(flag.variants)} as const,`, ` default: ${JSON.stringify(flag.default)},`);
|
|
3588
|
+
else if (flag.type === "json") lines.push(` default: ${serializeValue(flag.default)},`);
|
|
3589
|
+
else lines.push(` default: ${JSON.stringify(flag.default)},`);
|
|
3590
|
+
if (flag.description !== void 0) lines.push(` description: ${JSON.stringify(flag.description)},`);
|
|
3591
|
+
if (flag.tags.length > 0) lines.push(` tags: ${JSON.stringify(flag.tags)},`);
|
|
3592
|
+
if (flag.lifecycle === "deprecated") lines.push(` deprecated: true,`);
|
|
3593
|
+
lines.push(` },`);
|
|
3594
|
+
return lines.join("\n");
|
|
3595
|
+
}).join("\n")}
|
|
3596
|
+
});
|
|
3597
|
+
`;
|
|
3598
|
+
}
|
|
3599
|
+
function generateTypesSource(flags) {
|
|
3600
|
+
const entries = flags.map((flag) => {
|
|
3601
|
+
const lines = [` ${JSON.stringify(flag.key)}: {`, ` type: ${JSON.stringify(flag.type)};`];
|
|
3602
|
+
if (flag.type === "variant") {
|
|
3603
|
+
const variants = flag.variants && flag.variants.length > 0 ? flag.variants.map((v) => JSON.stringify(v)).join(" | ") : "string";
|
|
3604
|
+
lines.push(` variants: ${variants};`);
|
|
3605
|
+
}
|
|
3606
|
+
lines.push(` default: ${serializeTypeLiteral(flag.default)};`);
|
|
3607
|
+
lines.push(` };`);
|
|
3608
|
+
return lines.join("\n");
|
|
3609
|
+
}).join("\n\n");
|
|
3610
|
+
return `/* eslint-disable */
|
|
3611
|
+
/* This file is generated by shipd types gen. Do not edit. */
|
|
3612
|
+
|
|
3613
|
+
export interface FlagDefinitions {
|
|
3614
|
+
${flags.length === 0 ? " // No flags defined in shipd.config.ts\n" : `${entries}\n`}}
|
|
3615
|
+
|
|
3616
|
+
export type FlagKey = keyof FlagDefinitions;
|
|
3617
|
+
|
|
3618
|
+
export type BooleanFlagKey = {
|
|
3619
|
+
[K in FlagKey]: FlagDefinitions[K]["type"] extends "boolean" ? K : never;
|
|
3620
|
+
}[FlagKey];
|
|
3621
|
+
|
|
3622
|
+
export type VariantFlagKey = {
|
|
3623
|
+
[K in FlagKey]: FlagDefinitions[K]["type"] extends "variant" ? K : never;
|
|
3624
|
+
}[FlagKey];
|
|
3625
|
+
|
|
3626
|
+
export type NumberFlagKey = {
|
|
3627
|
+
[K in FlagKey]: FlagDefinitions[K]["type"] extends "number" ? K : never;
|
|
3628
|
+
}[FlagKey];
|
|
3629
|
+
|
|
3630
|
+
export type JsonFlagKey = {
|
|
3631
|
+
[K in FlagKey]: FlagDefinitions[K]["type"] extends "json" ? K : never;
|
|
3632
|
+
}[FlagKey];
|
|
3633
|
+
`;
|
|
3634
|
+
}
|
|
3635
|
+
function serializeTypeLiteral(value) {
|
|
3636
|
+
if (value === void 0) return "undefined";
|
|
3637
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
|
|
3638
|
+
if (value === null) return "null";
|
|
3639
|
+
return JSON.stringify(value);
|
|
3640
|
+
}
|
|
3641
|
+
|
|
3642
|
+
//#endregion
|
|
3643
|
+
//#region src/lib/plan.ts
|
|
3644
|
+
const DEFINITION_FIELDS = [
|
|
3645
|
+
"type",
|
|
3646
|
+
"default",
|
|
3647
|
+
"disabled",
|
|
3648
|
+
"description",
|
|
3649
|
+
"tags",
|
|
3650
|
+
"lifecycle",
|
|
3651
|
+
"variants"
|
|
3652
|
+
];
|
|
3653
|
+
function formatValue(value) {
|
|
3654
|
+
if (value === void 0) return "undefined";
|
|
3655
|
+
return JSON.stringify(value, null, 0).replace(/,(?=\S)/g, ", ");
|
|
3656
|
+
}
|
|
3657
|
+
function fieldChanges(before, after) {
|
|
3658
|
+
const fields = {};
|
|
3659
|
+
for (const field of DEFINITION_FIELDS) {
|
|
3660
|
+
const from = before[field];
|
|
3661
|
+
const to = after[field];
|
|
3662
|
+
if (JSON.stringify(from ?? null) !== JSON.stringify(to ?? null)) fields[field] = {
|
|
3663
|
+
from,
|
|
3664
|
+
to
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
return fields;
|
|
3668
|
+
}
|
|
3669
|
+
const DEFINITION_ONLY_FIELDS = [
|
|
3670
|
+
"type",
|
|
3671
|
+
"description",
|
|
3672
|
+
"tags",
|
|
3673
|
+
"lifecycle",
|
|
3674
|
+
"variants"
|
|
3675
|
+
];
|
|
3676
|
+
function planHasDefinitionChanges(plan) {
|
|
3677
|
+
if (plan.creates.length > 0 || plan.archives.length > 0) return true;
|
|
3678
|
+
for (const update of plan.updates) {
|
|
3679
|
+
if (update.before.managedBy && update.before.managedBy !== "code") return true;
|
|
3680
|
+
for (const field of DEFINITION_ONLY_FIELDS) if (update.fields[field]) return true;
|
|
3681
|
+
}
|
|
3682
|
+
return false;
|
|
3683
|
+
}
|
|
3684
|
+
function buildSyncPlan(changes) {
|
|
3685
|
+
const plan = {
|
|
3686
|
+
creates: [],
|
|
3687
|
+
updates: [],
|
|
3688
|
+
archives: [],
|
|
3689
|
+
unlinked: [],
|
|
3690
|
+
conflicts: []
|
|
3691
|
+
};
|
|
3692
|
+
for (const change of changes) {
|
|
3693
|
+
if (change.op === "add" && change.after) {
|
|
3694
|
+
plan.creates.push({
|
|
3695
|
+
key: change.key,
|
|
3696
|
+
after: change.after
|
|
3697
|
+
});
|
|
3698
|
+
continue;
|
|
3699
|
+
}
|
|
3700
|
+
if (change.op === "update" && change.before && change.after) {
|
|
3701
|
+
plan.updates.push({
|
|
3702
|
+
key: change.key,
|
|
3703
|
+
before: change.before,
|
|
3704
|
+
after: change.after,
|
|
3705
|
+
fields: fieldChanges(change.before, change.after)
|
|
3706
|
+
});
|
|
3707
|
+
continue;
|
|
3708
|
+
}
|
|
3709
|
+
if (change.op === "remove" && change.before) {
|
|
3710
|
+
plan.archives.push({
|
|
3711
|
+
key: change.key,
|
|
3712
|
+
before: change.before
|
|
3713
|
+
});
|
|
3714
|
+
continue;
|
|
3715
|
+
}
|
|
3716
|
+
if (change.op === "unlinked") plan.unlinked.push({
|
|
3717
|
+
key: change.key,
|
|
3718
|
+
message: change.message ?? "unlinked remote flag",
|
|
3719
|
+
before: change.before,
|
|
3720
|
+
after: change.after
|
|
3721
|
+
});
|
|
3722
|
+
}
|
|
3723
|
+
return plan;
|
|
3724
|
+
}
|
|
3725
|
+
function planIsEmpty(plan) {
|
|
3726
|
+
return plan.creates.length === 0 && plan.updates.length === 0 && plan.archives.length === 0 && plan.unlinked.length === 0 && plan.conflicts.length === 0;
|
|
3727
|
+
}
|
|
3728
|
+
function planHasDrift(plan) {
|
|
3729
|
+
return plan.creates.length > 0 || plan.updates.length > 0 || plan.archives.length > 0;
|
|
3730
|
+
}
|
|
3731
|
+
function formatSyncPlan(plan) {
|
|
3732
|
+
if (planIsEmpty(plan)) return "No drift.";
|
|
3733
|
+
const lines = [];
|
|
3734
|
+
if (plan.conflicts.length > 0) {
|
|
3735
|
+
lines.push("Conflict:");
|
|
3736
|
+
for (const conflict of plan.conflicts) {
|
|
3737
|
+
lines.push(` flag "${conflict.key}" ${conflict.message}`);
|
|
3738
|
+
if (conflict.localBaseVersion !== void 0) lines.push(` local base version: ${conflict.localBaseVersion}`);
|
|
3739
|
+
if (conflict.remoteVersion !== void 0) lines.push(` remote version: ${conflict.remoteVersion}`);
|
|
3740
|
+
lines.push("");
|
|
3741
|
+
lines.push("Run:");
|
|
3742
|
+
lines.push(" shipd pull");
|
|
3743
|
+
lines.push("");
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
if (plan.unlinked.length > 0) {
|
|
3747
|
+
lines.push("Unlinked:");
|
|
3748
|
+
for (const item of plan.unlinked) lines.push(` ! flag "${item.key}" ${item.message}`);
|
|
3749
|
+
lines.push("");
|
|
3750
|
+
lines.push("Pass --adopt to link ownership to code.");
|
|
3751
|
+
lines.push("");
|
|
3752
|
+
}
|
|
3753
|
+
if (plan.creates.length > 0 || plan.updates.length > 0 || plan.archives.length > 0) {
|
|
3754
|
+
lines.push("Plan:");
|
|
3755
|
+
for (const create of plan.creates) lines.push(` + create flag "${create.key}"`);
|
|
3756
|
+
for (const update of plan.updates) {
|
|
3757
|
+
lines.push(` ~ update flag "${update.key}"`);
|
|
3758
|
+
for (const [field, change] of Object.entries(update.fields)) lines.push(` ${field}: ${formatValue(change.from)} -> ${formatValue(change.to)}`);
|
|
3759
|
+
}
|
|
3760
|
+
for (const archive of plan.archives) lines.push(` - archive flag "${archive.key}"`);
|
|
3761
|
+
}
|
|
3762
|
+
if (planHasDefinitionChanges(plan)) {
|
|
3763
|
+
lines.push("");
|
|
3764
|
+
lines.push("Note: definition changes (type, variants, tags, lifecycle, description) and ownership adoption apply to all environments.");
|
|
3765
|
+
}
|
|
3766
|
+
return lines.join("\n").trimEnd();
|
|
3767
|
+
}
|
|
3768
|
+
|
|
3769
|
+
//#endregion
|
|
3770
|
+
//#region src/commands/diff.ts
|
|
3771
|
+
function registerDiffCommand(program) {
|
|
3772
|
+
program.command("diff").description("Show drift between local definitions and the server").option("--exit-code", "Exit 2 on drift, 4 on unlinked (0 when clean)", false).action(async (opts, command) => {
|
|
3773
|
+
const runtime = getRuntime(command);
|
|
3774
|
+
const client = await createCliApiClient(runtime);
|
|
3775
|
+
const { projectId, environmentId } = await resolveIds(client, runtime);
|
|
3776
|
+
const localFlags = await loadLocalFlags(runtime.configFile);
|
|
3777
|
+
const result = await client.flag.diff({
|
|
3778
|
+
projectId,
|
|
3779
|
+
environmentId,
|
|
3780
|
+
flags: localFlags
|
|
3781
|
+
}).catch(mapApiError);
|
|
3782
|
+
const plan = buildSyncPlan(result.changes);
|
|
3783
|
+
if (runtime.json) console.log(JSON.stringify({
|
|
3784
|
+
...plan,
|
|
3785
|
+
remoteOnly: result.remoteOnly ?? []
|
|
3786
|
+
}, null, 2));
|
|
3787
|
+
else {
|
|
3788
|
+
console.log(formatSyncPlan(plan));
|
|
3789
|
+
if ((result.remoteOnly?.length ?? 0) > 0) console.error(`\nNote: ${result.remoteOnly.length} remote flag(s) are missing locally. shipd push leaves them alone unless you pass --prune.`);
|
|
3790
|
+
}
|
|
3791
|
+
if (opts.exitCode) {
|
|
3792
|
+
if (plan.unlinked.length > 0) process.exitCode = 4;
|
|
3793
|
+
else if (planHasDrift(plan)) process.exitCode = 2;
|
|
3794
|
+
else if (!planIsEmpty(plan)) process.exitCode = 2;
|
|
3795
|
+
}
|
|
3796
|
+
});
|
|
3797
|
+
}
|
|
3798
|
+
|
|
3799
|
+
//#endregion
|
|
3800
|
+
//#region src/commands/environments.ts
|
|
3801
|
+
function registerEnvironmentsCommands(program) {
|
|
3802
|
+
program.command("environments").description("Environment operations").command("list").description("List environments for the current project").action(async (_opts, command) => {
|
|
3803
|
+
const runtime = getRuntime(command);
|
|
3804
|
+
const client = await createCliApiClient(runtime);
|
|
3805
|
+
const { projectId } = await resolveProjectId(client, runtime);
|
|
3806
|
+
const result = await client.environment.list({ projectId }).catch(mapApiError);
|
|
3807
|
+
if (runtime.json) {
|
|
3808
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
if (result.length === 0) {
|
|
3812
|
+
console.log("No environments.");
|
|
3813
|
+
return;
|
|
3814
|
+
}
|
|
3815
|
+
for (const environment of result) {
|
|
3816
|
+
const marker = environment.isProduction ? "production" : environment.type;
|
|
3817
|
+
console.log(`${environment.slug}\t${environment.name}\t${marker}\t${environment.id}`);
|
|
3818
|
+
}
|
|
3819
|
+
});
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
//#endregion
|
|
3823
|
+
//#region src/lib/flag-options.ts
|
|
3824
|
+
/** Parse `--variants a,b` / `--variants a --variants b` into a deduped list. */
|
|
3825
|
+
function parseVariantsOption(raw) {
|
|
3826
|
+
const parts = (Array.isArray(raw) ? raw : raw !== void 0 ? [raw] : []).flatMap((value) => value.split(",")).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3827
|
+
return [...new Set(parts)];
|
|
3828
|
+
}
|
|
3829
|
+
|
|
3830
|
+
//#endregion
|
|
3831
|
+
//#region src/commands/flags.ts
|
|
3832
|
+
const FLAG_TYPES = [
|
|
3833
|
+
"boolean",
|
|
3834
|
+
"variant",
|
|
3835
|
+
"number",
|
|
3836
|
+
"json"
|
|
3837
|
+
];
|
|
3838
|
+
function registerFlagsCommands(program) {
|
|
3839
|
+
const flags = program.command("flags").description("Lower-level flag operations");
|
|
3840
|
+
flags.command("list").description("List flags in the current project").action(async (_opts, command) => {
|
|
3841
|
+
const runtime = getRuntime(command);
|
|
3842
|
+
const client = await createCliApiClient(runtime);
|
|
3843
|
+
const { projectId } = await resolveProjectId(client, runtime);
|
|
3844
|
+
const result = await client.flag.list({ projectId }).catch(mapApiError);
|
|
3845
|
+
if (runtime.json) {
|
|
3846
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3847
|
+
return;
|
|
3848
|
+
}
|
|
3849
|
+
if (result.length === 0) {
|
|
3850
|
+
console.log("No flags.");
|
|
3851
|
+
return;
|
|
3852
|
+
}
|
|
3853
|
+
for (const flag of result) console.log(`${flag.key}\t${flag.type}\t${flag.lifecycle}\t${flag.managedBy}`);
|
|
3854
|
+
});
|
|
3855
|
+
flags.command("create").description("Create a flag").requiredOption("--key <key>", "Flag key").option("--name <name>", "Display name").option("--type <type>", "Flag type (boolean | variant | number | json)", "boolean").option("--variants <names>", "Comma-separated variant names (required when --type variant; repeatable)", (value, previous) => previous.concat([value]), []).option("--description <text>", "Description").action(async (opts, command) => {
|
|
3856
|
+
const runtime = getRuntime(command);
|
|
3857
|
+
const client = await createCliApiClient(runtime);
|
|
3858
|
+
const { projectId } = await resolveProjectId(client, runtime);
|
|
3859
|
+
if (!FLAG_TYPES.includes(opts.type)) throw new CliError("validation_error", `Unsupported flag type: ${opts.type}`);
|
|
3860
|
+
const type = opts.type;
|
|
3861
|
+
const variants = parseVariantsOption(opts.variants);
|
|
3862
|
+
if (type === "variant" && variants.length === 0) throw new CliError("validation_error", "Variant flags require --variants (e.g. --variants control,treatment)");
|
|
3863
|
+
if (type !== "variant" && variants.length > 0) throw new CliError("validation_error", `--variants is only valid with --type variant (got --type ${type})`);
|
|
3864
|
+
const created = await client.flag.create({
|
|
3865
|
+
projectId,
|
|
3866
|
+
key: opts.key,
|
|
3867
|
+
name: opts.name ?? opts.key,
|
|
3868
|
+
type,
|
|
3869
|
+
description: opts.description,
|
|
3870
|
+
...type === "variant" ? { variants } : {}
|
|
3871
|
+
}).catch(mapApiError);
|
|
3872
|
+
printResult(runtime, created, `Created flag ${created.key}`);
|
|
3873
|
+
});
|
|
3874
|
+
flags.command("archive").description("Archive a flag").requiredOption("--key <key>", "Flag key").action(async (opts, command) => {
|
|
3875
|
+
const runtime = getRuntime(command);
|
|
3876
|
+
const client = await createCliApiClient(runtime);
|
|
3877
|
+
const { projectId } = await resolveProjectId(client, runtime);
|
|
3878
|
+
const existing = await client.flag.get({
|
|
3879
|
+
projectId,
|
|
3880
|
+
key: opts.key
|
|
3881
|
+
}).catch(mapApiError);
|
|
3882
|
+
if (!await confirm(runtime, `Archive flag ${existing.key}?`)) throw new CliError("validation_error", "Archive cancelled");
|
|
3883
|
+
const archived = await client.flag.archive({ flagId: existing.id }).catch(mapApiError);
|
|
3884
|
+
printResult(runtime, archived, `Archived flag ${archived.key}`);
|
|
3885
|
+
});
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
//#endregion
|
|
3889
|
+
//#region src/commands/projects.ts
|
|
3890
|
+
function registerProjectsCommands(program) {
|
|
3891
|
+
program.command("projects").description("Project operations").command("list").description("List projects in the active organization").action(async (_opts, command) => {
|
|
3892
|
+
const runtime = getRuntime(command);
|
|
3893
|
+
const result = await (await createCliApiClient(runtime)).project.list({}).catch(mapApiError);
|
|
3894
|
+
if (runtime.json) {
|
|
3895
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3896
|
+
return;
|
|
3897
|
+
}
|
|
3898
|
+
if (result.length === 0) {
|
|
3899
|
+
console.log("No projects.");
|
|
3900
|
+
return;
|
|
3901
|
+
}
|
|
3902
|
+
for (const project of result) console.log(`${project.slug}\t${project.name}\t${project.id}`);
|
|
3903
|
+
});
|
|
3904
|
+
}
|
|
3905
|
+
|
|
3906
|
+
//#endregion
|
|
3907
|
+
//#region src/lib/typegen.ts
|
|
3908
|
+
async function runTypegen(runtime, outPath = runtime.typesOut) {
|
|
3909
|
+
const flags = await loadLocalFlags(runtime.configFile);
|
|
3910
|
+
const absolute = path.resolve(outPath);
|
|
3911
|
+
const source = generateTypesSource(flags);
|
|
3912
|
+
fs.mkdirSync(path.dirname(absolute), { recursive: true });
|
|
3913
|
+
fs.writeFileSync(absolute, source);
|
|
3914
|
+
return {
|
|
3915
|
+
written: absolute,
|
|
3916
|
+
flagCount: flags.length
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3919
|
+
|
|
3920
|
+
//#endregion
|
|
3921
|
+
//#region src/commands/pull.ts
|
|
3922
|
+
function registerPullCommand(program) {
|
|
3923
|
+
program.command("pull").description("Regenerate shipd.config.ts from the server and run typegen").action(async (_opts, command) => {
|
|
3924
|
+
const runtime = getRuntime(command);
|
|
3925
|
+
const client = await createCliApiClient(runtime);
|
|
3926
|
+
const { projectId, environmentId } = await resolveIds(client, runtime);
|
|
3927
|
+
const localFlags = (await client.flag.pull({
|
|
3928
|
+
projectId,
|
|
3929
|
+
environmentId
|
|
3930
|
+
}).catch(mapApiError)).flags.map((flag) => ({
|
|
3931
|
+
key: flag.key,
|
|
3932
|
+
type: flag.type,
|
|
3933
|
+
default: flag.default,
|
|
3934
|
+
description: flag.description,
|
|
3935
|
+
tags: flag.tags,
|
|
3936
|
+
lifecycle: flag.lifecycle,
|
|
3937
|
+
variants: flag.variants,
|
|
3938
|
+
disabled: flag.disabled
|
|
3939
|
+
}));
|
|
3940
|
+
const source = generateShipdConfigSource(localFlags);
|
|
3941
|
+
const outPath = path.resolve(runtime.configFile);
|
|
3942
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
3943
|
+
fs.writeFileSync(outPath, source);
|
|
3944
|
+
const types = await runTypegen(runtime);
|
|
3945
|
+
printResult(runtime, {
|
|
3946
|
+
written: outPath,
|
|
3947
|
+
flagCount: localFlags.length,
|
|
3948
|
+
types
|
|
3949
|
+
}, [`Wrote ${localFlags.length} flag(s) to ${outPath}`, `Wrote types for ${types.flagCount} flag(s) to ${types.written}`].join("\n"));
|
|
3950
|
+
});
|
|
3951
|
+
}
|
|
3952
|
+
|
|
3953
|
+
//#endregion
|
|
3954
|
+
//#region src/commands/push.ts
|
|
3955
|
+
function expectedVersionsFromChanges(changes) {
|
|
3956
|
+
const expected = {};
|
|
3957
|
+
for (const change of changes) if (change.before?.version !== void 0) expected[change.key] = {
|
|
3958
|
+
version: change.before.version,
|
|
3959
|
+
...change.before.environmentVersion !== void 0 ? { environmentVersion: change.before.environmentVersion } : {}
|
|
3960
|
+
};
|
|
3961
|
+
return expected;
|
|
3962
|
+
}
|
|
3963
|
+
function warnRemoteOnly(keys, json) {
|
|
3964
|
+
if (keys.length === 0 || json) return;
|
|
3965
|
+
console.error(`Warning: ${keys.length} remote flag(s) not in local config (pass --prune to archive):`);
|
|
3966
|
+
for (const key of keys) console.error(` - ${key}`);
|
|
3967
|
+
}
|
|
3968
|
+
function registerPushCommand(program) {
|
|
3969
|
+
program.command("push").description("Plan and apply local flag definitions to the server").option("--prune", "Archive remote flags missing from local config", false).option("--force", "Override stale-version conflicts (audited); does not adopt ownership", false).option("--adopt", "Link local flags to remote non-code flags by key", false).action(async (opts, command) => {
|
|
3970
|
+
const runtime = getRuntime(command);
|
|
3971
|
+
const client = await createCliApiClient(runtime);
|
|
3972
|
+
const { projectId, environmentId } = await resolveIds(client, runtime);
|
|
3973
|
+
const localFlags = await loadLocalFlags(runtime.configFile);
|
|
3974
|
+
const prune = opts.prune === true;
|
|
3975
|
+
const force = opts.force === true;
|
|
3976
|
+
const adopt = opts.adopt === true;
|
|
3977
|
+
const planned = await client.flag.push({
|
|
3978
|
+
projectId,
|
|
3979
|
+
environmentId,
|
|
3980
|
+
flags: localFlags,
|
|
3981
|
+
apply: false,
|
|
3982
|
+
prune,
|
|
3983
|
+
force,
|
|
3984
|
+
adopt
|
|
3985
|
+
}).catch(mapApiError);
|
|
3986
|
+
const plan = buildSyncPlan(planned.changes);
|
|
3987
|
+
const remoteOnly = planned.remoteOnly ?? [];
|
|
3988
|
+
warnRemoteOnly(remoteOnly.map((flag) => flag.key), runtime.json);
|
|
3989
|
+
if (!runtime.json) console.log(planIsEmpty(plan) ? "Nothing to push." : formatSyncPlan(plan));
|
|
3990
|
+
if (plan.unlinked.length > 0 && !adopt) throw new CliError("unlinked", `${plan.unlinked.length} unlinked flag(s). Pass --adopt to link ownership to code.`, {
|
|
3991
|
+
exitCode: 4,
|
|
3992
|
+
details: { keys: plan.unlinked.map((item) => item.key) }
|
|
3993
|
+
});
|
|
3994
|
+
if (!(planHasDrift(plan) || adopt && plan.updates.length > 0)) {
|
|
3995
|
+
if (runtime.json) console.log(JSON.stringify({
|
|
3996
|
+
plan,
|
|
3997
|
+
remoteOnly
|
|
3998
|
+
}, null, 2));
|
|
3999
|
+
return;
|
|
4000
|
+
}
|
|
4001
|
+
if (planHasDefinitionChanges(plan) && !runtime.json) console.error("Note: definition/ownership changes apply to all environments (requires production permission).");
|
|
4002
|
+
if (!await confirm(runtime, "Apply this plan?")) throw new CliError("validation_error", "Push cancelled (pass --yes or --ci to apply non-interactively)");
|
|
4003
|
+
const expectedVersions = expectedVersionsFromChanges(planned.changes);
|
|
4004
|
+
const applied = await client.flag.push({
|
|
4005
|
+
projectId,
|
|
4006
|
+
environmentId,
|
|
4007
|
+
flags: localFlags,
|
|
4008
|
+
apply: true,
|
|
4009
|
+
prune,
|
|
4010
|
+
force,
|
|
4011
|
+
adopt,
|
|
4012
|
+
expectedVersions
|
|
4013
|
+
}).catch(mapApiError);
|
|
4014
|
+
const appliedPlan = buildSyncPlan(applied.changes);
|
|
4015
|
+
const types = await runTypegen(runtime);
|
|
4016
|
+
printResult(runtime, {
|
|
4017
|
+
plan: appliedPlan,
|
|
4018
|
+
remoteOnly,
|
|
4019
|
+
forced: applied.forced === true,
|
|
4020
|
+
adopted: applied.adopted === true,
|
|
4021
|
+
types
|
|
4022
|
+
}, [
|
|
4023
|
+
`Applied ${applied.changes.length} change(s).`,
|
|
4024
|
+
applied.forced ? "Forced through version conflicts (audited)." : null,
|
|
4025
|
+
applied.adopted ? "Adopted remote ownership to code." : null,
|
|
4026
|
+
`Wrote types for ${types.flagCount} flag(s) to ${types.written}`
|
|
4027
|
+
].filter(Boolean).join("\n"));
|
|
4028
|
+
});
|
|
4029
|
+
}
|
|
4030
|
+
|
|
4031
|
+
//#endregion
|
|
4032
|
+
//#region src/commands/snapshots.ts
|
|
4033
|
+
function registerSnapshotsCommands(program) {
|
|
4034
|
+
program.command("snapshots").description("Data-plane snapshot operations").command("publish").description("Materialize the environment snapshot from Postgres and publish to the data plane").action(async (_opts, command) => {
|
|
4035
|
+
const runtime = getRuntime(command);
|
|
4036
|
+
const client = await createCliApiClient(runtime);
|
|
4037
|
+
const { environmentId } = await resolveIds(client, runtime);
|
|
4038
|
+
const result = await client.snapshot.publish({ environmentId }).catch(mapApiError);
|
|
4039
|
+
if (runtime.json) {
|
|
4040
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4041
|
+
return;
|
|
4042
|
+
}
|
|
4043
|
+
console.log(`Published ${result.environmentKey} v${result.version} (${result.flagCount} flags) → ${result.keys.current}`);
|
|
4044
|
+
});
|
|
4045
|
+
}
|
|
4046
|
+
|
|
4047
|
+
//#endregion
|
|
4048
|
+
//#region src/commands/types.ts
|
|
4049
|
+
function registerTypesCommands(program) {
|
|
4050
|
+
program.command("types").description("Type generation helpers").command("gen").description("Generate TypeScript types from shipd.config.ts").option("-o, --out <path>", "Output file path").action(async (opts, command) => {
|
|
4051
|
+
const runtime = getRuntime(command);
|
|
4052
|
+
const result = await runTypegen(runtime, opts.out ?? runtime.typesOut);
|
|
4053
|
+
printResult(runtime, result, `Wrote types for ${result.flagCount} flag(s) to ${result.written}`);
|
|
4054
|
+
});
|
|
4055
|
+
}
|
|
4056
|
+
|
|
4057
|
+
//#endregion
|
|
4058
|
+
//#region src/index.ts
|
|
4059
|
+
/** Detected before parse so usage errors can suppress Commander text under `--json`. */
|
|
4060
|
+
const jsonRequested = process.argv.includes("--json");
|
|
4061
|
+
const program = new Command().name("shipd").description("shipd CLI — flags as code").option("--json", "Machine-readable JSON output", false).option("--yes", "Skip confirmation prompts", false).option("--ci", "Non-interactive mode (same as --yes / CI=1)", false).option("--api-url <url>", "API origin").option("--org <slug>", "Organization slug (session: select; API key: must match)").option("--project <slug>", "Project slug").option("--env <slug>", "Environment slug").option("--config <path>", "Project settings JSON (.shipd/config.json shape)").option("--flags-config <path>", "Path to shipd.config.ts").exitOverride().showHelpAfterError(!jsonRequested);
|
|
4062
|
+
if (jsonRequested) program.configureOutput({
|
|
4063
|
+
writeErr: () => {},
|
|
4064
|
+
writeOut: () => {}
|
|
4065
|
+
});
|
|
4066
|
+
registerAuthCommands(program);
|
|
4067
|
+
registerPullCommand(program);
|
|
4068
|
+
registerDiffCommand(program);
|
|
4069
|
+
registerPushCommand(program);
|
|
4070
|
+
registerTypesCommands(program);
|
|
4071
|
+
registerFlagsCommands(program);
|
|
4072
|
+
registerProjectsCommands(program);
|
|
4073
|
+
registerEnvironmentsCommands(program);
|
|
4074
|
+
registerSnapshotsCommands(program);
|
|
4075
|
+
function commanderMessage(error) {
|
|
4076
|
+
return error.message.replace(/^error:\s*/i, "");
|
|
4077
|
+
}
|
|
4078
|
+
async function main() {
|
|
4079
|
+
try {
|
|
4080
|
+
await program.parseAsync(process.argv);
|
|
4081
|
+
} catch (error) {
|
|
4082
|
+
if (error instanceof CommanderError && (error.code === "commander.helpDisplayed" || error.code === "commander.version")) {
|
|
4083
|
+
process.exitCode = error.exitCode;
|
|
4084
|
+
return;
|
|
4085
|
+
}
|
|
4086
|
+
const json = jsonRequested || program.opts().json === true;
|
|
4087
|
+
if (error instanceof CommanderError) {
|
|
4088
|
+
if (json) console.error(JSON.stringify({ error: {
|
|
4089
|
+
code: "validation_error",
|
|
4090
|
+
message: commanderMessage(error)
|
|
4091
|
+
} }));
|
|
4092
|
+
process.exitCode = error.exitCode;
|
|
4093
|
+
return;
|
|
4094
|
+
}
|
|
4095
|
+
if (json) {
|
|
4096
|
+
const payload = error instanceof CliError ? { error: {
|
|
4097
|
+
code: error.code,
|
|
4098
|
+
message: error.message,
|
|
4099
|
+
details: error.details
|
|
4100
|
+
} } : { error: {
|
|
4101
|
+
code: "internal",
|
|
4102
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4103
|
+
} };
|
|
4104
|
+
console.error(JSON.stringify(payload));
|
|
4105
|
+
} else if (error instanceof CliError) console.error(`Error: ${error.message}`);
|
|
4106
|
+
else if (error instanceof Error) console.error(`Error: ${error.message}`);
|
|
4107
|
+
else console.error(String(error));
|
|
4108
|
+
process.exitCode = exitCodeForError(error);
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
main();
|
|
4112
|
+
|
|
4113
|
+
//#endregion
|
|
4114
|
+
export { };
|