@relyio/cli 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1362 -807
- package/package.json +9 -7
- package/templates/frameworks/next/app/api/relyio/draft/route.ts.tmpl +4 -0
- package/templates/frameworks/next/app/api/relyio/revalidate/route.ts.tmpl +4 -0
- package/templates/frameworks/next/lib/relyio.ts.tmpl +8 -0
- package/templates/frameworks/next/next.config.ts.tmpl +12 -0
- package/templates/frameworks/next/relyio-image-loader.ts.tmpl +2 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import http from 'http';
|
|
2
3
|
import * as fs2 from 'fs';
|
|
3
|
-
import { existsSync, readdirSync,
|
|
4
|
-
import
|
|
4
|
+
import fs2__default, { existsSync, readFileSync, mkdirSync, readdirSync, writeFileSync, statSync, cpSync } from 'fs';
|
|
5
|
+
import path5 from 'path';
|
|
5
6
|
import * as os from 'os';
|
|
6
7
|
import os__default from 'os';
|
|
7
8
|
import * as yaml from 'yaml';
|
|
@@ -9,17 +10,18 @@ import axios, { AxiosError } from 'axios';
|
|
|
9
10
|
import axiosRetry from 'axios-retry';
|
|
10
11
|
import { z } from 'zod';
|
|
11
12
|
import * as fs4 from 'fs/promises';
|
|
12
|
-
import {
|
|
13
|
+
import { rm, writeFile, readFile, stat, mkdir } from 'fs/promises';
|
|
13
14
|
import * as yaml2 from 'js-yaml';
|
|
14
15
|
import { glob } from 'glob';
|
|
15
16
|
import { createJiti } from 'jiti';
|
|
16
17
|
import { fileURLToPath } from 'url';
|
|
17
18
|
import { execFileSync, execSync, spawn } from 'child_process';
|
|
19
|
+
import Handlebars from 'handlebars';
|
|
18
20
|
import 'object-hash';
|
|
19
21
|
import 'semver';
|
|
20
22
|
import { format } from 'prettier';
|
|
21
23
|
import { structuredPatch, diffWordsWithSpace } from 'diff';
|
|
22
|
-
import { randomUUID, createHash } from 'crypto';
|
|
24
|
+
import { randomBytes, randomUUID, createHash } from 'crypto';
|
|
23
25
|
import React3, { createContext, memo, useState, useEffect, useReducer, useMemo, useCallback, useContext, useRef, useSyncExternalStore } from 'react';
|
|
24
26
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
25
27
|
import { Box, Text, useApp, Static, useInput, usePaste, useWindowSize } from 'ink';
|
|
@@ -35,13 +37,11 @@ import figures from 'figures';
|
|
|
35
37
|
import { table as table$1 } from 'table';
|
|
36
38
|
import readline from 'readline';
|
|
37
39
|
import open from 'open';
|
|
38
|
-
import
|
|
39
|
-
import inquirer from 'inquirer';
|
|
40
|
+
import inquirer2 from 'inquirer';
|
|
40
41
|
import { Listr } from 'listr2';
|
|
41
42
|
import 'strip-ansi';
|
|
42
43
|
import { watch } from 'chokidar';
|
|
43
44
|
import { EventEmitter } from 'events';
|
|
44
|
-
import Handlebars from 'handlebars';
|
|
45
45
|
|
|
46
46
|
var __defProp = Object.defineProperty;
|
|
47
47
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -52,6 +52,143 @@ var __export = (target, all) => {
|
|
|
52
52
|
for (var name in all)
|
|
53
53
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
54
54
|
};
|
|
55
|
+
async function startCallbackServer(options = {}) {
|
|
56
|
+
const host = options.host ?? "127.0.0.1";
|
|
57
|
+
const callbackPath = options.callbackPath ?? "/callback";
|
|
58
|
+
const server = http.createServer();
|
|
59
|
+
await new Promise((resolve, reject) => {
|
|
60
|
+
server.once("error", reject);
|
|
61
|
+
server.listen(0, host, resolve);
|
|
62
|
+
});
|
|
63
|
+
const { port } = server.address();
|
|
64
|
+
const origin = `http://${host}:${port}`;
|
|
65
|
+
const redirectUri = `${origin}${callbackPath === "/" ? "" : callbackPath}`;
|
|
66
|
+
let settled = false;
|
|
67
|
+
let waiter;
|
|
68
|
+
const held = [];
|
|
69
|
+
const close = () => {
|
|
70
|
+
try {
|
|
71
|
+
server.close();
|
|
72
|
+
server.closeAllConnections?.();
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const decide = (query, res, active) => {
|
|
77
|
+
if (query.get("state") !== active.expectedState) {
|
|
78
|
+
settled = true;
|
|
79
|
+
html(res, 400, errorHtml("State mismatch"));
|
|
80
|
+
close();
|
|
81
|
+
active.settle({
|
|
82
|
+
ok: false,
|
|
83
|
+
error: new Error("Sign-in state mismatch \u2014 aborting for safety.")
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const error2 = query.get("error");
|
|
88
|
+
if (error2 !== null) {
|
|
89
|
+
settled = true;
|
|
90
|
+
html(res, 400, errorHtml(error2));
|
|
91
|
+
close();
|
|
92
|
+
active.settle({ ok: false, error: new Error(`Authorization failed: ${error2}`) });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
settled = true;
|
|
96
|
+
html(res, 200, SUCCESS_HTML);
|
|
97
|
+
close();
|
|
98
|
+
active.settle({ ok: true, query });
|
|
99
|
+
};
|
|
100
|
+
server.on("request", (req, res) => {
|
|
101
|
+
const url = new URL(req.url ?? "/", origin);
|
|
102
|
+
if (url.pathname !== callbackPath) {
|
|
103
|
+
res.writeHead(404).end();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (settled) {
|
|
107
|
+
html(res, 200, SUCCESS_HTML);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (url.search === "") {
|
|
111
|
+
html(res, 200, WAITING_HTML);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (waiter === void 0) {
|
|
115
|
+
held.push({ query: url.searchParams, res });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
decide(url.searchParams, res, waiter);
|
|
119
|
+
});
|
|
120
|
+
const waitForCallback = (expectedState, timeoutMs = DEFAULT_CALLBACK_TIMEOUT_MS) => new Promise((resolve, reject) => {
|
|
121
|
+
const timer = setTimeout(() => {
|
|
122
|
+
if (settled) return;
|
|
123
|
+
settled = true;
|
|
124
|
+
close();
|
|
125
|
+
reject(new Error("Timed out waiting for the browser sign-in to complete."));
|
|
126
|
+
}, timeoutMs);
|
|
127
|
+
timer.unref?.();
|
|
128
|
+
const active = {
|
|
129
|
+
expectedState,
|
|
130
|
+
settle: (outcome) => {
|
|
131
|
+
clearTimeout(timer);
|
|
132
|
+
if (outcome.ok) resolve(outcome.query);
|
|
133
|
+
else reject(outcome.error);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
waiter = active;
|
|
137
|
+
const [first, ...rest] = held.splice(0);
|
|
138
|
+
for (const extra of rest) html(extra.res, 200, SUCCESS_HTML);
|
|
139
|
+
if (first) decide(first.query, first.res, active);
|
|
140
|
+
});
|
|
141
|
+
const waitForCode = async (expectedState, timeoutMs) => {
|
|
142
|
+
const query = await waitForCallback(expectedState, timeoutMs);
|
|
143
|
+
const code = query.get("code");
|
|
144
|
+
if (code === null || code === "") {
|
|
145
|
+
throw new Error("The sign-in callback carried no authorization code.");
|
|
146
|
+
}
|
|
147
|
+
return code;
|
|
148
|
+
};
|
|
149
|
+
return { redirectUri, waitForCallback, waitForCode, close };
|
|
150
|
+
}
|
|
151
|
+
function escapeHtml(value) {
|
|
152
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
153
|
+
}
|
|
154
|
+
function writeSecretFile(filePath, data) {
|
|
155
|
+
fs2__default.mkdirSync(path5.dirname(filePath), { recursive: true });
|
|
156
|
+
fs2__default.writeFileSync(filePath, JSON.stringify(data, null, 2), {
|
|
157
|
+
encoding: "utf8",
|
|
158
|
+
mode: SECRET_FILE_MODE
|
|
159
|
+
});
|
|
160
|
+
fs2__default.chmodSync(filePath, SECRET_FILE_MODE);
|
|
161
|
+
}
|
|
162
|
+
function readSecretFile(filePath) {
|
|
163
|
+
try {
|
|
164
|
+
if (!fs2__default.existsSync(filePath)) return null;
|
|
165
|
+
return JSON.parse(fs2__default.readFileSync(filePath, "utf8"));
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
var DEFAULT_CALLBACK_TIMEOUT_MS, SUCCESS_HTML, WAITING_HTML, errorHtml, html, SECRET_FILE_MODE;
|
|
171
|
+
var init_dist = __esm({
|
|
172
|
+
"../device-auth/dist/index.js"() {
|
|
173
|
+
DEFAULT_CALLBACK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
174
|
+
SUCCESS_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>RelyIO</title>
|
|
175
|
+
<style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;text-align:center;padding:3rem;color:#111}h1{color:#16a34a}</style>
|
|
176
|
+
</head><body><h1>Connected to RelyIO</h1><p>Authentication succeeded. You can close this tab and return to your terminal.</p></body></html>`;
|
|
177
|
+
WAITING_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>RelyIO</title>
|
|
178
|
+
<style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;text-align:center;padding:3rem;color:#111}</style>
|
|
179
|
+
</head><body><h1>Waiting for RelyIO</h1><p>Finish signing in in the tab that opened, then come back here.</p></body></html>`;
|
|
180
|
+
errorHtml = (message) => `<!doctype html><html><head><meta charset="utf-8"><title>RelyIO</title>
|
|
181
|
+
<style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;text-align:center;padding:3rem;color:#111}h1{color:#dc2626}</style>
|
|
182
|
+
</head><body><h1>Authentication failed</h1><p>${escapeHtml(message)}</p></body></html>`;
|
|
183
|
+
html = (res, status, body) => {
|
|
184
|
+
res.writeHead(status, {
|
|
185
|
+
"content-type": "text/html; charset=utf-8",
|
|
186
|
+
"cache-control": "no-store"
|
|
187
|
+
}).end(body);
|
|
188
|
+
};
|
|
189
|
+
SECRET_FILE_MODE = 384;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
55
192
|
|
|
56
193
|
// src/config/secret-store.ts
|
|
57
194
|
var secret_store_exports = {};
|
|
@@ -91,19 +228,10 @@ function emitPlaintextWarning() {
|
|
|
91
228
|
);
|
|
92
229
|
}
|
|
93
230
|
function readLegacyFile() {
|
|
94
|
-
|
|
95
|
-
if (!fs2.existsSync(LEGACY_CONFIG_FILE)) return {};
|
|
96
|
-
const raw = fs2.readFileSync(LEGACY_CONFIG_FILE, "utf8");
|
|
97
|
-
return JSON.parse(raw);
|
|
98
|
-
} catch {
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
231
|
+
return readSecretFile(LEGACY_CONFIG_FILE) ?? {};
|
|
101
232
|
}
|
|
102
233
|
function writeLegacyFile(data) {
|
|
103
|
-
|
|
104
|
-
fs2.mkdirSync(LEGACY_CONFIG_DIR, { recursive: true });
|
|
105
|
-
}
|
|
106
|
-
fs2.writeFileSync(LEGACY_CONFIG_FILE, JSON.stringify(data, null, 2), "utf8");
|
|
234
|
+
writeSecretFile(LEGACY_CONFIG_FILE, data);
|
|
107
235
|
}
|
|
108
236
|
async function setSecret(key, value) {
|
|
109
237
|
cache.set(key, value);
|
|
@@ -183,9 +311,10 @@ function __resetForTests() {
|
|
|
183
311
|
var SERVICE_NAME, LEGACY_CONFIG_DIR, LEGACY_CONFIG_FILE, keytarPromise, keychainAvailable, plaintextWarningShown, cache;
|
|
184
312
|
var init_secret_store = __esm({
|
|
185
313
|
"src/config/secret-store.ts"() {
|
|
314
|
+
init_dist();
|
|
186
315
|
SERVICE_NAME = "relyio-cli";
|
|
187
|
-
LEGACY_CONFIG_DIR =
|
|
188
|
-
LEGACY_CONFIG_FILE =
|
|
316
|
+
LEGACY_CONFIG_DIR = path5.join(os.homedir(), ".relyio");
|
|
317
|
+
LEGACY_CONFIG_FILE = path5.join(LEGACY_CONFIG_DIR, "config.json");
|
|
189
318
|
plaintextWarningShown = false;
|
|
190
319
|
cache = /* @__PURE__ */ new Map();
|
|
191
320
|
}
|
|
@@ -233,28 +362,19 @@ function ensureDirectory(dir) {
|
|
|
233
362
|
}
|
|
234
363
|
}
|
|
235
364
|
function readGlobalConfig() {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (fs2.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
239
|
-
const configData = fs2.readFileSync(GLOBAL_CONFIG_FILE, "utf8");
|
|
240
|
-
return JSON.parse(configData);
|
|
241
|
-
}
|
|
242
|
-
} catch (error2) {
|
|
243
|
-
debugError("Error reading global config", error2);
|
|
244
|
-
}
|
|
245
|
-
return { ...defaultGlobalConfig };
|
|
365
|
+
const stored = readSecretFile(GLOBAL_CONFIG_FILE);
|
|
366
|
+
return stored ?? { ...defaultGlobalConfig };
|
|
246
367
|
}
|
|
247
368
|
function writeGlobalConfig(config) {
|
|
248
369
|
try {
|
|
249
|
-
|
|
250
|
-
fs2.writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2), "utf8");
|
|
370
|
+
writeSecretFile(GLOBAL_CONFIG_FILE, config);
|
|
251
371
|
} catch (error2) {
|
|
252
372
|
debugError("Error writing global config", error2);
|
|
253
373
|
throw new Error("Failed to write global configuration");
|
|
254
374
|
}
|
|
255
375
|
}
|
|
256
376
|
function getProjectConfigPath() {
|
|
257
|
-
return
|
|
377
|
+
return path5.join(process.cwd(), PROJECT_CONFIG_FILE);
|
|
258
378
|
}
|
|
259
379
|
function readProjectConfig() {
|
|
260
380
|
try {
|
|
@@ -278,7 +398,7 @@ function writeProjectConfig(config) {
|
|
|
278
398
|
}
|
|
279
399
|
}
|
|
280
400
|
function getLocalConfigPath() {
|
|
281
|
-
return
|
|
401
|
+
return path5.join(process.cwd(), LOCAL_CONFIG_FILE);
|
|
282
402
|
}
|
|
283
403
|
function readLocalConfig() {
|
|
284
404
|
try {
|
|
@@ -294,7 +414,7 @@ function readLocalConfig() {
|
|
|
294
414
|
}
|
|
295
415
|
function writeLocalConfig(config) {
|
|
296
416
|
try {
|
|
297
|
-
const configDir =
|
|
417
|
+
const configDir = path5.join(process.cwd(), LOCAL_CONFIG_DIR);
|
|
298
418
|
ensureDirectory(configDir);
|
|
299
419
|
const configPath = getLocalConfigPath();
|
|
300
420
|
fs2.writeFileSync(configPath, yaml.stringify(config), "utf8");
|
|
@@ -428,13 +548,14 @@ async function isAuthenticated() {
|
|
|
428
548
|
var isDebug, GLOBAL_CONFIG_DIR, GLOBAL_CONFIG_FILE, PROJECT_CONFIG_FILE, LOCAL_CONFIG_DIR, LOCAL_CONFIG_FILE, PROD_API_URL, PROD_DASHBOARD_URL, defaultGlobalConfig, defaultProjectConfig, defaultLocalConfig, getAuthTokenAsync, getApiKeyAsync, config_manager_default;
|
|
429
549
|
var init_config_manager = __esm({
|
|
430
550
|
"src/config/config-manager.ts"() {
|
|
551
|
+
init_dist();
|
|
431
552
|
init_secret_store();
|
|
432
553
|
isDebug = () => process.env.DEBUG === "true" || process.env.DEBUG === "1";
|
|
433
|
-
GLOBAL_CONFIG_DIR =
|
|
434
|
-
GLOBAL_CONFIG_FILE =
|
|
554
|
+
GLOBAL_CONFIG_DIR = path5.join(os.homedir(), ".relyio");
|
|
555
|
+
GLOBAL_CONFIG_FILE = path5.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
435
556
|
PROJECT_CONFIG_FILE = ".relyio-context.json";
|
|
436
557
|
LOCAL_CONFIG_DIR = "relyio";
|
|
437
|
-
LOCAL_CONFIG_FILE =
|
|
558
|
+
LOCAL_CONFIG_FILE = path5.join(LOCAL_CONFIG_DIR, "config.yaml");
|
|
438
559
|
PROD_API_URL = "https://api.relyio.com";
|
|
439
560
|
PROD_DASHBOARD_URL = "https://dashboard.relyio.com";
|
|
440
561
|
defaultGlobalConfig = {};
|
|
@@ -542,12 +663,32 @@ var init_config = __esm({
|
|
|
542
663
|
config_default = config_manager_default;
|
|
543
664
|
}
|
|
544
665
|
});
|
|
545
|
-
|
|
666
|
+
function redactForLog(data) {
|
|
667
|
+
if (typeof data === "string") {
|
|
668
|
+
try {
|
|
669
|
+
return redactForLog(JSON.parse(data));
|
|
670
|
+
} catch {
|
|
671
|
+
return data;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (Array.isArray(data)) return data.map((item) => redactForLog(item));
|
|
675
|
+
if (typeof data === "object" && data !== null) {
|
|
676
|
+
return Object.fromEntries(
|
|
677
|
+
Object.entries(data).map(([key, value]) => [
|
|
678
|
+
key,
|
|
679
|
+
SECRET_FIELD.test(key) ? "***" : redactForLog(value)
|
|
680
|
+
])
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
return data;
|
|
684
|
+
}
|
|
685
|
+
var DEFAULT_TIMEOUT_MS, isDebug2, SECRET_FIELD, ApiClient, apiClient, client_default;
|
|
546
686
|
var init_client = __esm({
|
|
547
687
|
"src/api/client.ts"() {
|
|
548
688
|
init_config();
|
|
549
689
|
DEFAULT_TIMEOUT_MS = 3e4;
|
|
550
690
|
isDebug2 = () => process.env.DEBUG === "true" || process.env.DEBUG === "1";
|
|
691
|
+
SECRET_FIELD = /secret|token|password/i;
|
|
551
692
|
ApiClient = class {
|
|
552
693
|
client;
|
|
553
694
|
constructor() {
|
|
@@ -635,9 +776,8 @@ var init_client = __esm({
|
|
|
635
776
|
}
|
|
636
777
|
}
|
|
637
778
|
if (reqConfig.data) {
|
|
638
|
-
const data = typeof reqConfig.data === "string" ? reqConfig.data : JSON.stringify(reqConfig.data);
|
|
639
779
|
curlCommand += ` \\
|
|
640
|
-
-d '${data}'`;
|
|
780
|
+
-d '${JSON.stringify(redactForLog(reqConfig.data))}'`;
|
|
641
781
|
}
|
|
642
782
|
console.error(`[relyio-cli][debug] ${curlCommand}`);
|
|
643
783
|
}
|
|
@@ -682,21 +822,21 @@ var init_client = __esm({
|
|
|
682
822
|
}
|
|
683
823
|
}
|
|
684
824
|
// Helper methods for common HTTP methods
|
|
685
|
-
async get(
|
|
825
|
+
async get(path25, options) {
|
|
686
826
|
return this.request({
|
|
687
827
|
method: "GET",
|
|
688
|
-
url:
|
|
828
|
+
url: path25,
|
|
689
829
|
params: options?.params,
|
|
690
830
|
headers: options?.headers
|
|
691
831
|
});
|
|
692
832
|
}
|
|
693
|
-
async post(
|
|
694
|
-
return this.request({ method: "POST", url:
|
|
833
|
+
async post(path25, data, headers) {
|
|
834
|
+
return this.request({ method: "POST", url: path25, data, headers });
|
|
695
835
|
}
|
|
696
|
-
async put(
|
|
697
|
-
return this.request({ method: "PUT", url:
|
|
836
|
+
async put(path25, data, headers) {
|
|
837
|
+
return this.request({ method: "PUT", url: path25, data, headers });
|
|
698
838
|
}
|
|
699
|
-
async delete(
|
|
839
|
+
async delete(path25, headers) {
|
|
700
840
|
const customHeaders = {
|
|
701
841
|
...headers,
|
|
702
842
|
// Remove Content-Type for DELETE requests as they typically don't have a body
|
|
@@ -704,7 +844,7 @@ var init_client = __esm({
|
|
|
704
844
|
};
|
|
705
845
|
return this.request({
|
|
706
846
|
method: "DELETE",
|
|
707
|
-
url:
|
|
847
|
+
url: path25,
|
|
708
848
|
headers: customHeaders
|
|
709
849
|
});
|
|
710
850
|
}
|
|
@@ -714,38 +854,10 @@ var init_client = __esm({
|
|
|
714
854
|
}
|
|
715
855
|
});
|
|
716
856
|
|
|
717
|
-
//
|
|
718
|
-
async function getSchemaStatus(projectId, branchId, localSchema) {
|
|
719
|
-
const response = await client_default.post(
|
|
720
|
-
`/projects/${projectId}/branches/${branchId}/schema/status`,
|
|
721
|
-
localSchema || {}
|
|
722
|
-
);
|
|
723
|
-
return response.data;
|
|
724
|
-
}
|
|
725
|
-
async function deploySchema(projectId, branchId, localSchema, options) {
|
|
726
|
-
const response = await client_default.post(
|
|
727
|
-
`/projects/${projectId}/branches/${branchId}/schema/deploy`,
|
|
728
|
-
{
|
|
729
|
-
localSchema,
|
|
730
|
-
...options
|
|
731
|
-
}
|
|
732
|
-
);
|
|
733
|
-
const data = response.data;
|
|
734
|
-
if ("data" in data && typeof data.data === "object") {
|
|
735
|
-
return data.data;
|
|
736
|
-
}
|
|
737
|
-
return data;
|
|
738
|
-
}
|
|
739
|
-
var init_schema = __esm({
|
|
740
|
-
"src/api/schema.ts"() {
|
|
741
|
-
init_client();
|
|
742
|
-
}
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
// ../../platform/api-contract/dist/chunk-QKXHDVSP.js
|
|
857
|
+
// ../../platform/api-contract/dist/chunk-MFO7NR2F.js
|
|
746
858
|
var ERROR_CODES;
|
|
747
|
-
var
|
|
748
|
-
"../../platform/api-contract/dist/chunk-
|
|
859
|
+
var init_chunk_MFO7NR2F = __esm({
|
|
860
|
+
"../../platform/api-contract/dist/chunk-MFO7NR2F.js"() {
|
|
749
861
|
ERROR_CODES = {
|
|
750
862
|
MISSING_API_KEY: { status: 401 },
|
|
751
863
|
INVALID_API_KEY: { status: 401 },
|
|
@@ -757,7 +869,7 @@ var init_chunk_QKXHDVSP = __esm({
|
|
|
757
869
|
REQUEST_INVALID: { status: 400 },
|
|
758
870
|
CONTENT_INVALID: { status: 400 },
|
|
759
871
|
/**
|
|
760
|
-
* Added in API3a,
|
|
872
|
+
* Added in API3a, the first name added to §4's approved seventeen.
|
|
761
873
|
*
|
|
762
874
|
* `apps/edge/cdn` answers any method other than `GET`, `HEAD` or `OPTIONS`
|
|
763
875
|
* with `405`, and no code in §4 carries that status. The two alternatives
|
|
@@ -775,6 +887,37 @@ var init_chunk_QKXHDVSP = __esm({
|
|
|
775
887
|
* approves those. Approved 2026-09-06 (plan §4, decision record in §16 API3a).
|
|
776
888
|
*/
|
|
777
889
|
METHOD_NOT_ALLOWED: { status: 405 },
|
|
890
|
+
/**
|
|
891
|
+
* Added by REL-657, the second name added to §4's approved seventeen.
|
|
892
|
+
*
|
|
893
|
+
* A session that verified a factor too long ago may not hand authority out:
|
|
894
|
+
* mint an Access Token, approve an app, delete the account. `ACCESS_DENIED`
|
|
895
|
+
* is what a subject may never do; this is what a subject may do once they
|
|
896
|
+
* have proved the session is still theirs, and a client does something
|
|
897
|
+
* different on reading it — it raises a Reverification and retries — which
|
|
898
|
+
* is Decision 3's test. `details.level` names the proof the client asks for.
|
|
899
|
+
*
|
|
900
|
+
* A **customer-facing naming decision**, approved by the product owner on
|
|
901
|
+
* 2026-09-20 (REL-657, spec 016).
|
|
902
|
+
*/
|
|
903
|
+
REVERIFICATION_REQUIRED: { status: 403 },
|
|
904
|
+
/**
|
|
905
|
+
* Added by REL-1080, the third name added to §4's approved seventeen.
|
|
906
|
+
*
|
|
907
|
+
* A downgrade (or cancel) that would leave the Organization keeping more than
|
|
908
|
+
* the target Plan allows — more Projects, Members or stored bytes than its
|
|
909
|
+
* Stock Limits — is refused, because the lower Plan would otherwise keep
|
|
910
|
+
* serving what it refuses to admit. It is not `ACCESS_DENIED` (the subject may
|
|
911
|
+
* downgrade) and not `RESOURCE_CONFLICT` (no version raced): a client reading
|
|
912
|
+
* it does something no other code tells it — shows `details.stockLimits`, the
|
|
913
|
+
* same list the downgrade preview reads, and asks the customer to reduce what
|
|
914
|
+
* they keep before retrying. 409 because the request conflicts with the
|
|
915
|
+
* Organization's current state and succeeds unchanged once that state does.
|
|
916
|
+
*
|
|
917
|
+
* A **customer-facing naming decision**, approved by the product owner on
|
|
918
|
+
* 2026-09-24 (REL-1080).
|
|
919
|
+
*/
|
|
920
|
+
PLAN_DOWNGRADE_BLOCKED: { status: 409 },
|
|
778
921
|
RESOURCE_NOT_FOUND: { status: 404 },
|
|
779
922
|
RESOURCE_CONFLICT: { status: 409 },
|
|
780
923
|
RESOURCE_EXPIRED: { status: 410 },
|
|
@@ -821,7 +964,7 @@ function readError(body) {
|
|
|
821
964
|
var ContractBodyError;
|
|
822
965
|
var init_client2 = __esm({
|
|
823
966
|
"../../platform/api-contract/dist/client/index.js"() {
|
|
824
|
-
|
|
967
|
+
init_chunk_MFO7NR2F();
|
|
825
968
|
ContractBodyError = class extends Error {
|
|
826
969
|
body;
|
|
827
970
|
constructor(message, body) {
|
|
@@ -868,9 +1011,11 @@ async function getProject(projectId) {
|
|
|
868
1011
|
}
|
|
869
1012
|
async function getProjectBranches(projectId, filter) {
|
|
870
1013
|
const params = new URLSearchParams();
|
|
871
|
-
if (filter?.name) params.append("name", filter.name);
|
|
872
|
-
if (filter?.sortField)
|
|
873
|
-
|
|
1014
|
+
if (filter?.name) params.append("name", `eq:${filter.name}`);
|
|
1015
|
+
if (filter?.sortField) {
|
|
1016
|
+
params.append("sort", filter.sortField);
|
|
1017
|
+
if (filter.sortDirection) params.append("order", filter.sortDirection);
|
|
1018
|
+
}
|
|
874
1019
|
params.append("limit", "100");
|
|
875
1020
|
const queryString = params.toString();
|
|
876
1021
|
const url = `/projects/${projectId}/branches${queryString ? `?${queryString}` : ""}`;
|
|
@@ -916,6 +1061,26 @@ async function compareBranchSchemas(projectId, sourceBranchId, targetBranchId) {
|
|
|
916
1061
|
)
|
|
917
1062
|
);
|
|
918
1063
|
}
|
|
1064
|
+
async function createProjectApiKey(projectId, body) {
|
|
1065
|
+
return readPayload(
|
|
1066
|
+
await client_default.post(`/projects/${projectId}/api-keys`, body)
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
async function getProjectConnections(projectId) {
|
|
1070
|
+
return readPayload(
|
|
1071
|
+
await client_default.get(`/projects/${projectId}/connections`)
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
async function createConnection(projectId, body) {
|
|
1075
|
+
return readPayload(
|
|
1076
|
+
await client_default.post(`/projects/${projectId}/connections`, body)
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
async function createAutomation(projectId, body) {
|
|
1080
|
+
return readPayload(
|
|
1081
|
+
await client_default.post(`/projects/${projectId}/automations`, body)
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
919
1084
|
var manage_default;
|
|
920
1085
|
var init_manage = __esm({
|
|
921
1086
|
"src/api/manage.ts"() {
|
|
@@ -932,11 +1097,43 @@ var init_manage = __esm({
|
|
|
932
1097
|
createBranchWithParentDetection,
|
|
933
1098
|
deleteBranch,
|
|
934
1099
|
getBranchDivergence,
|
|
935
|
-
compareBranchSchemas
|
|
1100
|
+
compareBranchSchemas,
|
|
1101
|
+
createProjectApiKey,
|
|
1102
|
+
getProjectConnections,
|
|
1103
|
+
createConnection,
|
|
1104
|
+
createAutomation
|
|
936
1105
|
};
|
|
937
1106
|
}
|
|
938
1107
|
});
|
|
939
1108
|
|
|
1109
|
+
// src/api/schema.ts
|
|
1110
|
+
async function getSchemaStatus(projectId, branchId, localSchema) {
|
|
1111
|
+
const response = await client_default.post(
|
|
1112
|
+
`/projects/${projectId}/branches/${branchId}/schema/status`,
|
|
1113
|
+
localSchema || {}
|
|
1114
|
+
);
|
|
1115
|
+
return response.data;
|
|
1116
|
+
}
|
|
1117
|
+
async function deploySchema(projectId, branchId, localSchema, options) {
|
|
1118
|
+
const response = await client_default.post(
|
|
1119
|
+
`/projects/${projectId}/branches/${branchId}/schema/deploy`,
|
|
1120
|
+
{
|
|
1121
|
+
localSchema,
|
|
1122
|
+
...options
|
|
1123
|
+
}
|
|
1124
|
+
);
|
|
1125
|
+
const data = response.data;
|
|
1126
|
+
if ("data" in data && typeof data.data === "object") {
|
|
1127
|
+
return data.data;
|
|
1128
|
+
}
|
|
1129
|
+
return data;
|
|
1130
|
+
}
|
|
1131
|
+
var init_schema = __esm({
|
|
1132
|
+
"src/api/schema.ts"() {
|
|
1133
|
+
init_client();
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
|
|
940
1137
|
// src/api/manage-error.ts
|
|
941
1138
|
function manageErrorBody(error2) {
|
|
942
1139
|
const candidate = error2;
|
|
@@ -977,24 +1174,24 @@ var init_manage_error = __esm({
|
|
|
977
1174
|
});
|
|
978
1175
|
function detectCircularFallback(startCode, locales) {
|
|
979
1176
|
const visited = /* @__PURE__ */ new Set();
|
|
980
|
-
const
|
|
1177
|
+
const path25 = [];
|
|
981
1178
|
const localeMap = new Map(locales.map((l) => [l.code, l]));
|
|
982
1179
|
function visit(code) {
|
|
983
1180
|
if (visited.has(code)) {
|
|
984
|
-
const cycleStart =
|
|
985
|
-
return [...
|
|
1181
|
+
const cycleStart = path25.indexOf(code);
|
|
1182
|
+
return [...path25.slice(cycleStart), code];
|
|
986
1183
|
}
|
|
987
1184
|
const locale = localeMap.get(code);
|
|
988
1185
|
if (!locale || !locale.fallback || locale.fallback.length === 0) {
|
|
989
1186
|
return null;
|
|
990
1187
|
}
|
|
991
1188
|
visited.add(code);
|
|
992
|
-
|
|
1189
|
+
path25.push(code);
|
|
993
1190
|
for (const fallbackCode of locale.fallback) {
|
|
994
1191
|
const cycle = visit(fallbackCode);
|
|
995
1192
|
if (cycle) return cycle;
|
|
996
1193
|
}
|
|
997
|
-
|
|
1194
|
+
path25.pop();
|
|
998
1195
|
visited.delete(code);
|
|
999
1196
|
return null;
|
|
1000
1197
|
}
|
|
@@ -1086,6 +1283,14 @@ var init_chunk_VGBOPF6G = __esm({
|
|
|
1086
1283
|
});
|
|
1087
1284
|
}
|
|
1088
1285
|
});
|
|
1286
|
+
|
|
1287
|
+
// ../../domain/schema/dist/chunk-JH6U6ENN.js
|
|
1288
|
+
var TIME_UNITS;
|
|
1289
|
+
var init_chunk_JH6U6ENN = __esm({
|
|
1290
|
+
"../../domain/schema/dist/chunk-JH6U6ENN.js"() {
|
|
1291
|
+
TIME_UNITS = ["minutes", "hours", "days", "weeks", "months", "years"];
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1089
1294
|
function sortDependencyLevels(nodes, dependencies) {
|
|
1090
1295
|
const nodeSet = new Set(nodes);
|
|
1091
1296
|
const dependents = /* @__PURE__ */ new Map();
|
|
@@ -1127,21 +1332,21 @@ function sortDependencyLevels(nodes, dependencies) {
|
|
|
1127
1332
|
function extractCycle(leftover, dependencies) {
|
|
1128
1333
|
const leftoverSet = new Set(leftover);
|
|
1129
1334
|
const visiting = /* @__PURE__ */ new Set();
|
|
1130
|
-
const
|
|
1335
|
+
const path25 = [];
|
|
1131
1336
|
const dfs = (node) => {
|
|
1132
1337
|
if (visiting.has(node)) {
|
|
1133
|
-
const start =
|
|
1134
|
-
return [...
|
|
1338
|
+
const start = path25.indexOf(node);
|
|
1339
|
+
return [...path25.slice(start), node];
|
|
1135
1340
|
}
|
|
1136
1341
|
if (!leftoverSet.has(node)) return null;
|
|
1137
1342
|
visiting.add(node);
|
|
1138
|
-
|
|
1343
|
+
path25.push(node);
|
|
1139
1344
|
for (const dep of dependencies.get(node) ?? []) {
|
|
1140
1345
|
if (!leftoverSet.has(dep)) continue;
|
|
1141
1346
|
const cycle = dfs(dep);
|
|
1142
1347
|
if (cycle) return cycle;
|
|
1143
1348
|
}
|
|
1144
|
-
|
|
1349
|
+
path25.pop();
|
|
1145
1350
|
visiting.delete(node);
|
|
1146
1351
|
leftoverSet.delete(node);
|
|
1147
1352
|
return null;
|
|
@@ -1171,7 +1376,7 @@ function fieldsFromDirectOrFieldsets(type) {
|
|
|
1171
1376
|
function refineDeclaredReadSets(fields, ctx) {
|
|
1172
1377
|
const knownIds = new Set(fields.map((entry) => entry.field.id));
|
|
1173
1378
|
const dependencies = /* @__PURE__ */ new Map();
|
|
1174
|
-
for (const { field, path:
|
|
1379
|
+
for (const { field, path: path25 } of fields) {
|
|
1175
1380
|
const inputs = field.ai?.inputs;
|
|
1176
1381
|
if (!inputs || inputs.length === 0) continue;
|
|
1177
1382
|
const valid2 = [];
|
|
@@ -1180,7 +1385,7 @@ function refineDeclaredReadSets(fields, ctx) {
|
|
|
1180
1385
|
ctx.addIssue({
|
|
1181
1386
|
code: z.ZodIssueCode.custom,
|
|
1182
1387
|
message: UNKNOWN_INPUT_MESSAGE(field.id, inputId),
|
|
1183
|
-
path: [...
|
|
1388
|
+
path: [...path25, "ai", "inputs"]
|
|
1184
1389
|
});
|
|
1185
1390
|
continue;
|
|
1186
1391
|
}
|
|
@@ -1200,9 +1405,10 @@ function refineDeclaredReadSets(fields, ctx) {
|
|
|
1200
1405
|
});
|
|
1201
1406
|
}
|
|
1202
1407
|
}
|
|
1203
|
-
var AI_INSTRUCTIONS_MAX_CHARS, AIConfigSchema, FieldAIConfigSchema, AssetAIConfigSchema, BaseUIConfigSchema, TextUIOptionsSchema, UIConfigSchema, RuleConditionSchema, RuleConditionsSchema, VisibilityRuleSchema, RequirementRuleSchema, ValidationRuleSchema, ReadOnlyRuleSchema, FieldRuleSchema, LocalizationConfigSchema, FieldSchema, FieldsetSchema, BUILT_IN_ROLES, ROLE_ACTIONS, RoleActionSchema, BuiltInRoleSchema, roleIdPattern, RoleIdSchema, accessTagPattern, AccessTagSchema, AccessTagsArraySchema, ResourcePermissionSchema, FieldVisibilitySchema, RolePermissionsSchema, RoleSchema, RolesArraySchema, stageIdPattern, WorkflowEscalationSchema, WorkflowAutoAssignSchema, WorkflowStageSchema, WorkflowConfigSchema, ContentTypeWorkflowSchema, FILTER_OPERATORS, FilterOperatorSchema, TEXT_OPERATORS, LONG_TEXT_OPERATORS, NUMERIC_OPERATORS, BOOLEAN_OPERATORS, ENUM_OPERATORS, DATE_OPERATORS, REFERENCE_OPERATORS, TAGS_OPERATORS, FIELD_TYPE_OPERATORS,
|
|
1204
|
-
var
|
|
1205
|
-
"../../domain/schema/dist/chunk-
|
|
1408
|
+
var AI_INSTRUCTIONS_MAX_CHARS, AIConfigSchema, FieldAIConfigSchema, AssetAIConfigSchema, BaseUIConfigSchema, TextUIOptionsSchema, UIConfigSchema, RuleConditionSchema, RuleConditionsSchema, VisibilityRuleSchema, RequirementRuleSchema, ValidationRuleSchema, ReadOnlyRuleSchema, FieldRuleSchema, LocalizationConfigSchema, FieldSchema, FieldsetSchema, BUILT_IN_ROLES, ROLE_ACTIONS, RoleActionSchema, BuiltInRoleSchema, roleIdPattern, RoleIdSchema, accessTagPattern, AccessTagSchema, AccessTagsArraySchema, ResourcePermissionSchema, FieldVisibilitySchema, RolePermissionsSchema, RoleSchema, RolesArraySchema, stageIdPattern, WorkflowEscalationSchema, WorkflowAutoAssignSchema, WorkflowStageSchema, WorkflowConfigSchema, ContentTypeWorkflowSchema, FILTER_OPERATORS, FilterOperatorSchema, TEXT_OPERATORS, LONG_TEXT_OPERATORS, NUMERIC_OPERATORS, BOOLEAN_OPERATORS, ENUM_OPERATORS, DATE_OPERATORS, REFERENCE_OPERATORS, TAGS_OPERATORS, FIELD_TYPE_OPERATORS, TimeUnitSchema, RelativeDateValueSchema, COLUMN_RENDERERS, ColumnRendererSchema, ASSET_KINDS, FORBIDDEN_ASSET_TYPE_FIELD_TYPES, IMAGE_OUTPUT_FORMATS, IMAGE_FIT_MODES, UNKNOWN_INPUT_MESSAGE, INPUT_CYCLE_MESSAGE, FitSchema, OutputFormatSchema, ImageTransformSchema, ImageUploadConfigSchema, VideoUploadConfigSchema, FileUploadConfigSchema, ImageExifConfigSchema, VariantDefinitionSchema, ImageSourceConfigSchema, ImageKindConfigSchema, VideoPosterConfigSchema, VideoCaptionsConfigSchema, VideoDownloadConfigSchema, VideoWatermarkConfigSchema, VideoKindConfigSchema, FileScanConfigSchema, FileKindConfigSchema, AssetTypeSchema;
|
|
1409
|
+
var init_chunk_PCG6XHFD = __esm({
|
|
1410
|
+
"../../domain/schema/dist/chunk-PCG6XHFD.js"() {
|
|
1411
|
+
init_chunk_JH6U6ENN();
|
|
1206
1412
|
AI_INSTRUCTIONS_MAX_CHARS = 1e3;
|
|
1207
1413
|
AIConfigSchema = z.object({
|
|
1208
1414
|
/**
|
|
@@ -1669,7 +1875,6 @@ var init_chunk_NB2NTUXG = __esm({
|
|
|
1669
1875
|
list: []
|
|
1670
1876
|
// Lists are complex, use nested filters
|
|
1671
1877
|
};
|
|
1672
|
-
TIME_UNITS = ["minutes", "hours", "days", "weeks", "months", "years"];
|
|
1673
1878
|
TimeUnitSchema = z.enum(TIME_UNITS);
|
|
1674
1879
|
RelativeDateValueSchema = z.object({
|
|
1675
1880
|
amount: z.number().int().positive(),
|
|
@@ -2057,11 +2262,42 @@ var init_chunk_NB2NTUXG = __esm({
|
|
|
2057
2262
|
});
|
|
2058
2263
|
}
|
|
2059
2264
|
});
|
|
2060
|
-
var StringOperationSchema, StringOperationWithParamsSchema, WhereValueSchema, WhereConditionSchema, SortConditionSchema, EnhancedIncludeObjectSchema, IncludeDefinitionSchema, SelectMappingSchema, FilterDefinitionSchema, FullTextSearchSchema, ContentTypesSchema, SearchBlockSchema, SimilarBlockSchema, AggregationMetricSchema, QueryCachePolicySchema, FetchBlockSchema, AggregateBlockSchema, IncludeSubQueriesSchema, QueryDefinitionSchema, FilterValueSchema, FilterConditionSchema, LogicalOperatorSchema, FilterGroupSchema, ColumnConfigSchema, MetadataFieldConfigSchema, MetadataLineConfigSchema, TableSettingsSchema, ViewScopeSchema, ViewDSLSchema, ViewVisibilitySchema, ViewSourceSchema, SchemaViewDefinitionSchema, getComponentIdFromType, ComponentSchema, ContentTypeSchema, SettingsGroupSchema, SchemaDefinitionSchema;
|
|
2061
|
-
var
|
|
2062
|
-
"../../domain/schema/dist/chunk-
|
|
2265
|
+
var PARAMETER_EXPRESSION_SOURCE, ParameterExpressionStringSchema, QUERY_PARAMETER_TYPES, QueryParameterTypeSchema, QueryParameterScalarSchema, QueryParameterSchema, StringOperationSchema, StringOperationWithParamsSchema, ParameterizedLimitSchema, ParameterizedOffsetSchema, WhereValueSchema, WhereConditionSchema, SortConditionSchema, EnhancedIncludeObjectSchema, IncludeDefinitionSchema, SelectMappingSchema, FilterDefinitionSchema, FullTextSearchSchema, ContentTypesSchema, SearchBlockSchema, SimilarBlockSchema, AggregationMetricSchema, QueryCardinalitySchema, QueryCachePolicySchema, FetchBlockSchema, AggregateBlockSchema, IncludeSubQueriesSchema, QueryDefinitionSchema, VIEW_SLUG_PATTERN, VIEW_SLUG_MESSAGE, FilterValueSchema, FilterConditionSchema, LogicalOperatorSchema, FilterGroupSchema, ColumnConfigSchema, MetadataFieldConfigSchema, MetadataLineConfigSchema, TableSettingsSchema, ViewScopeSchema, ViewDSLSchema, ViewVisibilitySchema, ViewSourceSchema, SchemaViewDefinitionSchema, getComponentIdFromType, ComponentSchema, ContentTypeSchema, SettingsGroupSchema, SchemaDefinitionSchema;
|
|
2266
|
+
var init_chunk_2326XWZE = __esm({
|
|
2267
|
+
"../../domain/schema/dist/chunk-2326XWZE.js"() {
|
|
2063
2268
|
init_chunk_VGBOPF6G();
|
|
2064
|
-
|
|
2269
|
+
init_chunk_PCG6XHFD();
|
|
2270
|
+
PARAMETER_EXPRESSION_SOURCE = String.raw`\$\{([a-zA-Z][a-zA-Z0-9_]*)(\?([^}]*))?\}`;
|
|
2271
|
+
ParameterExpressionStringSchema = z.string().regex(
|
|
2272
|
+
new RegExp(`^${PARAMETER_EXPRESSION_SOURCE}$`),
|
|
2273
|
+
"Must be a parameter expression like ${limit?20}"
|
|
2274
|
+
);
|
|
2275
|
+
QUERY_PARAMETER_TYPES = [
|
|
2276
|
+
"string",
|
|
2277
|
+
"number",
|
|
2278
|
+
"integer",
|
|
2279
|
+
"boolean",
|
|
2280
|
+
"array",
|
|
2281
|
+
"object"
|
|
2282
|
+
];
|
|
2283
|
+
QueryParameterTypeSchema = z.enum(QUERY_PARAMETER_TYPES);
|
|
2284
|
+
QueryParameterScalarSchema = z.union([z.string(), z.number(), z.boolean()]);
|
|
2285
|
+
QueryParameterSchema = z.object({
|
|
2286
|
+
name: z.string().regex(
|
|
2287
|
+
/^[a-zA-Z][a-zA-Z0-9_]*$/,
|
|
2288
|
+
"Parameter name must start with a letter and contain only letters, numbers, and underscores"
|
|
2289
|
+
),
|
|
2290
|
+
type: QueryParameterTypeSchema.optional(),
|
|
2291
|
+
/** Absent means "required unless every `${…}` occurrence says otherwise". */
|
|
2292
|
+
required: z.boolean().optional(),
|
|
2293
|
+
default: z.union([QueryParameterScalarSchema, z.array(QueryParameterScalarSchema)]).optional(),
|
|
2294
|
+
minimum: z.number().optional(),
|
|
2295
|
+
maximum: z.number().optional(),
|
|
2296
|
+
minLength: z.number().int().min(0).optional(),
|
|
2297
|
+
maxLength: z.number().int().min(0).optional(),
|
|
2298
|
+
pattern: z.string().min(1).optional(),
|
|
2299
|
+
enum: z.array(QueryParameterScalarSchema).min(1).optional()
|
|
2300
|
+
});
|
|
2065
2301
|
StringOperationSchema = z.enum([
|
|
2066
2302
|
"first",
|
|
2067
2303
|
// Get first character
|
|
@@ -2085,6 +2321,14 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2085
2321
|
name: z.string().min(1),
|
|
2086
2322
|
defaultValue: z.union([z.string(), z.number(), z.boolean()]).optional()
|
|
2087
2323
|
});
|
|
2324
|
+
ParameterizedLimitSchema = z.union([
|
|
2325
|
+
z.number().int().positive(),
|
|
2326
|
+
ParameterExpressionStringSchema
|
|
2327
|
+
]);
|
|
2328
|
+
ParameterizedOffsetSchema = z.union([
|
|
2329
|
+
z.number().int().min(0),
|
|
2330
|
+
ParameterExpressionStringSchema
|
|
2331
|
+
]);
|
|
2088
2332
|
WhereValueSchema = z.union([
|
|
2089
2333
|
z.string(),
|
|
2090
2334
|
z.number(),
|
|
@@ -2232,8 +2476,8 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2232
2476
|
]).optional(),
|
|
2233
2477
|
// Sorting and pagination
|
|
2234
2478
|
sort: SortConditionSchema.optional(),
|
|
2235
|
-
limit:
|
|
2236
|
-
offset:
|
|
2479
|
+
limit: ParameterizedLimitSchema.optional(),
|
|
2480
|
+
offset: ParameterizedOffsetSchema.optional()
|
|
2237
2481
|
}).refine((data) => data.contentType || data.contentTypes, {
|
|
2238
2482
|
message: "Either contentType or contentTypes is required for search queries"
|
|
2239
2483
|
});
|
|
@@ -2250,7 +2494,7 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2250
2494
|
/** Fields to return */
|
|
2251
2495
|
fields: SelectMappingSchema.optional(),
|
|
2252
2496
|
/** Maximum results to return */
|
|
2253
|
-
limit:
|
|
2497
|
+
limit: ParameterizedLimitSchema.optional()
|
|
2254
2498
|
}).refine((data) => data.contentType || data.contentTypes, {
|
|
2255
2499
|
message: "Either contentType or contentTypes is required for similar queries"
|
|
2256
2500
|
});
|
|
@@ -2260,6 +2504,7 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2260
2504
|
z.string()
|
|
2261
2505
|
// field expression like "items.quantity.sum" or "id.count"
|
|
2262
2506
|
);
|
|
2507
|
+
QueryCardinalitySchema = z.enum(["one", "many"]);
|
|
2263
2508
|
QueryCachePolicySchema = z.union([
|
|
2264
2509
|
// Simple: "public 300s" or "private" or "public 300s swr 60s"
|
|
2265
2510
|
z.string(),
|
|
@@ -2277,8 +2522,8 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2277
2522
|
where: WhereConditionSchema.optional(),
|
|
2278
2523
|
include: IncludeDefinitionSchema.optional(),
|
|
2279
2524
|
sort: SortConditionSchema.optional(),
|
|
2280
|
-
limit:
|
|
2281
|
-
offset:
|
|
2525
|
+
limit: ParameterizedLimitSchema.optional(),
|
|
2526
|
+
offset: ParameterizedOffsetSchema.optional()
|
|
2282
2527
|
}).refine((data) => data.contentType || data.singleton, {
|
|
2283
2528
|
message: "Either contentType or singleton must be specified"
|
|
2284
2529
|
}).refine((data) => !(data.contentType && data.singleton), {
|
|
@@ -2323,7 +2568,7 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2323
2568
|
])
|
|
2324
2569
|
).optional(),
|
|
2325
2570
|
sort: SortConditionSchema.optional(),
|
|
2326
|
-
limit:
|
|
2571
|
+
limit: ParameterizedLimitSchema.optional()
|
|
2327
2572
|
});
|
|
2328
2573
|
IncludeSubQueriesSchema = z.record(
|
|
2329
2574
|
z.string(),
|
|
@@ -2331,7 +2576,7 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2331
2576
|
source: z.string(),
|
|
2332
2577
|
where: WhereConditionSchema.optional(),
|
|
2333
2578
|
sort: SortConditionSchema.optional(),
|
|
2334
|
-
limit:
|
|
2579
|
+
limit: ParameterizedLimitSchema.optional(),
|
|
2335
2580
|
select: SelectMappingSchema.optional()
|
|
2336
2581
|
})
|
|
2337
2582
|
);
|
|
@@ -2359,7 +2604,15 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2359
2604
|
filters: FilterDefinitionSchema.optional(),
|
|
2360
2605
|
fullText: FullTextSearchSchema.optional(),
|
|
2361
2606
|
select: SelectMappingSchema.optional(),
|
|
2362
|
-
cache: QueryCachePolicySchema.optional()
|
|
2607
|
+
cache: QueryCachePolicySchema.optional(),
|
|
2608
|
+
/**
|
|
2609
|
+
* What the query accepts. Additive and optional: a query that declares nothing still has the
|
|
2610
|
+
* parameters its own `${…}` expressions and endpoint segments declare — `declareQueryParameters`
|
|
2611
|
+
* is the one reader, and this block is authoritative where it speaks (type and constraints).
|
|
2612
|
+
*/
|
|
2613
|
+
parameters: z.array(QueryParameterSchema).optional(),
|
|
2614
|
+
/** `one` or `many`. Absent means `many`, unless the query fetches a singleton. */
|
|
2615
|
+
cardinality: QueryCardinalitySchema.optional()
|
|
2363
2616
|
}).refine((data) => data.fetch || data.aggregate || data.search || data.similar, {
|
|
2364
2617
|
message: "Query must contain at least one of: fetch, aggregate, search, or similar block"
|
|
2365
2618
|
}).refine(
|
|
@@ -2373,6 +2626,8 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2373
2626
|
message: "Aggregate block must have a source when not used with fetch"
|
|
2374
2627
|
}
|
|
2375
2628
|
);
|
|
2629
|
+
VIEW_SLUG_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
2630
|
+
VIEW_SLUG_MESSAGE = "Slug must be lowercase, start with a letter, and contain only letters, numbers, and hyphens";
|
|
2376
2631
|
FilterValueSchema = z.union([
|
|
2377
2632
|
// Simple values
|
|
2378
2633
|
z.string(),
|
|
@@ -2620,7 +2875,7 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2620
2875
|
* URL-friendly slug for the view (unique per dataset)
|
|
2621
2876
|
* Used in Studio URLs like /studio/views/:slug
|
|
2622
2877
|
*/
|
|
2623
|
-
slug: z.string().regex(
|
|
2878
|
+
slug: z.string().regex(VIEW_SLUG_PATTERN, VIEW_SLUG_MESSAGE),
|
|
2624
2879
|
/**
|
|
2625
2880
|
* Optional description
|
|
2626
2881
|
*/
|
|
@@ -2676,7 +2931,7 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
2676
2931
|
* URL-friendly slug for the view (optional, auto-generated from id if not provided)
|
|
2677
2932
|
* Used in Studio URLs like /studio/views/:slug
|
|
2678
2933
|
*/
|
|
2679
|
-
slug: z.string().regex(
|
|
2934
|
+
slug: z.string().regex(VIEW_SLUG_PATTERN, VIEW_SLUG_MESSAGE).optional(),
|
|
2680
2935
|
/**
|
|
2681
2936
|
* View name
|
|
2682
2937
|
*/
|
|
@@ -3138,18 +3393,19 @@ var init_chunk_OOMXKJZA = __esm({
|
|
|
3138
3393
|
// ../../domain/schema/dist/parsed-type.js
|
|
3139
3394
|
var init_parsed_type = __esm({
|
|
3140
3395
|
"../../domain/schema/dist/parsed-type.js"() {
|
|
3141
|
-
|
|
3396
|
+
init_chunk_2326XWZE();
|
|
3142
3397
|
init_chunk_VGBOPF6G();
|
|
3143
|
-
|
|
3398
|
+
init_chunk_PCG6XHFD();
|
|
3399
|
+
init_chunk_JH6U6ENN();
|
|
3144
3400
|
}
|
|
3145
3401
|
});
|
|
3146
3402
|
async function loadRelyIOConfig(baseDir) {
|
|
3147
3403
|
for (const configPath of CONFIG_FILE_PATHS) {
|
|
3148
|
-
const fullPath =
|
|
3404
|
+
const fullPath = path5.join(baseDir, configPath);
|
|
3149
3405
|
if (existsSync(fullPath)) {
|
|
3150
3406
|
try {
|
|
3151
|
-
const
|
|
3152
|
-
const jiti = createJiti(
|
|
3407
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
3408
|
+
const jiti = createJiti(__filename, {
|
|
3153
3409
|
interopDefault: true,
|
|
3154
3410
|
// Must stay OFF: jiti's module cache is process-global, so in a long-running process
|
|
3155
3411
|
// (`relyio dev`) a cached config would be re-served after edits. fsCache (content-hashed
|
|
@@ -3172,7 +3428,7 @@ async function loadRelyIOConfig(baseDir) {
|
|
|
3172
3428
|
}
|
|
3173
3429
|
async function findTypeScriptSchema(relyioDir) {
|
|
3174
3430
|
for (const tsPath of TS_SCHEMA_PATHS) {
|
|
3175
|
-
const fullPath =
|
|
3431
|
+
const fullPath = path5.join(relyioDir, tsPath);
|
|
3176
3432
|
if (existsSync(fullPath)) {
|
|
3177
3433
|
return {
|
|
3178
3434
|
found: true,
|
|
@@ -3192,7 +3448,7 @@ async function findYamlSchemas(relyioDir) {
|
|
|
3192
3448
|
if (yamlFiles.length > 0) {
|
|
3193
3449
|
return {
|
|
3194
3450
|
found: true,
|
|
3195
|
-
paths: yamlFiles.map((f) =>
|
|
3451
|
+
paths: yamlFiles.map((f) => path5.join(relyioDir, f)),
|
|
3196
3452
|
description: `YAML schema (${yamlFiles.length} file${yamlFiles.length === 1 ? "" : "s"})`
|
|
3197
3453
|
};
|
|
3198
3454
|
}
|
|
@@ -3201,7 +3457,7 @@ async function findYamlSchemas(relyioDir) {
|
|
|
3201
3457
|
return { found: false };
|
|
3202
3458
|
}
|
|
3203
3459
|
async function detectSchemaSource(baseDir = process.cwd()) {
|
|
3204
|
-
const relyioDir =
|
|
3460
|
+
const relyioDir = path5.join(baseDir, RELYIO_DIR);
|
|
3205
3461
|
if (!existsSync(relyioDir)) {
|
|
3206
3462
|
return {
|
|
3207
3463
|
sourceType: null,
|
|
@@ -3218,7 +3474,7 @@ async function detectSchemaSource(baseDir = process.cwd()) {
|
|
|
3218
3474
|
if (config?.schemaSource) {
|
|
3219
3475
|
if (config.schemaSource === "typescript") {
|
|
3220
3476
|
if (config.schemaPath) {
|
|
3221
|
-
const customPath =
|
|
3477
|
+
const customPath = path5.join(baseDir, config.schemaPath);
|
|
3222
3478
|
if (existsSync(customPath)) {
|
|
3223
3479
|
return {
|
|
3224
3480
|
sourceType: "typescript",
|
|
@@ -3359,8 +3615,8 @@ async function loadTypeScriptSchema(schemaPath, detection) {
|
|
|
3359
3615
|
});
|
|
3360
3616
|
}
|
|
3361
3617
|
try {
|
|
3362
|
-
const
|
|
3363
|
-
const jiti = createJiti(
|
|
3618
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
3619
|
+
const jiti = createJiti(__filename, {
|
|
3364
3620
|
// Enable ESM interop
|
|
3365
3621
|
interopDefault: true,
|
|
3366
3622
|
// Must stay OFF. jiti's module cache is process-global and integrates with Node's require
|
|
@@ -3637,7 +3893,7 @@ function isIgnoredWatchPath(filePath) {
|
|
|
3637
3893
|
return IGNORED_WATCH_DIR_RE.test(filePath);
|
|
3638
3894
|
}
|
|
3639
3895
|
async function getSchemaWatchPaths(baseDir = process.cwd()) {
|
|
3640
|
-
const relyioDir =
|
|
3896
|
+
const relyioDir = path5.join(baseDir, RELYIO_DIR);
|
|
3641
3897
|
return existsSync(relyioDir) ? [relyioDir] : [];
|
|
3642
3898
|
}
|
|
3643
3899
|
var RELYIO_DIR, TS_SCHEMA_PATHS, CONFIG_FILE_PATHS, SCHEMA_FILE_RE, DECLARATION_FILE_RE, IGNORED_WATCH_DIR_RE, SchemaNotFoundError;
|
|
@@ -3652,7 +3908,7 @@ var init_schema_loader = __esm({
|
|
|
3652
3908
|
IGNORED_WATCH_DIR_RE = /(^|[/\\])(node_modules|\.git|dist|\.next|\.turbo|coverage)([/\\]|$)/;
|
|
3653
3909
|
SchemaNotFoundError = class extends Error {
|
|
3654
3910
|
constructor(baseDir) {
|
|
3655
|
-
const relyioDir =
|
|
3911
|
+
const relyioDir = path5.join(baseDir, RELYIO_DIR);
|
|
3656
3912
|
const message = `
|
|
3657
3913
|
No schema found in ${relyioDir}
|
|
3658
3914
|
|
|
@@ -4061,9 +4317,204 @@ var init_deploy_service = __esm({
|
|
|
4061
4317
|
}
|
|
4062
4318
|
});
|
|
4063
4319
|
|
|
4064
|
-
//
|
|
4065
|
-
var
|
|
4066
|
-
|
|
4320
|
+
// ../sdk/dist/chunk-XQ4QHWZE.js
|
|
4321
|
+
var __defProp2, __name;
|
|
4322
|
+
var init_chunk_XQ4QHWZE = __esm({
|
|
4323
|
+
"../sdk/dist/chunk-XQ4QHWZE.js"() {
|
|
4324
|
+
__defProp2 = Object.defineProperty;
|
|
4325
|
+
__name = (target, value) => __defProp2(target, "name", { value, configurable: true });
|
|
4326
|
+
}
|
|
4327
|
+
});
|
|
4328
|
+
|
|
4329
|
+
// ../sdk/dist/chunk-BBUB7C2Z.js
|
|
4330
|
+
function readDeadline(raw, now) {
|
|
4331
|
+
if (raw === void 0 || raw === null || raw === "") return { state: "none" };
|
|
4332
|
+
if (typeof raw !== "string") return { state: "unreadable" };
|
|
4333
|
+
const deadline = new Date(raw).getTime();
|
|
4334
|
+
if (!Number.isFinite(deadline)) return { state: "unreadable" };
|
|
4335
|
+
return deadline <= now ? { state: "passed", expiredAt: raw } : { state: "live", expiresAt: raw };
|
|
4336
|
+
}
|
|
4337
|
+
function parseDevContextFile(raw, now) {
|
|
4338
|
+
let parsed;
|
|
4339
|
+
try {
|
|
4340
|
+
parsed = JSON.parse(raw);
|
|
4341
|
+
} catch {
|
|
4342
|
+
return { state: "unreadable", reason: "not-json" };
|
|
4343
|
+
}
|
|
4344
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
4345
|
+
return { state: "unreadable", reason: "not-json" };
|
|
4346
|
+
}
|
|
4347
|
+
const record = parsed;
|
|
4348
|
+
const { datasetId, previewApiKey, branchId, expiresAt } = record;
|
|
4349
|
+
if (typeof datasetId !== "string" || datasetId === "" || typeof previewApiKey !== "string" || previewApiKey === "" || typeof branchId !== "string" || branchId === "") {
|
|
4350
|
+
return { state: "unreadable", reason: "missing-fields" };
|
|
4351
|
+
}
|
|
4352
|
+
const deadline = readDeadline(expiresAt, now);
|
|
4353
|
+
if (deadline.state === "unreadable") return { state: "unreadable", reason: "bad-expiry" };
|
|
4354
|
+
const context = {
|
|
4355
|
+
datasetId,
|
|
4356
|
+
previewApiKey,
|
|
4357
|
+
branchId,
|
|
4358
|
+
expiresAt: deadline.state === "none" ? null : expiresAt
|
|
4359
|
+
};
|
|
4360
|
+
return deadline.state === "passed" ? { state: "expired", context, expiredAt: deadline.expiredAt } : { state: "active", context };
|
|
4361
|
+
}
|
|
4362
|
+
function buildDevEnv(context) {
|
|
4363
|
+
const env = {
|
|
4364
|
+
[DEV_ENV.dataset]: context.datasetId,
|
|
4365
|
+
[DEV_ENV.apiKey]: context.previewApiKey
|
|
4366
|
+
};
|
|
4367
|
+
if (context.expiresAt != null && context.expiresAt !== "") {
|
|
4368
|
+
env[DEV_ENV.expiresAt] = context.expiresAt;
|
|
4369
|
+
}
|
|
4370
|
+
return env;
|
|
4371
|
+
}
|
|
4372
|
+
function parseDevEnv(env, now) {
|
|
4373
|
+
const dataset = env?.[DEV_ENV.dataset];
|
|
4374
|
+
const apiKey = env?.[DEV_ENV.apiKey];
|
|
4375
|
+
if (dataset == null || dataset === "" || apiKey == null || apiKey === "") {
|
|
4376
|
+
return { state: "absent" };
|
|
4377
|
+
}
|
|
4378
|
+
const deadline = readDeadline(env?.[DEV_ENV.expiresAt], now);
|
|
4379
|
+
switch (deadline.state) {
|
|
4380
|
+
case "unreadable":
|
|
4381
|
+
return { state: "unreadable", reason: "bad-expiry" };
|
|
4382
|
+
case "passed":
|
|
4383
|
+
return { state: "expired", expiredAt: deadline.expiredAt };
|
|
4384
|
+
case "live":
|
|
4385
|
+
return { state: "active", credentials: { dataset, apiKey }, expiresAt: deadline.expiresAt };
|
|
4386
|
+
case "none":
|
|
4387
|
+
return { state: "active", credentials: { dataset, apiKey }, expiresAt: null };
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
var DEV_CONTEXT_DIR, DEV_CONTEXT_FILENAME, DEV_CONTEXT_FILE, DEV_ENV;
|
|
4391
|
+
var init_chunk_BBUB7C2Z = __esm({
|
|
4392
|
+
"../sdk/dist/chunk-BBUB7C2Z.js"() {
|
|
4393
|
+
init_chunk_XQ4QHWZE();
|
|
4394
|
+
DEV_CONTEXT_DIR = ".relyio";
|
|
4395
|
+
DEV_CONTEXT_FILENAME = "dev.json";
|
|
4396
|
+
DEV_CONTEXT_FILE = `${DEV_CONTEXT_DIR}/${DEV_CONTEXT_FILENAME}`;
|
|
4397
|
+
DEV_ENV = {
|
|
4398
|
+
dataset: "RELYIO_DEV_DATASET",
|
|
4399
|
+
apiKey: "RELYIO_DEV_API_KEY",
|
|
4400
|
+
expiresAt: "RELYIO_DEV_EXPIRES_AT"
|
|
4401
|
+
};
|
|
4402
|
+
__name(readDeadline, "readDeadline");
|
|
4403
|
+
__name(parseDevContextFile, "parseDevContextFile");
|
|
4404
|
+
__name(buildDevEnv, "buildDevEnv");
|
|
4405
|
+
__name(parseDevEnv, "parseDevEnv");
|
|
4406
|
+
}
|
|
4407
|
+
});
|
|
4408
|
+
|
|
4409
|
+
// ../sdk/dist/dev-handshake/index.js
|
|
4410
|
+
var init_dev_handshake = __esm({
|
|
4411
|
+
"../sdk/dist/dev-handshake/index.js"() {
|
|
4412
|
+
init_chunk_BBUB7C2Z();
|
|
4413
|
+
}
|
|
4414
|
+
});
|
|
4415
|
+
function registerPlugin(language, load3) {
|
|
4416
|
+
registeredPlugins.set(language, load3);
|
|
4417
|
+
}
|
|
4418
|
+
function registeredLanguages() {
|
|
4419
|
+
return [...registeredPlugins.keys()].sort((a, b) => a.localeCompare(b));
|
|
4420
|
+
}
|
|
4421
|
+
function asPlugin(module_, describe3) {
|
|
4422
|
+
const candidate = module_?.default ?? module_;
|
|
4423
|
+
const plugin3 = candidate;
|
|
4424
|
+
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
4425
|
+
throw new Error(`Invalid plugin: ${describe3}`);
|
|
4426
|
+
}
|
|
4427
|
+
return plugin3;
|
|
4428
|
+
}
|
|
4429
|
+
async function loadPlugin(language) {
|
|
4430
|
+
const registered = registeredPlugins.get(language);
|
|
4431
|
+
if (!registered) {
|
|
4432
|
+
const available = registeredLanguages();
|
|
4433
|
+
throw new Error(
|
|
4434
|
+
`No generator is registered for "${language}". ` + (available.length > 0 ? `Registered generators: ${available.join(", ")}.` : `No generator is registered at all \u2014 the host registers them at startup.`)
|
|
4435
|
+
);
|
|
4436
|
+
}
|
|
4437
|
+
return asPlugin(await registered(), `registered ${language}`);
|
|
4438
|
+
}
|
|
4439
|
+
async function writeFiles(files, outputDir) {
|
|
4440
|
+
await fs4.mkdir(outputDir, { recursive: true });
|
|
4441
|
+
await Promise.all(
|
|
4442
|
+
files.map(async (file) => {
|
|
4443
|
+
const fullPath = path5.join(outputDir, file.path);
|
|
4444
|
+
const dir = path5.dirname(fullPath);
|
|
4445
|
+
await fs4.mkdir(dir, { recursive: true });
|
|
4446
|
+
await fs4.writeFile(fullPath, file.content, "utf8");
|
|
4447
|
+
})
|
|
4448
|
+
);
|
|
4449
|
+
}
|
|
4450
|
+
function words(identifier) {
|
|
4451
|
+
return identifier.split(/[-_\s]+/).filter((word) => word.length > 0);
|
|
4452
|
+
}
|
|
4453
|
+
var BUILT_IN_LANGUAGES, registeredPlugins, TemplateEngine, naming;
|
|
4454
|
+
var init_dist2 = __esm({
|
|
4455
|
+
"../codegen-core/dist/index.js"() {
|
|
4456
|
+
BUILT_IN_LANGUAGES = ["typescript", "python"];
|
|
4457
|
+
registeredPlugins = /* @__PURE__ */ new Map();
|
|
4458
|
+
TemplateEngine = class {
|
|
4459
|
+
handlebars;
|
|
4460
|
+
constructor() {
|
|
4461
|
+
this.handlebars = Handlebars.create();
|
|
4462
|
+
this.registerHelpers();
|
|
4463
|
+
}
|
|
4464
|
+
registerHelpers() {
|
|
4465
|
+
this.handlebars.registerHelper("pascalCase", (str) => {
|
|
4466
|
+
if (!str) return "";
|
|
4467
|
+
return str.replaceAll(/(^|_)(\w)/g, (_, __, char) => char.toUpperCase());
|
|
4468
|
+
});
|
|
4469
|
+
this.handlebars.registerHelper("camelCase", (str) => {
|
|
4470
|
+
if (!str) return "";
|
|
4471
|
+
const pascal = str.replaceAll(/(^|_)(\w)/g, (_, __, char) => char.toUpperCase());
|
|
4472
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
4473
|
+
});
|
|
4474
|
+
this.handlebars.registerHelper("snakeCase", (str) => {
|
|
4475
|
+
if (!str) return "";
|
|
4476
|
+
return str.replaceAll(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
4477
|
+
});
|
|
4478
|
+
this.handlebars.registerHelper("kebabCase", (str) => {
|
|
4479
|
+
if (!str) return "";
|
|
4480
|
+
return str.replaceAll(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
4481
|
+
});
|
|
4482
|
+
this.handlebars.registerHelper("plural", (str) => {
|
|
4483
|
+
if (!str) return "";
|
|
4484
|
+
if (str.endsWith("y")) {
|
|
4485
|
+
return str.slice(0, -1) + "ies";
|
|
4486
|
+
}
|
|
4487
|
+
if (str.endsWith("s") || str.endsWith("sh") || str.endsWith("ch")) {
|
|
4488
|
+
return str + "es";
|
|
4489
|
+
}
|
|
4490
|
+
return str + "s";
|
|
4491
|
+
});
|
|
4492
|
+
}
|
|
4493
|
+
compile(template) {
|
|
4494
|
+
const compiledTemplate = this.handlebars.compile(template);
|
|
4495
|
+
return (context) => compiledTemplate(context);
|
|
4496
|
+
}
|
|
4497
|
+
render(template, context) {
|
|
4498
|
+
const compiledTemplate = this.compile(template);
|
|
4499
|
+
return compiledTemplate(context);
|
|
4500
|
+
}
|
|
4501
|
+
};
|
|
4502
|
+
new TemplateEngine();
|
|
4503
|
+
naming = {
|
|
4504
|
+
/** `blogPost` → `BlogPost`. The name of a generated type, class or struct. */
|
|
4505
|
+
pascal(identifier) {
|
|
4506
|
+
return words(identifier).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
4507
|
+
},
|
|
4508
|
+
/** `blog_post` → `blogPost`. The name of a generated value or field. */
|
|
4509
|
+
camel(identifier) {
|
|
4510
|
+
const pascal = naming.pascal(identifier);
|
|
4511
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
4512
|
+
},
|
|
4513
|
+
/** `blogPost` → `blog_post`. Python module paths and field names. */
|
|
4514
|
+
snake(identifier) {
|
|
4515
|
+
return identifier.replaceAll(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").replaceAll(/[-\s]+/g, "_");
|
|
4516
|
+
}
|
|
4517
|
+
};
|
|
4067
4518
|
}
|
|
4068
4519
|
});
|
|
4069
4520
|
function normalizeReferenceTargets(to) {
|
|
@@ -4071,8 +4522,8 @@ function normalizeReferenceTargets(to) {
|
|
|
4071
4522
|
return Array.isArray(to) ? [...to] : [to];
|
|
4072
4523
|
}
|
|
4073
4524
|
var BaseFieldConfigSchema, ReferenceStrengthSchema, OnTargetDeleteSchema, ReferenceTargetSchema;
|
|
4074
|
-
var
|
|
4075
|
-
"../../domain/schema/dist/chunk-
|
|
4525
|
+
var init_chunk_RIJEP5Z6 = __esm({
|
|
4526
|
+
"../../domain/schema/dist/chunk-RIJEP5Z6.js"() {
|
|
4076
4527
|
BaseFieldConfigSchema = z.object({
|
|
4077
4528
|
required: z.boolean().optional(),
|
|
4078
4529
|
unique: z.boolean().optional(),
|
|
@@ -4126,19 +4577,11 @@ var init_chunk_YL47KAP2 = __esm({
|
|
|
4126
4577
|
});
|
|
4127
4578
|
}
|
|
4128
4579
|
});
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
init_chunk_YL47KAP2();
|
|
4135
|
-
init_chunk_NB2NTUXG();
|
|
4136
|
-
}
|
|
4137
|
-
});
|
|
4138
|
-
var init_chunk_KWUTF26B = __esm({
|
|
4139
|
-
"../../domain/schema/dist/chunk-KWUTF26B.js"() {
|
|
4140
|
-
init_chunk_YL47KAP2();
|
|
4141
|
-
init_chunk_NB2NTUXG();
|
|
4580
|
+
var init_chunk_3UOSTM65 = __esm({
|
|
4581
|
+
"../../domain/schema/dist/chunk-3UOSTM65.js"() {
|
|
4582
|
+
init_chunk_2326XWZE();
|
|
4583
|
+
init_chunk_RIJEP5Z6();
|
|
4584
|
+
init_chunk_PCG6XHFD();
|
|
4142
4585
|
BaseFieldConfigSchema.extend({
|
|
4143
4586
|
maxLength: z.number().min(1).optional(),
|
|
4144
4587
|
pattern: z.string().optional(),
|
|
@@ -4369,15 +4812,67 @@ var init_chunk_KWUTF26B = __esm({
|
|
|
4369
4812
|
z.record(z.any());
|
|
4370
4813
|
}
|
|
4371
4814
|
});
|
|
4372
|
-
var
|
|
4373
|
-
"../../domain/schema/dist/
|
|
4374
|
-
|
|
4815
|
+
var init_chunk_XTMEVLMJ = __esm({
|
|
4816
|
+
"../../domain/schema/dist/chunk-XTMEVLMJ.js"() {
|
|
4817
|
+
}
|
|
4818
|
+
});
|
|
4819
|
+
|
|
4820
|
+
// ../../domain/schema/dist/chunk-73FJJM22.js
|
|
4821
|
+
var TABLE_SYSTEM_FIELD_KINDS;
|
|
4822
|
+
var init_chunk_73FJJM22 = __esm({
|
|
4823
|
+
"../../domain/schema/dist/chunk-73FJJM22.js"() {
|
|
4824
|
+
init_chunk_RIJEP5Z6();
|
|
4825
|
+
init_chunk_PCG6XHFD();
|
|
4826
|
+
TABLE_SYSTEM_FIELD_KINDS = {
|
|
4827
|
+
id: "text",
|
|
4828
|
+
contentType: "choice",
|
|
4829
|
+
status: "text",
|
|
4830
|
+
createdAt: "date",
|
|
4831
|
+
updatedAt: "date",
|
|
4832
|
+
publishedAt: "date",
|
|
4833
|
+
createdBy: "reference",
|
|
4834
|
+
updatedBy: "reference"
|
|
4835
|
+
};
|
|
4836
|
+
({
|
|
4837
|
+
...TABLE_SYSTEM_FIELD_KINDS,
|
|
4838
|
+
"file.status": "text",
|
|
4839
|
+
"file.backend": "text",
|
|
4840
|
+
"file.mimeType": "text",
|
|
4841
|
+
"file.fileName": "text",
|
|
4842
|
+
"file.size": "number",
|
|
4843
|
+
"file.extracted.width": "number",
|
|
4844
|
+
"file.extracted.height": "number",
|
|
4845
|
+
"file.extracted.duration": "number"
|
|
4846
|
+
});
|
|
4847
|
+
}
|
|
4848
|
+
});
|
|
4849
|
+
|
|
4850
|
+
// ../../domain/schema/dist/chunk-QSWR2YJN.js
|
|
4851
|
+
var init_chunk_QSWR2YJN = __esm({
|
|
4852
|
+
"../../domain/schema/dist/chunk-QSWR2YJN.js"() {
|
|
4853
|
+
}
|
|
4854
|
+
});
|
|
4855
|
+
|
|
4856
|
+
// ../../domain/schema/dist/chunk-2ABFISBQ.js
|
|
4857
|
+
var init_chunk_2ABFISBQ = __esm({
|
|
4858
|
+
"../../domain/schema/dist/chunk-2ABFISBQ.js"() {
|
|
4859
|
+
init_chunk_RIJEP5Z6();
|
|
4375
4860
|
init_chunk_QSWR2YJN();
|
|
4376
|
-
|
|
4377
|
-
|
|
4861
|
+
init_chunk_PCG6XHFD();
|
|
4862
|
+
}
|
|
4863
|
+
});
|
|
4864
|
+
var init_dist3 = __esm({
|
|
4865
|
+
"../../domain/schema/dist/index.js"() {
|
|
4866
|
+
init_chunk_3UOSTM65();
|
|
4867
|
+
init_chunk_2326XWZE();
|
|
4868
|
+
init_chunk_XTMEVLMJ();
|
|
4378
4869
|
init_chunk_VGBOPF6G();
|
|
4379
|
-
|
|
4380
|
-
|
|
4870
|
+
init_chunk_73FJJM22();
|
|
4871
|
+
init_chunk_2ABFISBQ();
|
|
4872
|
+
init_chunk_RIJEP5Z6();
|
|
4873
|
+
init_chunk_QSWR2YJN();
|
|
4874
|
+
init_chunk_PCG6XHFD();
|
|
4875
|
+
init_chunk_JH6U6ENN();
|
|
4381
4876
|
new Set(FORBIDDEN_ASSET_TYPE_FIELD_TYPES);
|
|
4382
4877
|
}
|
|
4383
4878
|
});
|
|
@@ -4422,24 +4917,17 @@ function validateSchema(schema) {
|
|
|
4422
4917
|
formatted: SchemaValidator.formatErrors(errors)
|
|
4423
4918
|
};
|
|
4424
4919
|
}
|
|
4425
|
-
function toPascalCase(str) {
|
|
4426
|
-
const spaced = str.replaceAll(/([a-z])([A-Z])/g, "$1 $2");
|
|
4427
|
-
return spaced.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
4428
|
-
}
|
|
4429
|
-
function toCamelCase(str) {
|
|
4430
|
-
const pascal = toPascalCase(str);
|
|
4431
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
4432
|
-
}
|
|
4433
4920
|
async function generateTypeScriptFromSchema(rawSchema, options) {
|
|
4434
4921
|
const parsedSchema = parseSchema(rawSchema);
|
|
4435
4922
|
const generator = new TypeScriptGenerator(parsedSchema, options);
|
|
4436
4923
|
return generator.generate();
|
|
4437
4924
|
}
|
|
4438
4925
|
var ASSET_KINDS2, SchemaParser, SchemaValidator, TypeScriptGenerator, plugin, index_default;
|
|
4439
|
-
var
|
|
4926
|
+
var init_dist4 = __esm({
|
|
4440
4927
|
"../codegen-typescript/dist/index.js"() {
|
|
4441
|
-
|
|
4442
|
-
|
|
4928
|
+
init_dist3();
|
|
4929
|
+
init_dist2();
|
|
4930
|
+
init_dist3();
|
|
4443
4931
|
ASSET_KINDS2 = ["image", "video", "file"];
|
|
4444
4932
|
SchemaParser = class {
|
|
4445
4933
|
/**
|
|
@@ -4906,16 +5394,16 @@ var init_dist2 = __esm({
|
|
|
4906
5394
|
* Validate a content type
|
|
4907
5395
|
*/
|
|
4908
5396
|
validateContentType(id, contentType) {
|
|
4909
|
-
const
|
|
4910
|
-
this.validateFields(contentType.fields,
|
|
5397
|
+
const path25 = `contentTypes.${id}`;
|
|
5398
|
+
this.validateFields(contentType.fields, path25);
|
|
4911
5399
|
if (contentType.fields.length === 0) {
|
|
4912
|
-
this.addWarning(
|
|
5400
|
+
this.addWarning(path25, "Content type has no fields defined");
|
|
4913
5401
|
}
|
|
4914
5402
|
const reservedFields = /* @__PURE__ */ new Set(["id", "createdAt", "updatedAt", "_id"]);
|
|
4915
5403
|
for (const field of contentType.fields) {
|
|
4916
5404
|
if (reservedFields.has(field.id)) {
|
|
4917
5405
|
this.addError(
|
|
4918
|
-
`${
|
|
5406
|
+
`${path25}.fields.${field.id}`,
|
|
4919
5407
|
`Field name '${field.id}' is reserved by BaseContent`,
|
|
4920
5408
|
`Use a different field name`
|
|
4921
5409
|
);
|
|
@@ -4942,20 +5430,20 @@ var init_dist2 = __esm({
|
|
|
4942
5430
|
/**
|
|
4943
5431
|
* Validate field type
|
|
4944
5432
|
*/
|
|
4945
|
-
validateFieldType(field,
|
|
5433
|
+
validateFieldType(field, path25) {
|
|
4946
5434
|
if (field.type === "enum" && (!field.enumValues || field.enumValues.length === 0)) {
|
|
4947
|
-
this.addError(
|
|
5435
|
+
this.addError(path25, "Enum field has no values defined");
|
|
4948
5436
|
}
|
|
4949
5437
|
if (field.type === "reference" && !field.referenceType) {
|
|
4950
5438
|
this.addError(
|
|
4951
|
-
|
|
5439
|
+
path25,
|
|
4952
5440
|
"Reference field missing referenceType",
|
|
4953
5441
|
"Ensure the reference target (to) is specified in the schema"
|
|
4954
5442
|
);
|
|
4955
5443
|
}
|
|
4956
5444
|
if (field.type === "component" && !field.componentType) {
|
|
4957
5445
|
this.addError(
|
|
4958
|
-
|
|
5446
|
+
path25,
|
|
4959
5447
|
"Component field missing componentType",
|
|
4960
5448
|
"Ensure component type is specified as component(componentName)"
|
|
4961
5449
|
);
|
|
@@ -4965,11 +5453,11 @@ var init_dist2 = __esm({
|
|
|
4965
5453
|
* Check for circular references
|
|
4966
5454
|
*/
|
|
4967
5455
|
checkCircularReferences(schema) {
|
|
4968
|
-
const checkType = (typeName, visited,
|
|
5456
|
+
const checkType = (typeName, visited, path25) => {
|
|
4969
5457
|
if (visited.has(typeName)) {
|
|
4970
5458
|
this.addError(
|
|
4971
|
-
|
|
4972
|
-
`Circular reference detected: ${
|
|
5459
|
+
path25.join(" -> "),
|
|
5460
|
+
`Circular reference detected: ${path25.join(" -> ")} -> ${typeName}`
|
|
4973
5461
|
);
|
|
4974
5462
|
return;
|
|
4975
5463
|
}
|
|
@@ -4978,7 +5466,7 @@ var init_dist2 = __esm({
|
|
|
4978
5466
|
visited.add(typeName);
|
|
4979
5467
|
for (const field of contentType.fields) {
|
|
4980
5468
|
if (field.isReference && field.referenceType) {
|
|
4981
|
-
checkType(field.referenceType, new Set(visited), [...
|
|
5469
|
+
checkType(field.referenceType, new Set(visited), [...path25, field.referenceType]);
|
|
4982
5470
|
}
|
|
4983
5471
|
}
|
|
4984
5472
|
};
|
|
@@ -4989,10 +5477,10 @@ var init_dist2 = __esm({
|
|
|
4989
5477
|
/**
|
|
4990
5478
|
* Add an error
|
|
4991
5479
|
*/
|
|
4992
|
-
addError(
|
|
5480
|
+
addError(path25, message, suggestion) {
|
|
4993
5481
|
this.errors.push({
|
|
4994
5482
|
type: "error",
|
|
4995
|
-
path:
|
|
5483
|
+
path: path25,
|
|
4996
5484
|
message,
|
|
4997
5485
|
suggestion
|
|
4998
5486
|
});
|
|
@@ -5000,10 +5488,10 @@ var init_dist2 = __esm({
|
|
|
5000
5488
|
/**
|
|
5001
5489
|
* Add a warning
|
|
5002
5490
|
*/
|
|
5003
|
-
addWarning(
|
|
5491
|
+
addWarning(path25, message, suggestion) {
|
|
5004
5492
|
this.warnings.push({
|
|
5005
5493
|
type: "warning",
|
|
5006
|
-
path:
|
|
5494
|
+
path: path25,
|
|
5007
5495
|
message,
|
|
5008
5496
|
suggestion
|
|
5009
5497
|
});
|
|
@@ -5148,6 +5636,9 @@ ${prefix}: ${error2.path}`, ` ${error2.message}`);
|
|
|
5148
5636
|
import type {
|
|
5149
5637
|
${typeImports.join(",\n ")},
|
|
5150
5638
|
} from '@relyio/sdk/schema'
|
|
5639
|
+
|
|
5640
|
+
// Puts '@relyio/sdk' in the program for the \`Register\` augmentation at the end of this file
|
|
5641
|
+
import type {} from '@relyio/sdk'
|
|
5151
5642
|
`);
|
|
5152
5643
|
}
|
|
5153
5644
|
/**
|
|
@@ -5178,7 +5669,7 @@ import type {
|
|
|
5178
5669
|
}
|
|
5179
5670
|
lines.push(" */");
|
|
5180
5671
|
}
|
|
5181
|
-
const varName =
|
|
5672
|
+
const varName = naming.camel(component.id) + "Component";
|
|
5182
5673
|
lines.push(`export const ${varName} = defineComponent('${component.id}', {`);
|
|
5183
5674
|
if (component.displayName) {
|
|
5184
5675
|
lines.push(` displayName: '${this.escapeString(component.displayName)}',`);
|
|
@@ -5221,7 +5712,7 @@ import type {
|
|
|
5221
5712
|
}
|
|
5222
5713
|
lines.push(" */");
|
|
5223
5714
|
}
|
|
5224
|
-
const varName =
|
|
5715
|
+
const varName = naming.camel(contentType.id);
|
|
5225
5716
|
lines.push(`export const ${varName} = defineContentType('${contentType.id}', {`);
|
|
5226
5717
|
if (contentType.displayName) {
|
|
5227
5718
|
lines.push(` displayName: '${this.escapeString(contentType.displayName)}',`);
|
|
@@ -5278,7 +5769,7 @@ import type {
|
|
|
5278
5769
|
}
|
|
5279
5770
|
lines.push(" */");
|
|
5280
5771
|
}
|
|
5281
|
-
const varName =
|
|
5772
|
+
const varName = naming.camel(assetType.id);
|
|
5282
5773
|
lines.push(`export const ${varName} = defineAssetType('${assetType.id}', {`);
|
|
5283
5774
|
if (assetType.displayName) {
|
|
5284
5775
|
lines.push(` displayName: '${this.escapeString(assetType.displayName)}',`);
|
|
@@ -5553,7 +6044,7 @@ import type {
|
|
|
5553
6044
|
}
|
|
5554
6045
|
lines.push(" */");
|
|
5555
6046
|
}
|
|
5556
|
-
const varName =
|
|
6047
|
+
const varName = naming.camel(singleton5.id);
|
|
5557
6048
|
lines.push(`export const ${varName} = defineSingleton('${singleton5.id}', {`);
|
|
5558
6049
|
if (singleton5.displayName) {
|
|
5559
6050
|
lines.push(` displayName: '${this.escapeString(singleton5.displayName)}',`);
|
|
@@ -5605,7 +6096,7 @@ import type {
|
|
|
5605
6096
|
}
|
|
5606
6097
|
lines.push(" */");
|
|
5607
6098
|
}
|
|
5608
|
-
const varName =
|
|
6099
|
+
const varName = naming.camel(group.id) + "Settings";
|
|
5609
6100
|
lines.push(`export const ${varName} = defineSettingsGroup('${group.id}', {`);
|
|
5610
6101
|
if (group.displayName) {
|
|
5611
6102
|
lines.push(` displayName: '${this.escapeString(group.displayName)}',`);
|
|
@@ -5638,7 +6129,7 @@ import type {
|
|
|
5638
6129
|
*/
|
|
5639
6130
|
generateQuery(query) {
|
|
5640
6131
|
const lines = [];
|
|
5641
|
-
const varName =
|
|
6132
|
+
const varName = naming.camel(query.id) + "Query";
|
|
5642
6133
|
lines.push(`export const ${varName} = defineQuery('${query.id}', {`);
|
|
5643
6134
|
if (query.endpoint) {
|
|
5644
6135
|
lines.push(` endpoint: '${query.endpoint}',`);
|
|
@@ -5697,7 +6188,7 @@ import type {
|
|
|
5697
6188
|
if (this.schema.contentTypes.size > 0) {
|
|
5698
6189
|
lines.push(" contentTypes: {");
|
|
5699
6190
|
for (const [id] of this.schema.contentTypes) {
|
|
5700
|
-
const varName =
|
|
6191
|
+
const varName = naming.camel(id);
|
|
5701
6192
|
lines.push(` ${id}: ${varName},`);
|
|
5702
6193
|
}
|
|
5703
6194
|
lines.push(" },");
|
|
@@ -5705,7 +6196,7 @@ import type {
|
|
|
5705
6196
|
if (this.schema.components.size > 0) {
|
|
5706
6197
|
lines.push(" components: {");
|
|
5707
6198
|
for (const [id] of this.schema.components) {
|
|
5708
|
-
const varName =
|
|
6199
|
+
const varName = naming.camel(id) + "Component";
|
|
5709
6200
|
lines.push(` ${id}: ${varName},`);
|
|
5710
6201
|
}
|
|
5711
6202
|
lines.push(" },");
|
|
@@ -5713,7 +6204,7 @@ import type {
|
|
|
5713
6204
|
if (this.schema.assetTypes.size > 0) {
|
|
5714
6205
|
lines.push(" assetTypes: {");
|
|
5715
6206
|
for (const [id] of this.schema.assetTypes) {
|
|
5716
|
-
const varName =
|
|
6207
|
+
const varName = naming.camel(id);
|
|
5717
6208
|
lines.push(` ${id}: ${varName},`);
|
|
5718
6209
|
}
|
|
5719
6210
|
lines.push(" },");
|
|
@@ -5721,7 +6212,7 @@ import type {
|
|
|
5721
6212
|
if (this.schema.singletons.size > 0) {
|
|
5722
6213
|
lines.push(" singletonContentTypes: {");
|
|
5723
6214
|
for (const [id] of this.schema.singletons) {
|
|
5724
|
-
const varName =
|
|
6215
|
+
const varName = naming.camel(id);
|
|
5725
6216
|
lines.push(` ${id}: ${varName},`);
|
|
5726
6217
|
}
|
|
5727
6218
|
lines.push(" },");
|
|
@@ -5729,7 +6220,7 @@ import type {
|
|
|
5729
6220
|
if (this.schema.queries.size > 0) {
|
|
5730
6221
|
lines.push(" queries: {");
|
|
5731
6222
|
for (const [id] of this.schema.queries) {
|
|
5732
|
-
const varName =
|
|
6223
|
+
const varName = naming.camel(id) + "Query";
|
|
5733
6224
|
lines.push(` ${id}: ${varName},`);
|
|
5734
6225
|
}
|
|
5735
6226
|
lines.push(" },");
|
|
@@ -5737,7 +6228,7 @@ import type {
|
|
|
5737
6228
|
if (this.schema.settingsGroups.size > 0) {
|
|
5738
6229
|
lines.push(" settingsGroups: {");
|
|
5739
6230
|
for (const [id] of this.schema.settingsGroups) {
|
|
5740
|
-
const varName =
|
|
6231
|
+
const varName = naming.camel(id) + "Settings";
|
|
5741
6232
|
lines.push(` ${id}: ${varName},`);
|
|
5742
6233
|
}
|
|
5743
6234
|
lines.push(" },");
|
|
@@ -5755,13 +6246,13 @@ import type {
|
|
|
5755
6246
|
`);
|
|
5756
6247
|
const lines = [];
|
|
5757
6248
|
for (const [id] of this.schema.contentTypes) {
|
|
5758
|
-
const varName =
|
|
5759
|
-
const typeName =
|
|
6249
|
+
const varName = naming.camel(id);
|
|
6250
|
+
const typeName = naming.pascal(id);
|
|
5760
6251
|
lines.push(`export type ${typeName} = InferContentType<typeof ${varName}>`);
|
|
5761
6252
|
}
|
|
5762
6253
|
for (const [, assetType] of this.schema.assetTypes) {
|
|
5763
|
-
const varName =
|
|
5764
|
-
const typeName =
|
|
6254
|
+
const varName = naming.camel(assetType.id);
|
|
6255
|
+
const typeName = naming.pascal(assetType.id);
|
|
5765
6256
|
lines.push(`export type ${typeName} = InferAssetType<typeof ${varName}>`);
|
|
5766
6257
|
if (assetType.variantIds && assetType.variantIds.length > 0) {
|
|
5767
6258
|
const union = assetType.variantIds.map((vid) => `'${this.escapeString(vid)}'`).join(" | ");
|
|
@@ -5769,8 +6260,8 @@ import type {
|
|
|
5769
6260
|
}
|
|
5770
6261
|
}
|
|
5771
6262
|
for (const [id] of this.schema.singletons) {
|
|
5772
|
-
const varName =
|
|
5773
|
-
const typeName =
|
|
6263
|
+
const varName = naming.camel(id);
|
|
6264
|
+
const typeName = naming.pascal(id);
|
|
5774
6265
|
lines.push(`export type ${typeName} = InferSingleton<typeof ${varName}>`);
|
|
5775
6266
|
}
|
|
5776
6267
|
this.output.push(
|
|
@@ -5780,6 +6271,27 @@ import type {
|
|
|
5780
6271
|
export type SchemaTypes = typeof schema
|
|
5781
6272
|
`
|
|
5782
6273
|
);
|
|
6274
|
+
this.addRegisterAugmentation();
|
|
6275
|
+
}
|
|
6276
|
+
/**
|
|
6277
|
+
* Register this schema with the SDK, so `createClient({ apiKey })` is typed with no generic and no
|
|
6278
|
+
* `schema:` (`INV-SS-TYPES-INFERRED`, `sdk-surfaces-spec.md` decision 7).
|
|
6279
|
+
*
|
|
6280
|
+
* It is emitted into this same file rather than a second one: the augmentation takes effect
|
|
6281
|
+
* wherever `schema.ts` is part of the program. It needs `'@relyio/sdk'` itself in the program too,
|
|
6282
|
+
* which is what the empty `import type {} from '@relyio/sdk'` in `addImports` is for — measured,
|
|
6283
|
+
* a program whose only SDK import is `@relyio/sdk/client` fails this block with TS2664 ("module
|
|
6284
|
+
* '@relyio/sdk' cannot be found") even though the name resolves. Two generated files augmenting
|
|
6285
|
+
* `Register` in one program conflict on `schema` (TS2717); one program registers one schema.
|
|
6286
|
+
*/
|
|
6287
|
+
addRegisterAugmentation() {
|
|
6288
|
+
this.output.push(`// Registers this schema with the SDK: \`createClient({ apiKey })\` is typed by it
|
|
6289
|
+
declare module '@relyio/sdk' {
|
|
6290
|
+
interface Register {
|
|
6291
|
+
schema: typeof schema
|
|
6292
|
+
}
|
|
6293
|
+
}
|
|
6294
|
+
`);
|
|
5783
6295
|
}
|
|
5784
6296
|
/**
|
|
5785
6297
|
* Escape string for use in generated code
|
|
@@ -5913,18 +6425,12 @@ function mapFieldTypeToPython(fieldType, config) {
|
|
|
5913
6425
|
default: {
|
|
5914
6426
|
const componentMatch = fieldType.match(/^component\(([^)]+)\)$/);
|
|
5915
6427
|
if (componentMatch) {
|
|
5916
|
-
return
|
|
6428
|
+
return naming.pascal(componentMatch[1]);
|
|
5917
6429
|
}
|
|
5918
6430
|
return "Any";
|
|
5919
6431
|
}
|
|
5920
6432
|
}
|
|
5921
6433
|
}
|
|
5922
|
-
function toPascalCase2(str) {
|
|
5923
|
-
return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
5924
|
-
}
|
|
5925
|
-
function toSnakeCase(str) {
|
|
5926
|
-
return str.replaceAll(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").replaceAll(/[-\s]+/g, "_");
|
|
5927
|
-
}
|
|
5928
6434
|
function isRecord2(value) {
|
|
5929
6435
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5930
6436
|
}
|
|
@@ -5963,7 +6469,7 @@ async function generatePython(ir, options) {
|
|
|
5963
6469
|
for (const [id, contentType] of recordEntries(ir.contentTypes)) {
|
|
5964
6470
|
const content = generateContentType(id, asSchemaType(contentType), options);
|
|
5965
6471
|
files.push({
|
|
5966
|
-
path: `content_types/${
|
|
6472
|
+
path: `content_types/${naming.snake(id)}.py`,
|
|
5967
6473
|
content
|
|
5968
6474
|
});
|
|
5969
6475
|
}
|
|
@@ -5977,7 +6483,7 @@ async function generatePython(ir, options) {
|
|
|
5977
6483
|
for (const [id, component] of recordEntries(ir.components)) {
|
|
5978
6484
|
const content = generateComponent(id, asSchemaType(component), options);
|
|
5979
6485
|
files.push({
|
|
5980
|
-
path: `components/${
|
|
6486
|
+
path: `components/${naming.snake(id)}.py`,
|
|
5981
6487
|
content
|
|
5982
6488
|
});
|
|
5983
6489
|
}
|
|
@@ -5991,7 +6497,7 @@ async function generatePython(ir, options) {
|
|
|
5991
6497
|
for (const [id, singleton5] of recordEntries(ir.singletons)) {
|
|
5992
6498
|
const content = generateSingleton(id, asSchemaType(singleton5), options);
|
|
5993
6499
|
files.push({
|
|
5994
|
-
path: `singletons/${
|
|
6500
|
+
path: `singletons/${naming.snake(id)}.py`,
|
|
5995
6501
|
content
|
|
5996
6502
|
});
|
|
5997
6503
|
}
|
|
@@ -6104,7 +6610,7 @@ __all__ = ['RichTextContent', 'ImageField', 'FileField', 'Reference']
|
|
|
6104
6610
|
`;
|
|
6105
6611
|
}
|
|
6106
6612
|
function generateContentType(id, contentType, options) {
|
|
6107
|
-
const className =
|
|
6613
|
+
const className = naming.pascal(id);
|
|
6108
6614
|
const fields = generateFields(contentType.fields || [], options);
|
|
6109
6615
|
const imports = ["from ..base_types import RichTextContent, ImageField, FileField, Reference"];
|
|
6110
6616
|
if (options.baseModel === "pydantic") {
|
|
@@ -6142,7 +6648,7 @@ __all__ = ['${className}', 'Create${className}Input', 'Update${className}Input']
|
|
|
6142
6648
|
}
|
|
6143
6649
|
}
|
|
6144
6650
|
function generateComponent(id, component, options) {
|
|
6145
|
-
const className =
|
|
6651
|
+
const className = naming.pascal(id);
|
|
6146
6652
|
const fields = generateFields(component.fields || [], options);
|
|
6147
6653
|
const imports = ["from ..base_types import RichTextContent, ImageField, FileField, Reference"];
|
|
6148
6654
|
if (options.baseModel === "pydantic") {
|
|
@@ -6173,7 +6679,7 @@ __all__ = ['${className}']
|
|
|
6173
6679
|
}
|
|
6174
6680
|
}
|
|
6175
6681
|
function generateSingleton(id, singleton5, options) {
|
|
6176
|
-
const className =
|
|
6682
|
+
const className = naming.pascal(id);
|
|
6177
6683
|
const fields = generateFields(singleton5.fields || [], options);
|
|
6178
6684
|
const imports = ["from ..base_types import RichTextContent, ImageField, FileField, Reference"];
|
|
6179
6685
|
if (options.baseModel === "pydantic") {
|
|
@@ -6209,12 +6715,12 @@ __all__ = ['${className}', 'Update${className}Input']
|
|
|
6209
6715
|
}
|
|
6210
6716
|
function generateFields(fields, options) {
|
|
6211
6717
|
return fields.map((field) => {
|
|
6212
|
-
const fieldName =
|
|
6718
|
+
const fieldName = naming.snake(field.id);
|
|
6213
6719
|
const pythonType = mapFieldTypeToPython(field.type, field.config);
|
|
6214
6720
|
const isOptional = !field.required;
|
|
6215
6721
|
const fieldType = isOptional ? `Optional[${pythonType}]` : pythonType;
|
|
6216
6722
|
const defaultValue = isOptional ? " = None" : "";
|
|
6217
|
-
if (options.baseModel === "pydantic" && field.id !==
|
|
6723
|
+
if (options.baseModel === "pydantic" && field.id !== naming.snake(field.id)) {
|
|
6218
6724
|
return `${fieldName}: ${fieldType} = Field(${defaultValue.slice(3)}, alias='${field.id}')`;
|
|
6219
6725
|
}
|
|
6220
6726
|
return `${fieldName}: ${fieldType}${defaultValue}`;
|
|
@@ -6334,8 +6840,8 @@ class TenantContext(BaseModel):
|
|
|
6334
6840
|
`);
|
|
6335
6841
|
if (isRecord2(ir.contentTypes)) {
|
|
6336
6842
|
for (const id of Object.keys(ir.contentTypes)) {
|
|
6337
|
-
const className =
|
|
6338
|
-
imports.push(`from .content_types.${
|
|
6843
|
+
const className = naming.pascal(id);
|
|
6844
|
+
imports.push(`from .content_types.${naming.snake(id)} import ${className}`);
|
|
6339
6845
|
tenantTypes.push(`
|
|
6340
6846
|
class Tenant${className}(${className}):
|
|
6341
6847
|
"""Tenant-scoped ${className}"""
|
|
@@ -6354,8 +6860,8 @@ class TenantContext:
|
|
|
6354
6860
|
`);
|
|
6355
6861
|
if (isRecord2(ir.contentTypes)) {
|
|
6356
6862
|
for (const id of Object.keys(ir.contentTypes)) {
|
|
6357
|
-
const className =
|
|
6358
|
-
imports.push(`from .content_types.${
|
|
6863
|
+
const className = naming.pascal(id);
|
|
6864
|
+
imports.push(`from .content_types.${naming.snake(id)} import ${className}`);
|
|
6359
6865
|
tenantTypes.push(`
|
|
6360
6866
|
@dataclass
|
|
6361
6867
|
class Tenant${className}(${className}):
|
|
@@ -6368,7 +6874,7 @@ class Tenant${className}(${className}):
|
|
|
6368
6874
|
const exportList = ["TenantContext"];
|
|
6369
6875
|
if (isRecord2(ir.contentTypes)) {
|
|
6370
6876
|
for (const id of Object.keys(ir.contentTypes)) {
|
|
6371
|
-
exportList.push(`Tenant${
|
|
6877
|
+
exportList.push(`Tenant${naming.pascal(id)}`);
|
|
6372
6878
|
}
|
|
6373
6879
|
}
|
|
6374
6880
|
return `${imports.join("\n")}
|
|
@@ -6411,10 +6917,10 @@ __all__ = ['validate_data', 'to_dict', 'to_json']
|
|
|
6411
6917
|
}
|
|
6412
6918
|
function generateContentTypesIndex(contentTypeIds, _options) {
|
|
6413
6919
|
const imports = contentTypeIds.map(
|
|
6414
|
-
(id) => `from .${
|
|
6920
|
+
(id) => `from .${naming.snake(id)} import ${naming.pascal(id)}, Create${naming.pascal(id)}Input, Update${naming.pascal(id)}Input`
|
|
6415
6921
|
);
|
|
6416
6922
|
const exports = contentTypeIds.flatMap((id) => {
|
|
6417
|
-
const className =
|
|
6923
|
+
const className = naming.pascal(id);
|
|
6418
6924
|
return [`'${className}'`, `'Create${className}Input'`, `'Update${className}Input'`];
|
|
6419
6925
|
});
|
|
6420
6926
|
return `${imports.join("\n")}
|
|
@@ -6423,8 +6929,8 @@ __all__ = [${exports.join(", ")}]
|
|
|
6423
6929
|
`;
|
|
6424
6930
|
}
|
|
6425
6931
|
function generateComponentsIndex(componentIds, _options) {
|
|
6426
|
-
const imports = componentIds.map((id) => `from .${
|
|
6427
|
-
const exports = componentIds.map((id) => `'${
|
|
6932
|
+
const imports = componentIds.map((id) => `from .${naming.snake(id)} import ${naming.pascal(id)}`);
|
|
6933
|
+
const exports = componentIds.map((id) => `'${naming.pascal(id)}'`);
|
|
6428
6934
|
return `${imports.join("\n")}
|
|
6429
6935
|
|
|
6430
6936
|
__all__ = [${exports.join(", ")}]
|
|
@@ -6432,10 +6938,10 @@ __all__ = [${exports.join(", ")}]
|
|
|
6432
6938
|
}
|
|
6433
6939
|
function generateSingletonsIndex(singletonIds, _options) {
|
|
6434
6940
|
const imports = singletonIds.map(
|
|
6435
|
-
(id) => `from .${
|
|
6941
|
+
(id) => `from .${naming.snake(id)} import ${naming.pascal(id)}, Update${naming.pascal(id)}Input`
|
|
6436
6942
|
);
|
|
6437
6943
|
const exports = singletonIds.flatMap((id) => {
|
|
6438
|
-
const className =
|
|
6944
|
+
const className = naming.pascal(id);
|
|
6439
6945
|
return [`'${className}'`, `'Update${className}Input'`];
|
|
6440
6946
|
});
|
|
6441
6947
|
return `${imports.join("\n")}
|
|
@@ -6444,8 +6950,10 @@ __all__ = [${exports.join(", ")}]
|
|
|
6444
6950
|
`;
|
|
6445
6951
|
}
|
|
6446
6952
|
var plugin2, index_default2;
|
|
6447
|
-
var
|
|
6953
|
+
var init_dist5 = __esm({
|
|
6448
6954
|
"../codegen-python/dist/index.js"() {
|
|
6955
|
+
init_dist2();
|
|
6956
|
+
init_dist2();
|
|
6449
6957
|
plugin2 = {
|
|
6450
6958
|
language: "python",
|
|
6451
6959
|
async generate(ir, options) {
|
|
@@ -6659,16 +7167,23 @@ var init_diff_service = __esm({
|
|
|
6659
7167
|
}
|
|
6660
7168
|
});
|
|
6661
7169
|
|
|
6662
|
-
// src/ai/core/
|
|
7170
|
+
// src/ai/core/gateway-url.ts
|
|
6663
7171
|
function getGatewayUrl() {
|
|
6664
7172
|
if (process.env.RELYIO_AI_GATEWAY_URL) {
|
|
6665
7173
|
return process.env.RELYIO_AI_GATEWAY_URL.replaceAll("http://localhost", "http://127.0.0.1");
|
|
6666
7174
|
}
|
|
6667
|
-
if (process.env.RELYIO_API_URL)
|
|
6668
|
-
|
|
6669
|
-
}
|
|
6670
|
-
return "https://ai-gateway.relyio.com";
|
|
7175
|
+
if (process.env.RELYIO_API_URL) return LOCAL_GATEWAY_URL;
|
|
7176
|
+
return PRODUCTION_GATEWAY_URL;
|
|
6671
7177
|
}
|
|
7178
|
+
var PRODUCTION_GATEWAY_URL, LOCAL_GATEWAY_URL;
|
|
7179
|
+
var init_gateway_url = __esm({
|
|
7180
|
+
"src/ai/core/gateway-url.ts"() {
|
|
7181
|
+
PRODUCTION_GATEWAY_URL = "https://ai.relyio.com";
|
|
7182
|
+
LOCAL_GATEWAY_URL = "http://127.0.0.1:3600";
|
|
7183
|
+
}
|
|
7184
|
+
});
|
|
7185
|
+
|
|
7186
|
+
// src/ai/core/stream-client.ts
|
|
6672
7187
|
function getAuthToken3() {
|
|
6673
7188
|
const token = config_default.getAuthToken();
|
|
6674
7189
|
if (token) return token;
|
|
@@ -6680,6 +7195,7 @@ var AI_GATEWAY_PATH, MAX_RETRIES, RETRY_DELAY_MS, REQUEST_TIMEOUT_MS, GatewayStr
|
|
|
6680
7195
|
var init_stream_client = __esm({
|
|
6681
7196
|
"src/ai/core/stream-client.ts"() {
|
|
6682
7197
|
init_config();
|
|
7198
|
+
init_gateway_url();
|
|
6683
7199
|
AI_GATEWAY_PATH = "/ai/cli";
|
|
6684
7200
|
MAX_RETRIES = 2;
|
|
6685
7201
|
RETRY_DELAY_MS = 1e3;
|
|
@@ -6830,13 +7346,6 @@ var init_stream_client = __esm({
|
|
|
6830
7346
|
});
|
|
6831
7347
|
|
|
6832
7348
|
// src/ai/services/handoff-client.ts
|
|
6833
|
-
function getGatewayUrl2() {
|
|
6834
|
-
if (process.env.RELYIO_AI_GATEWAY_URL) {
|
|
6835
|
-
return process.env.RELYIO_AI_GATEWAY_URL.replaceAll("http://localhost", "http://127.0.0.1");
|
|
6836
|
-
}
|
|
6837
|
-
if (process.env.RELYIO_API_URL) return "http://127.0.0.1:3600";
|
|
6838
|
-
return "https://ai-gateway.relyio.com";
|
|
6839
|
-
}
|
|
6840
7349
|
function getAuthToken4() {
|
|
6841
7350
|
const token = config_default.getAuthToken();
|
|
6842
7351
|
return token ?? null;
|
|
@@ -6847,7 +7356,7 @@ async function fetchHandoffSummary(req) {
|
|
|
6847
7356
|
const controller = new AbortController();
|
|
6848
7357
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
6849
7358
|
try {
|
|
6850
|
-
const response = await fetch(`${
|
|
7359
|
+
const response = await fetch(`${getGatewayUrl()}${AI_GATEWAY_HANDOFF_PATH}`, {
|
|
6851
7360
|
method: "POST",
|
|
6852
7361
|
headers: {
|
|
6853
7362
|
"Content-Type": "application/json",
|
|
@@ -6856,7 +7365,8 @@ async function fetchHandoffSummary(req) {
|
|
|
6856
7365
|
body: JSON.stringify({
|
|
6857
7366
|
fromAgent: req.fromAgent,
|
|
6858
7367
|
toAgent: req.toAgent,
|
|
6859
|
-
messages: req.messages
|
|
7368
|
+
messages: req.messages,
|
|
7369
|
+
projectId: req.projectId
|
|
6860
7370
|
}),
|
|
6861
7371
|
signal: controller.signal
|
|
6862
7372
|
});
|
|
@@ -6873,6 +7383,7 @@ var init_handoff_client = __esm({
|
|
|
6873
7383
|
"src/ai/services/handoff-client.ts"() {
|
|
6874
7384
|
init_wire();
|
|
6875
7385
|
init_config();
|
|
7386
|
+
init_gateway_url();
|
|
6876
7387
|
AI_GATEWAY_HANDOFF_PATH = "/ai/cli/handoff/summary";
|
|
6877
7388
|
REQUEST_TIMEOUT_MS2 = 15e3;
|
|
6878
7389
|
}
|
|
@@ -8038,7 +8549,7 @@ var init_agent_loop = __esm({
|
|
|
8038
8549
|
async tryReadFile(relPath) {
|
|
8039
8550
|
if (!this.projectRoot) return void 0;
|
|
8040
8551
|
try {
|
|
8041
|
-
const fullPath =
|
|
8552
|
+
const fullPath = path5.resolve(this.projectRoot, relPath);
|
|
8042
8553
|
if (!fullPath.startsWith(this.projectRoot)) return void 0;
|
|
8043
8554
|
return await readFile(fullPath, "utf8");
|
|
8044
8555
|
} catch {
|
|
@@ -8199,7 +8710,9 @@ var init_agent_loop = __esm({
|
|
|
8199
8710
|
const result = await fetchHandoffSummary({
|
|
8200
8711
|
fromAgent,
|
|
8201
8712
|
toAgent,
|
|
8202
|
-
messages: this.messages
|
|
8713
|
+
messages: this.messages,
|
|
8714
|
+
// The gateway needs it to attribute the summary's tokens and cost to an org.
|
|
8715
|
+
projectId: this.options.context.projectId
|
|
8203
8716
|
});
|
|
8204
8717
|
if (result) {
|
|
8205
8718
|
this.messages = [
|
|
@@ -8295,10 +8808,10 @@ var init_permission_gate = __esm({
|
|
|
8295
8808
|
return PROTECTED_PATHS.some((p) => normalized.startsWith(p) || normalized.includes(`/${p}`));
|
|
8296
8809
|
}
|
|
8297
8810
|
isOutsideProjectRoot(filePath) {
|
|
8298
|
-
if (
|
|
8811
|
+
if (path5.isAbsolute(filePath)) {
|
|
8299
8812
|
return !filePath.startsWith(this.projectRoot);
|
|
8300
8813
|
}
|
|
8301
|
-
const resolved =
|
|
8814
|
+
const resolved = path5.resolve(this.projectRoot, filePath);
|
|
8302
8815
|
return !resolved.startsWith(this.projectRoot);
|
|
8303
8816
|
}
|
|
8304
8817
|
};
|
|
@@ -8447,7 +8960,7 @@ var init_context_provider = __esm({
|
|
|
8447
8960
|
});
|
|
8448
8961
|
const schemaFiles = [];
|
|
8449
8962
|
for (const filePath of files) {
|
|
8450
|
-
const fullPath =
|
|
8963
|
+
const fullPath = path5.join(projectRoot, filePath);
|
|
8451
8964
|
try {
|
|
8452
8965
|
const stats = await stat2(fullPath);
|
|
8453
8966
|
const contentType = this.inferContentType(filePath);
|
|
@@ -8515,7 +9028,7 @@ var init_read_file_handler = __esm({
|
|
|
8515
9028
|
}
|
|
8516
9029
|
async execute(input) {
|
|
8517
9030
|
const filePath = input.path;
|
|
8518
|
-
const fullPath =
|
|
9031
|
+
const fullPath = path5.resolve(this.projectRoot, filePath);
|
|
8519
9032
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
8520
9033
|
return { error: "Path is outside project root" };
|
|
8521
9034
|
}
|
|
@@ -8598,12 +9111,12 @@ var init_write_file_handler = __esm({
|
|
|
8598
9111
|
async execute(input) {
|
|
8599
9112
|
const filePath = input.path;
|
|
8600
9113
|
const content = input.content;
|
|
8601
|
-
const fullPath =
|
|
9114
|
+
const fullPath = path5.resolve(this.projectRoot, filePath);
|
|
8602
9115
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
8603
9116
|
return { error: "Path is outside project root" };
|
|
8604
9117
|
}
|
|
8605
9118
|
try {
|
|
8606
|
-
await mkdir(
|
|
9119
|
+
await mkdir(path5.dirname(fullPath), { recursive: true });
|
|
8607
9120
|
await writeFile(fullPath, content, "utf8");
|
|
8608
9121
|
return { success: true, path: filePath, bytesWritten: content.length };
|
|
8609
9122
|
} catch (error2) {
|
|
@@ -8627,7 +9140,7 @@ var init_apply_patch_handler = __esm({
|
|
|
8627
9140
|
const filePath = input.path;
|
|
8628
9141
|
const searchBlock = input.searchBlock;
|
|
8629
9142
|
const replaceBlock = input.replaceBlock;
|
|
8630
|
-
const fullPath =
|
|
9143
|
+
const fullPath = path5.resolve(this.projectRoot, filePath);
|
|
8631
9144
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
8632
9145
|
return { error: "Path is outside project root" };
|
|
8633
9146
|
}
|
|
@@ -10135,7 +10648,7 @@ function Banner() {
|
|
|
10135
10648
|
label: "App",
|
|
10136
10649
|
value: dev.sandbox.wiredEnv ? "wired" : "manual",
|
|
10137
10650
|
valueColor: dev.sandbox.wiredEnv ? "green" : void 0,
|
|
10138
|
-
suffix: dev.sandbox.wiredEnv ? void 0 :
|
|
10651
|
+
suffix: dev.sandbox.wiredEnv ? void 0 : DEV_CONTEXT_FILE
|
|
10139
10652
|
}
|
|
10140
10653
|
];
|
|
10141
10654
|
} else {
|
|
@@ -10201,11 +10714,12 @@ function FieldRow({ field }) {
|
|
|
10201
10714
|
var CLI_VERSION2, BRAND_GLYPH, BRAND_NAME, LABEL_WIDTH, TWO_COLUMN_MIN_COLS;
|
|
10202
10715
|
var init_banner = __esm({
|
|
10203
10716
|
"src/ai/repl/components/banner.tsx"() {
|
|
10717
|
+
init_dev_handshake();
|
|
10204
10718
|
init_runtime_context();
|
|
10205
10719
|
init_dev_cockpit_context();
|
|
10206
10720
|
init_dev_cockpit_format();
|
|
10207
10721
|
init_startup_info();
|
|
10208
|
-
CLI_VERSION2 = "0.
|
|
10722
|
+
CLI_VERSION2 = "0.3.0" ;
|
|
10209
10723
|
BRAND_GLYPH = "\u25B6";
|
|
10210
10724
|
BRAND_NAME = "RelyIO";
|
|
10211
10725
|
LABEL_WIDTH = 9;
|
|
@@ -10465,8 +10979,8 @@ function entryLabel(fields, contentType) {
|
|
|
10465
10979
|
return title || contentType || "";
|
|
10466
10980
|
}
|
|
10467
10981
|
function itemTarget(tc) {
|
|
10468
|
-
const
|
|
10469
|
-
if (
|
|
10982
|
+
const path25 = tc.input.path;
|
|
10983
|
+
if (path25) return path25;
|
|
10470
10984
|
switch (tc.toolName) {
|
|
10471
10985
|
case "getSchemaReference": {
|
|
10472
10986
|
const topic = tc.input.topic;
|
|
@@ -11194,8 +11708,8 @@ var init_input_preprocessor = __esm({
|
|
|
11194
11708
|
var HISTORY_DIR, HISTORY_FILE, MAX_HISTORY_ENTRIES, PersistentHistory;
|
|
11195
11709
|
var init_input_history = __esm({
|
|
11196
11710
|
"src/ai/services/input-history.ts"() {
|
|
11197
|
-
HISTORY_DIR =
|
|
11198
|
-
HISTORY_FILE =
|
|
11711
|
+
HISTORY_DIR = path5.join(os.homedir(), ".relyio");
|
|
11712
|
+
HISTORY_FILE = path5.join(HISTORY_DIR, "ai-history");
|
|
11199
11713
|
MAX_HISTORY_ENTRIES = 1e3;
|
|
11200
11714
|
PersistentHistory = class {
|
|
11201
11715
|
entries = [];
|
|
@@ -11206,7 +11720,7 @@ var init_input_history = __esm({
|
|
|
11206
11720
|
}
|
|
11207
11721
|
load() {
|
|
11208
11722
|
try {
|
|
11209
|
-
fs2.mkdirSync(
|
|
11723
|
+
fs2.mkdirSync(path5.dirname(this.filePath), { recursive: true });
|
|
11210
11724
|
if (fs2.existsSync(this.filePath)) {
|
|
11211
11725
|
const content = fs2.readFileSync(this.filePath, "utf8");
|
|
11212
11726
|
this.entries = content.split("\n").filter(Boolean);
|
|
@@ -11236,7 +11750,7 @@ var init_input_history = __esm({
|
|
|
11236
11750
|
}
|
|
11237
11751
|
save() {
|
|
11238
11752
|
try {
|
|
11239
|
-
fs2.mkdirSync(
|
|
11753
|
+
fs2.mkdirSync(path5.dirname(this.filePath), { recursive: true });
|
|
11240
11754
|
fs2.writeFileSync(this.filePath, this.entries.join("\n") + "\n");
|
|
11241
11755
|
} catch {
|
|
11242
11756
|
}
|
|
@@ -11245,18 +11759,18 @@ var init_input_history = __esm({
|
|
|
11245
11759
|
}
|
|
11246
11760
|
});
|
|
11247
11761
|
function readMentionedFile(filePath, projectRoot) {
|
|
11248
|
-
const resolved =
|
|
11762
|
+
const resolved = path5.isAbsolute(filePath) ? filePath : path5.resolve(projectRoot, filePath);
|
|
11249
11763
|
try {
|
|
11250
11764
|
const stat2 = fs2.statSync(resolved);
|
|
11251
11765
|
if (stat2.size > MAX_FILE_SIZE) {
|
|
11252
11766
|
const content2 = fs2.readFileSync(resolved, "utf8").slice(0, MAX_FILE_SIZE);
|
|
11253
11767
|
const lines2 = content2.split("\n").length;
|
|
11254
|
-
const relativePath2 =
|
|
11768
|
+
const relativePath2 = path5.relative(projectRoot, resolved);
|
|
11255
11769
|
return { filePath: relativePath2, content: content2, lines: lines2, truncated: true };
|
|
11256
11770
|
}
|
|
11257
11771
|
const content = fs2.readFileSync(resolved, "utf8");
|
|
11258
11772
|
const lines = content.split("\n").length;
|
|
11259
|
-
const relativePath =
|
|
11773
|
+
const relativePath = path5.relative(projectRoot, resolved);
|
|
11260
11774
|
return { filePath: relativePath, content, lines, truncated: false };
|
|
11261
11775
|
} catch {
|
|
11262
11776
|
return null;
|
|
@@ -12128,11 +12642,11 @@ var init_autocomplete = __esm({
|
|
|
12128
12642
|
const schemaMatches = this.schemaFiles.filter((f) => f.toLowerCase().includes(query.toLowerCase())).slice(0, 15).map((f) => ({ value: f, label: f, kind: "file" }));
|
|
12129
12643
|
if (schemaMatches.length > 0) return schemaMatches;
|
|
12130
12644
|
try {
|
|
12131
|
-
const dir = query.includes("/") ?
|
|
12132
|
-
const prefix = query.includes("/") ?
|
|
12645
|
+
const dir = query.includes("/") ? path5.join(this.projectRoot, path5.dirname(query)) : this.projectRoot;
|
|
12646
|
+
const prefix = query.includes("/") ? path5.basename(query) : query;
|
|
12133
12647
|
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
12134
12648
|
return entries.filter((e) => e.name.startsWith(prefix) && !e.name.startsWith(".")).map((e) => {
|
|
12135
|
-
const rel =
|
|
12649
|
+
const rel = path5.relative(this.projectRoot, path5.join(dir, e.name));
|
|
12136
12650
|
const value = e.isDirectory() ? `${rel}/` : rel;
|
|
12137
12651
|
return { value, label: value, kind: "file" };
|
|
12138
12652
|
}).slice(0, 15);
|
|
@@ -12459,13 +12973,6 @@ var init_agent_picker = __esm({
|
|
|
12459
12973
|
});
|
|
12460
12974
|
|
|
12461
12975
|
// src/ai/services/models-client.ts
|
|
12462
|
-
function getGatewayUrl3() {
|
|
12463
|
-
if (process.env.RELYIO_AI_GATEWAY_URL) {
|
|
12464
|
-
return process.env.RELYIO_AI_GATEWAY_URL.replaceAll("http://localhost", "http://127.0.0.1");
|
|
12465
|
-
}
|
|
12466
|
-
if (process.env.RELYIO_API_URL) return "http://127.0.0.1:3600";
|
|
12467
|
-
return "https://ai-gateway.relyio.com";
|
|
12468
|
-
}
|
|
12469
12976
|
function getAuthToken5() {
|
|
12470
12977
|
const token = config_default.getAuthToken();
|
|
12471
12978
|
if (token) return token;
|
|
@@ -12500,6 +13007,7 @@ var init_models_client = __esm({
|
|
|
12500
13007
|
"src/ai/services/models-client.ts"() {
|
|
12501
13008
|
init_wire();
|
|
12502
13009
|
init_config();
|
|
13010
|
+
init_gateway_url();
|
|
12503
13011
|
AI_GATEWAY_MODELS_PATH = "/models";
|
|
12504
13012
|
ModelsClient = class {
|
|
12505
13013
|
// In-process cache. Lifetime = CLI process. See file header for rationale.
|
|
@@ -12520,7 +13028,7 @@ var init_models_client = __esm({
|
|
|
12520
13028
|
this.cached = null;
|
|
12521
13029
|
}
|
|
12522
13030
|
async fetchModels() {
|
|
12523
|
-
const url = `${
|
|
13031
|
+
const url = `${getGatewayUrl()}${AI_GATEWAY_MODELS_PATH}`;
|
|
12524
13032
|
const response = await fetch(url, {
|
|
12525
13033
|
method: "GET",
|
|
12526
13034
|
headers: {
|
|
@@ -12599,8 +13107,7 @@ function ModelPicker() {
|
|
|
12599
13107
|
description = `${description} \xB7 now routing to ${resolvedModelId}`;
|
|
12600
13108
|
}
|
|
12601
13109
|
if (!m.available) {
|
|
12602
|
-
|
|
12603
|
-
description = `${description} \xB7 ${reason}`;
|
|
13110
|
+
description = `${description} \xB7 admin-disabled for this workspace`;
|
|
12604
13111
|
}
|
|
12605
13112
|
return {
|
|
12606
13113
|
id: m.id,
|
|
@@ -13990,7 +14497,7 @@ var init_use_confirmation = __esm({
|
|
|
13990
14497
|
var SESSIONS_DIR, SESSION_VERSION, SessionManager;
|
|
13991
14498
|
var init_session_manager = __esm({
|
|
13992
14499
|
"src/ai/services/session-manager.ts"() {
|
|
13993
|
-
SESSIONS_DIR =
|
|
14500
|
+
SESSIONS_DIR = path5.join(os.homedir(), ".relyio", "ai-sessions");
|
|
13994
14501
|
SESSION_VERSION = 4;
|
|
13995
14502
|
SessionManager = class {
|
|
13996
14503
|
sessionsDir;
|
|
@@ -13999,13 +14506,13 @@ var init_session_manager = __esm({
|
|
|
13999
14506
|
fs2.mkdirSync(this.sessionsDir, { recursive: true });
|
|
14000
14507
|
}
|
|
14001
14508
|
save(session) {
|
|
14002
|
-
const filePath =
|
|
14509
|
+
const filePath = path5.join(this.sessionsDir, `${session.id}.json`);
|
|
14003
14510
|
session.version = SESSION_VERSION;
|
|
14004
14511
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14005
14512
|
fs2.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
14006
14513
|
}
|
|
14007
14514
|
load(sessionId) {
|
|
14008
|
-
const filePath =
|
|
14515
|
+
const filePath = path5.join(this.sessionsDir, `${sessionId}.json`);
|
|
14009
14516
|
try {
|
|
14010
14517
|
const content = fs2.readFileSync(filePath, "utf8");
|
|
14011
14518
|
const parsed = JSON.parse(content);
|
|
@@ -14062,7 +14569,7 @@ var init_session_manager = __esm({
|
|
|
14062
14569
|
const files = fs2.readdirSync(this.sessionsDir).filter((f) => f.endsWith(".json"));
|
|
14063
14570
|
return files.map((f) => {
|
|
14064
14571
|
try {
|
|
14065
|
-
const content = fs2.readFileSync(
|
|
14572
|
+
const content = fs2.readFileSync(path5.join(this.sessionsDir, f), "utf8");
|
|
14066
14573
|
const parsed = JSON.parse(content);
|
|
14067
14574
|
if (parsed.version !== SESSION_VERSION && parsed.version !== 3 && parsed.version !== 2) {
|
|
14068
14575
|
return null;
|
|
@@ -14080,7 +14587,7 @@ var init_session_manager = __esm({
|
|
|
14080
14587
|
return this.listAll().slice(0, count);
|
|
14081
14588
|
}
|
|
14082
14589
|
delete(sessionId) {
|
|
14083
|
-
const filePath =
|
|
14590
|
+
const filePath = path5.join(this.sessionsDir, `${sessionId}.json`);
|
|
14084
14591
|
try {
|
|
14085
14592
|
fs2.unlinkSync(filePath);
|
|
14086
14593
|
return true;
|
|
@@ -14118,7 +14625,7 @@ var init_snapshot_store = __esm({
|
|
|
14118
14625
|
SnapshotStore = class {
|
|
14119
14626
|
dir;
|
|
14120
14627
|
constructor(sessionDir) {
|
|
14121
|
-
this.dir =
|
|
14628
|
+
this.dir = path5.join(sessionDir, "snapshots");
|
|
14122
14629
|
fs2.mkdirSync(this.dir, { recursive: true });
|
|
14123
14630
|
}
|
|
14124
14631
|
/**
|
|
@@ -14179,7 +14686,7 @@ var init_snapshot_store = __esm({
|
|
|
14179
14686
|
const hash = entry.slice(0, -4);
|
|
14180
14687
|
if (keepHashes.has(hash)) continue;
|
|
14181
14688
|
try {
|
|
14182
|
-
fs2.unlinkSync(
|
|
14689
|
+
fs2.unlinkSync(path5.join(this.dir, entry));
|
|
14183
14690
|
removed++;
|
|
14184
14691
|
} catch {
|
|
14185
14692
|
}
|
|
@@ -14187,7 +14694,7 @@ var init_snapshot_store = __esm({
|
|
|
14187
14694
|
return removed;
|
|
14188
14695
|
}
|
|
14189
14696
|
pathFor(hash) {
|
|
14190
|
-
return
|
|
14697
|
+
return path5.join(this.dir, `${hash}.bin`);
|
|
14191
14698
|
}
|
|
14192
14699
|
};
|
|
14193
14700
|
}
|
|
@@ -14202,7 +14709,7 @@ var init_decision_log = __esm({
|
|
|
14202
14709
|
DecisionLog = class {
|
|
14203
14710
|
filePath;
|
|
14204
14711
|
constructor(sessionDir) {
|
|
14205
|
-
this.filePath =
|
|
14712
|
+
this.filePath = path5.join(sessionDir, "decisions.jsonl");
|
|
14206
14713
|
if (!fs2.existsSync(this.filePath)) {
|
|
14207
14714
|
fs2.writeFileSync(this.filePath, "", "utf8");
|
|
14208
14715
|
}
|
|
@@ -14327,7 +14834,7 @@ var init_session_history = __esm({
|
|
|
14327
14834
|
"src/ai/sessions/session-history.ts"() {
|
|
14328
14835
|
init_snapshot_store();
|
|
14329
14836
|
init_decision_log();
|
|
14330
|
-
SESSIONS_ROOT =
|
|
14837
|
+
SESSIONS_ROOT = path5.join(os.homedir(), ".relyio", "ai-sessions");
|
|
14331
14838
|
MAX_UNDOABLE_EVENTS = 200;
|
|
14332
14839
|
SessionHistory = class {
|
|
14333
14840
|
sessionDir;
|
|
@@ -14336,7 +14843,7 @@ var init_session_history = __esm({
|
|
|
14336
14843
|
projectRoot;
|
|
14337
14844
|
constructor(args) {
|
|
14338
14845
|
const root = args.sessionsRoot ?? SESSIONS_ROOT;
|
|
14339
|
-
this.sessionDir =
|
|
14846
|
+
this.sessionDir = path5.join(root, args.sessionId);
|
|
14340
14847
|
fs2.mkdirSync(this.sessionDir, { recursive: true });
|
|
14341
14848
|
this.snapshots = new SnapshotStore(this.sessionDir);
|
|
14342
14849
|
this.log = new DecisionLog(this.sessionDir);
|
|
@@ -14497,11 +15004,11 @@ var init_session_history = __esm({
|
|
|
14497
15004
|
* files via a malformed log entry.
|
|
14498
15005
|
*/
|
|
14499
15006
|
async writeFileSafe(relPath, content) {
|
|
14500
|
-
const fullPath =
|
|
15007
|
+
const fullPath = path5.resolve(this.projectRoot, relPath);
|
|
14501
15008
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
14502
15009
|
throw new Error(`Refusing to write outside project root: ${relPath}`);
|
|
14503
15010
|
}
|
|
14504
|
-
await fs2.promises.mkdir(
|
|
15011
|
+
await fs2.promises.mkdir(path5.dirname(fullPath), { recursive: true });
|
|
14505
15012
|
await fs2.promises.writeFile(fullPath, content, "utf8");
|
|
14506
15013
|
}
|
|
14507
15014
|
};
|
|
@@ -14509,10 +15016,10 @@ var init_session_history = __esm({
|
|
|
14509
15016
|
});
|
|
14510
15017
|
function renameLocalSessionArtifacts(oldId, newId) {
|
|
14511
15018
|
if (oldId === newId) return;
|
|
14512
|
-
const oldTranscript =
|
|
14513
|
-
const newTranscript =
|
|
14514
|
-
const oldHistoryDir =
|
|
14515
|
-
const newHistoryDir =
|
|
15019
|
+
const oldTranscript = path5.join(SESSIONS_DIR2, `${oldId}.json`);
|
|
15020
|
+
const newTranscript = path5.join(SESSIONS_DIR2, `${newId}.json`);
|
|
15021
|
+
const oldHistoryDir = path5.join(SESSIONS_DIR2, oldId);
|
|
15022
|
+
const newHistoryDir = path5.join(SESSIONS_DIR2, newId);
|
|
14516
15023
|
try {
|
|
14517
15024
|
if (fs2.existsSync(oldTranscript) && !fs2.existsSync(newTranscript)) {
|
|
14518
15025
|
fs2.renameSync(oldTranscript, newTranscript);
|
|
@@ -14616,18 +15123,11 @@ var init_use_session_persistence = __esm({
|
|
|
14616
15123
|
init_runtime_context();
|
|
14617
15124
|
init_session_manager();
|
|
14618
15125
|
init_session_history();
|
|
14619
|
-
SESSIONS_DIR2 =
|
|
15126
|
+
SESSIONS_DIR2 = path5.join(os.homedir(), ".relyio", "ai-sessions");
|
|
14620
15127
|
}
|
|
14621
15128
|
});
|
|
14622
15129
|
|
|
14623
15130
|
// src/ai/services/proposals-client.ts
|
|
14624
|
-
function getGatewayUrl4() {
|
|
14625
|
-
if (process.env.RELYIO_AI_GATEWAY_URL) {
|
|
14626
|
-
return process.env.RELYIO_AI_GATEWAY_URL.replaceAll("http://localhost", "http://127.0.0.1");
|
|
14627
|
-
}
|
|
14628
|
-
if (process.env.RELYIO_API_URL) return "http://127.0.0.1:3600";
|
|
14629
|
-
return "https://ai-gateway.relyio.com";
|
|
14630
|
-
}
|
|
14631
15131
|
function getAuthToken6() {
|
|
14632
15132
|
const token = config_default.getAuthToken();
|
|
14633
15133
|
if (token) return token;
|
|
@@ -14642,10 +15142,11 @@ var init_proposals_client = __esm({
|
|
|
14642
15142
|
"src/ai/services/proposals-client.ts"() {
|
|
14643
15143
|
init_wire();
|
|
14644
15144
|
init_config();
|
|
15145
|
+
init_gateway_url();
|
|
14645
15146
|
AI_GATEWAY_PROPOSALS_PATH = "/ai/proposals";
|
|
14646
15147
|
ProposalsClient = class {
|
|
14647
|
-
async request(method,
|
|
14648
|
-
const url = new URL(`${
|
|
15148
|
+
async request(method, path25, init = {}) {
|
|
15149
|
+
const url = new URL(`${getGatewayUrl()}${AI_GATEWAY_PROPOSALS_PATH}${path25}`);
|
|
14649
15150
|
if (init.query) {
|
|
14650
15151
|
for (const [k, v] of Object.entries(init.query)) url.searchParams.set(k, v);
|
|
14651
15152
|
}
|
|
@@ -14661,7 +15162,7 @@ var init_proposals_client = __esm({
|
|
|
14661
15162
|
const raw = await response.text().catch(() => "");
|
|
14662
15163
|
const refusal = readError(parseJson(raw));
|
|
14663
15164
|
throw new Error(
|
|
14664
|
-
refusal === void 0 ? `Proposals API ${method} ${
|
|
15165
|
+
refusal === void 0 ? `Proposals API ${method} ${path25} \u2192 ${response.status}: ${raw}` : `Proposals API ${method} ${path25} \u2192 ${response.status} ${refusal.code}: ${refusal.messages.join(" ")}`
|
|
14665
15166
|
);
|
|
14666
15167
|
}
|
|
14667
15168
|
return readPayload(await response.json());
|
|
@@ -15439,8 +15940,8 @@ function formatHistoryEntries(entries, status, limit) {
|
|
|
15439
15940
|
const rows = entries.map((e) => {
|
|
15440
15941
|
const time = new Date(e.timestamp).toLocaleTimeString();
|
|
15441
15942
|
const glyph = decisionGlyph(e.kind);
|
|
15442
|
-
const
|
|
15443
|
-
return ` ${time} ${glyph} ${
|
|
15943
|
+
const path25 = e.path || "\u2014";
|
|
15944
|
+
return ` ${time} ${glyph} ${path25}`;
|
|
15444
15945
|
});
|
|
15445
15946
|
return [header, "", ...rows, "", footer].join("\n");
|
|
15446
15947
|
}
|
|
@@ -15678,11 +16179,10 @@ Tip: just type \`/model\` (no args) to pick interactively.`
|
|
|
15678
16179
|
return;
|
|
15679
16180
|
}
|
|
15680
16181
|
if (!match.available) {
|
|
15681
|
-
const reason = match.disabledReason === "paused" ? "AI is paused globally" : "this model is currently disabled by the workspace admin";
|
|
15682
16182
|
ctx.dispatch({
|
|
15683
16183
|
type: "SYSTEM_MESSAGE_APPENDED",
|
|
15684
16184
|
label: "/model",
|
|
15685
|
-
text: `Cannot switch to ${match.name} \u2014
|
|
16185
|
+
text: `Cannot switch to ${match.name} \u2014 this model is currently disabled by the workspace admin.`
|
|
15686
16186
|
});
|
|
15687
16187
|
return;
|
|
15688
16188
|
}
|
|
@@ -16068,7 +16568,7 @@ async function resolveContext(spec, flags, pins = {}) {
|
|
|
16068
16568
|
acc.datasetId = pins.datasetId;
|
|
16069
16569
|
acc.datasetName = await safeDatasetName(projectId, acc.branchId, pins.datasetId);
|
|
16070
16570
|
} else {
|
|
16071
|
-
const datasetOutcome = await
|
|
16571
|
+
const datasetOutcome = await resolveDataset2(projectId, acc.branchId, flags.dataset);
|
|
16072
16572
|
if (datasetOutcome.kind === "needs-pick") {
|
|
16073
16573
|
return { ...datasetOutcome, partial: acc };
|
|
16074
16574
|
}
|
|
@@ -16142,7 +16642,7 @@ async function safeBranchName(projectId, branchId) {
|
|
|
16142
16642
|
return void 0;
|
|
16143
16643
|
}
|
|
16144
16644
|
}
|
|
16145
|
-
async function
|
|
16645
|
+
async function resolveDataset2(projectId, branchId, flag) {
|
|
16146
16646
|
let datasets;
|
|
16147
16647
|
try {
|
|
16148
16648
|
datasets = await manage_default.getProjectDatasets(projectId, { branchId });
|
|
@@ -16722,223 +17222,55 @@ function confirm(message) {
|
|
|
16722
17222
|
// src/api/auth.ts
|
|
16723
17223
|
init_client();
|
|
16724
17224
|
init_config();
|
|
17225
|
+
init_dist();
|
|
16725
17226
|
var isDebug3 = () => process.env.DEBUG === "true" || process.env.DEBUG === "1";
|
|
16726
|
-
var
|
|
16727
|
-
success: (tokenName) => `
|
|
16728
|
-
<html>
|
|
16729
|
-
<head>
|
|
16730
|
-
<title>RelyIO Authentication</title>
|
|
16731
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16732
|
-
<style>
|
|
16733
|
-
body {
|
|
16734
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16735
|
-
text-align: center;
|
|
16736
|
-
padding: 2rem;
|
|
16737
|
-
max-width: 600px;
|
|
16738
|
-
margin: 0 auto;
|
|
16739
|
-
line-height: 1.5;
|
|
16740
|
-
color: #333;
|
|
16741
|
-
}
|
|
16742
|
-
h1 { color: #38a169; margin-bottom: 1rem; }
|
|
16743
|
-
p { margin-bottom: 1rem; }
|
|
16744
|
-
</style>
|
|
16745
|
-
</head>
|
|
16746
|
-
<body>
|
|
16747
|
-
<h1>Authentication Successful</h1>
|
|
16748
|
-
<p>${tokenName ? `Personal access token "${tokenName}" created successfully.` : "You have successfully authenticated."}</p>
|
|
16749
|
-
<p>You can close this window and return to the CLI.</p>
|
|
16750
|
-
</body>
|
|
16751
|
-
</html>
|
|
16752
|
-
`,
|
|
16753
|
-
error: (message) => `
|
|
16754
|
-
<html>
|
|
16755
|
-
<head>
|
|
16756
|
-
<title>RelyIO Authentication Error</title>
|
|
16757
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16758
|
-
<style>
|
|
16759
|
-
body {
|
|
16760
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16761
|
-
text-align: center;
|
|
16762
|
-
padding: 2rem;
|
|
16763
|
-
max-width: 600px;
|
|
16764
|
-
margin: 0 auto;
|
|
16765
|
-
line-height: 1.5;
|
|
16766
|
-
color: #333;
|
|
16767
|
-
}
|
|
16768
|
-
h1 { color: #e53e3e; margin-bottom: 1rem; }
|
|
16769
|
-
p { margin-bottom: 1rem; }
|
|
16770
|
-
</style>
|
|
16771
|
-
</head>
|
|
16772
|
-
<body>
|
|
16773
|
-
<h1>Authentication Failed</h1>
|
|
16774
|
-
<p>${message}</p>
|
|
16775
|
-
<p>Please try again or contact support if the issue persists.</p>
|
|
16776
|
-
</body>
|
|
16777
|
-
</html>
|
|
16778
|
-
`,
|
|
16779
|
-
serverError: (message) => `
|
|
16780
|
-
<html>
|
|
16781
|
-
<head>
|
|
16782
|
-
<title>RelyIO Server Error</title>
|
|
16783
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16784
|
-
<style>
|
|
16785
|
-
body {
|
|
16786
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16787
|
-
text-align: center;
|
|
16788
|
-
padding: 2rem;
|
|
16789
|
-
max-width: 600px;
|
|
16790
|
-
margin: 0 auto;
|
|
16791
|
-
line-height: 1.5;
|
|
16792
|
-
color: #333;
|
|
16793
|
-
}
|
|
16794
|
-
h1 { color: #e53e3e; margin-bottom: 1rem; }
|
|
16795
|
-
p { margin-bottom: 1rem; }
|
|
16796
|
-
</style>
|
|
16797
|
-
</head>
|
|
16798
|
-
<body>
|
|
16799
|
-
<h1>Internal Error</h1>
|
|
16800
|
-
<p>An unexpected error occurred during authentication:</p>
|
|
16801
|
-
<p>${message}</p>
|
|
16802
|
-
<p>Please try again or contact support if the issue persists.</p>
|
|
16803
|
-
</body>
|
|
16804
|
-
</html>
|
|
16805
|
-
`
|
|
16806
|
-
};
|
|
17227
|
+
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
16807
17228
|
async function login(email, password) {
|
|
16808
17229
|
const response = await client_default.post("/auth/login", { email, password });
|
|
16809
17230
|
await config_default.storeAuthToken(response.token);
|
|
16810
17231
|
return response;
|
|
16811
17232
|
}
|
|
16812
17233
|
async function browserLogin() {
|
|
16813
|
-
const server = http.createServer();
|
|
16814
|
-
await new Promise((resolve) => server.listen(0, resolve));
|
|
16815
|
-
const { port } = server.address();
|
|
16816
|
-
const callbackUrl = `http://localhost:${port}`;
|
|
16817
|
-
const deviceName = os__default.hostname();
|
|
16818
17234
|
const dashboardUrl = config_default.getDashboardUrl();
|
|
16819
17235
|
if (!dashboardUrl) {
|
|
16820
17236
|
throw new Error(
|
|
16821
17237
|
"Dashboard URL is not configured. Please run the command with --dashboard-url option."
|
|
16822
17238
|
);
|
|
16823
17239
|
}
|
|
16824
|
-
const
|
|
17240
|
+
const state = randomBytes(32).toString("base64url");
|
|
17241
|
+
const server = await startCallbackServer({ callbackPath: "/" });
|
|
16825
17242
|
try {
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
(
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
);
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16846
|
-
|
|
16847
|
-
|
|
16848
|
-
|
|
16849
|
-
if (!authProcessed && token) {
|
|
16850
|
-
authProcessed = true;
|
|
16851
|
-
clearTimeout(timeoutId);
|
|
16852
|
-
try {
|
|
16853
|
-
await (token_name && expires_at ? config_default.storePAT(token, token_name, expires_at) : config_default.storeAuthToken(token));
|
|
16854
|
-
sendHtmlResponse(res, 200, HTML_TEMPLATES.success(token_name || void 0));
|
|
16855
|
-
let user;
|
|
16856
|
-
try {
|
|
16857
|
-
user = await getCurrentUser();
|
|
16858
|
-
} catch (userError) {
|
|
16859
|
-
if (isDebug3()) console.error("[relyio-cli][debug] fetch user failed:", userError);
|
|
16860
|
-
user = {
|
|
16861
|
-
id: "unknown",
|
|
16862
|
-
email: "unknown",
|
|
16863
|
-
name: "Unknown User"
|
|
16864
|
-
};
|
|
16865
|
-
}
|
|
16866
|
-
cleanupServer(server);
|
|
16867
|
-
resolve({
|
|
16868
|
-
token,
|
|
16869
|
-
user
|
|
16870
|
-
});
|
|
16871
|
-
} catch (storageError) {
|
|
16872
|
-
if (isDebug3()) console.error("[relyio-cli][debug] token storage:", storageError);
|
|
16873
|
-
sendHtmlResponse(
|
|
16874
|
-
res,
|
|
16875
|
-
500,
|
|
16876
|
-
HTML_TEMPLATES.serverError("Failed to store authentication token")
|
|
16877
|
-
);
|
|
16878
|
-
cleanupServer(server);
|
|
16879
|
-
reject(storageError);
|
|
16880
|
-
}
|
|
16881
|
-
} else if (!authProcessed && params.has("error")) {
|
|
16882
|
-
authProcessed = true;
|
|
16883
|
-
const errorMsg = params.get("error") || "Authentication failed or was canceled.";
|
|
16884
|
-
sendHtmlResponse(res, 400, HTML_TEMPLATES.error(errorMsg));
|
|
16885
|
-
cleanupServer(server);
|
|
16886
|
-
reject(new Error(errorMsg));
|
|
16887
|
-
} else {
|
|
16888
|
-
if (!token && !authProcessed) {
|
|
16889
|
-
if (!res.headersSent) {
|
|
16890
|
-
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
16891
|
-
res.end("Waiting for authentication to complete...");
|
|
16892
|
-
}
|
|
16893
|
-
} else if (authProcessed && !res.headersSent) {
|
|
16894
|
-
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
16895
|
-
res.end("Authentication already processed. You can close this window.");
|
|
16896
|
-
}
|
|
16897
|
-
}
|
|
16898
|
-
} catch (error2) {
|
|
16899
|
-
if (isDebug3()) console.error("[relyio-cli][debug] callback processing:", error2);
|
|
16900
|
-
if (authProcessed) {
|
|
16901
|
-
if (!res.headersSent) {
|
|
16902
|
-
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
16903
|
-
res.end("Error occurred, but authentication was already processed.");
|
|
16904
|
-
}
|
|
16905
|
-
} else {
|
|
16906
|
-
authProcessed = true;
|
|
16907
|
-
if (!res.headersSent) {
|
|
16908
|
-
sendHtmlResponse(
|
|
16909
|
-
res,
|
|
16910
|
-
500,
|
|
16911
|
-
HTML_TEMPLATES.serverError(error2.message || "Unknown error")
|
|
16912
|
-
);
|
|
16913
|
-
}
|
|
16914
|
-
cleanupServer(server);
|
|
16915
|
-
reject(error2);
|
|
16916
|
-
}
|
|
16917
|
-
}
|
|
16918
|
-
});
|
|
16919
|
-
});
|
|
16920
|
-
return tokenData;
|
|
16921
|
-
}
|
|
16922
|
-
function sendHtmlResponse(res, statusCode, html) {
|
|
16923
|
-
if (!res.headersSent) {
|
|
16924
|
-
res.writeHead(statusCode, {
|
|
16925
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
16926
|
-
"Cache-Control": "no-store, no-cache, must-revalidate"
|
|
16927
|
-
});
|
|
16928
|
-
res.end(html);
|
|
17243
|
+
const authUrl = new URL("/auth/cli-login", dashboardUrl);
|
|
17244
|
+
authUrl.searchParams.set("callback", server.redirectUri);
|
|
17245
|
+
authUrl.searchParams.set("device_name", os__default.hostname());
|
|
17246
|
+
authUrl.searchParams.set("state", state);
|
|
17247
|
+
try {
|
|
17248
|
+
await open(authUrl.toString());
|
|
17249
|
+
console.log(success("Browser opened successfully"));
|
|
17250
|
+
} catch (error2) {
|
|
17251
|
+
console.error(error(`Failed to open browser: ${error2.message}`));
|
|
17252
|
+
throw new Error(`Failed to open browser: ${error2.message}`);
|
|
17253
|
+
}
|
|
17254
|
+
console.log(info("Waiting for authentication to complete..."));
|
|
17255
|
+
const handOff = await server.waitForCallback(state, LOGIN_TIMEOUT_MS);
|
|
17256
|
+
const token = handOff.get("token");
|
|
17257
|
+
const tokenName = handOff.get("token_name");
|
|
17258
|
+
const expiresAt = handOff.get("expires_at");
|
|
17259
|
+
if (token === null || token === "") {
|
|
17260
|
+
throw new Error("The sign-in callback carried no token.");
|
|
17261
|
+
}
|
|
17262
|
+
await (tokenName && expiresAt ? config_default.storePAT(token, tokenName, expiresAt) : config_default.storeAuthToken(token));
|
|
17263
|
+
return { token, user: await currentUserOrStub() };
|
|
17264
|
+
} finally {
|
|
17265
|
+
server.close();
|
|
16929
17266
|
}
|
|
16930
17267
|
}
|
|
16931
|
-
function
|
|
17268
|
+
async function currentUserOrStub() {
|
|
16932
17269
|
try {
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
}
|
|
16937
|
-
const exitTimeout = setTimeout(() => {
|
|
16938
|
-
}, 100);
|
|
16939
|
-
exitTimeout.unref();
|
|
16940
|
-
} catch (error2) {
|
|
16941
|
-
if (isDebug3()) console.error("[relyio-cli][debug] server close:", error2);
|
|
17270
|
+
return await getCurrentUser();
|
|
17271
|
+
} catch (userError) {
|
|
17272
|
+
if (isDebug3()) console.error("[relyio-cli][debug] fetch user failed:", userError);
|
|
17273
|
+
return { id: "unknown", email: "unknown", name: "Unknown User" };
|
|
16942
17274
|
}
|
|
16943
17275
|
}
|
|
16944
17276
|
async function logout() {
|
|
@@ -17025,18 +17357,17 @@ init_client();
|
|
|
17025
17357
|
async function getProjects() {
|
|
17026
17358
|
return await client_default.get("/projects");
|
|
17027
17359
|
}
|
|
17028
|
-
var
|
|
17029
|
-
var __dirname = path3.dirname(__filename);
|
|
17360
|
+
var __dirname = path5.dirname(fileURLToPath(import.meta.url));
|
|
17030
17361
|
function getTemplatesDir() {
|
|
17031
17362
|
const override = process.env.RELYIO_CLI_TEMPLATES_DIR;
|
|
17032
17363
|
const candidates = [
|
|
17033
|
-
override ?
|
|
17364
|
+
override ? path5.resolve(override) : null,
|
|
17034
17365
|
// dist/index.js → ../templates (built layout)
|
|
17035
|
-
|
|
17036
|
-
// src/
|
|
17037
|
-
|
|
17038
|
-
// src/
|
|
17039
|
-
|
|
17366
|
+
path5.resolve(__dirname, "..", "templates"),
|
|
17367
|
+
// src/utils/templates-dir.ts → ../../templates (source layout)
|
|
17368
|
+
path5.resolve(__dirname, "..", "..", "templates"),
|
|
17369
|
+
// src/utils/templates-dir.ts → ../../../templates (just in case dist gets nested)
|
|
17370
|
+
path5.resolve(__dirname, "..", "..", "..", "templates")
|
|
17040
17371
|
].filter((p) => p !== null);
|
|
17041
17372
|
for (const candidate of candidates) {
|
|
17042
17373
|
if (existsSync(candidate)) return candidate;
|
|
@@ -17047,10 +17378,402 @@ function getTemplatesDir() {
|
|
|
17047
17378
|
Set RELYIO_CLI_TEMPLATES_DIR to point at the templates folder, or reinstall the CLI.`
|
|
17048
17379
|
);
|
|
17049
17380
|
}
|
|
17381
|
+
function schemaTemplateNames(templatesDir) {
|
|
17382
|
+
return readdirSync(templatesDir).filter((item) => {
|
|
17383
|
+
const fullPath = path5.join(templatesDir, item);
|
|
17384
|
+
return statSync(fullPath).isDirectory() && item !== "node_modules" && !item.startsWith(".") && existsSync(path5.join(fullPath, "schemas"));
|
|
17385
|
+
}).sort();
|
|
17386
|
+
}
|
|
17387
|
+
|
|
17388
|
+
// src/commands/init-next.ts
|
|
17389
|
+
init_config();
|
|
17390
|
+
init_manage();
|
|
17391
|
+
var NEXT_ENV = {
|
|
17392
|
+
apiKey: "RELYIO_API_KEY",
|
|
17393
|
+
previewApiKey: "RELYIO_PREVIEW_API_KEY",
|
|
17394
|
+
webhookSecret: "RELYIO_WEBHOOK_SECRET"
|
|
17395
|
+
};
|
|
17396
|
+
var REVALIDATE_PATH = "/api/relyio/revalidate";
|
|
17397
|
+
var REVALIDATION_EVENTS = [
|
|
17398
|
+
"entry.published",
|
|
17399
|
+
"entry.unpublished",
|
|
17400
|
+
"entry.deleted",
|
|
17401
|
+
"entry.archived",
|
|
17402
|
+
"entry.restored"
|
|
17403
|
+
];
|
|
17404
|
+
var WEBHOOK_ACTION_SLUG = "http-post";
|
|
17405
|
+
var ENV_FILE = ".env.local";
|
|
17406
|
+
var FRAMEWORK_DIR = path5.join("frameworks", "next");
|
|
17407
|
+
var TEMPLATE_SUFFIX = ".tmpl";
|
|
17408
|
+
var DATASET_PLACEHOLDER = "{{DATASET}}";
|
|
17409
|
+
var NEXT_CONFIG = "next.config.ts";
|
|
17410
|
+
var NEXT_CONFIG_NAMES = [
|
|
17411
|
+
"next.config.ts",
|
|
17412
|
+
"next.config.mts",
|
|
17413
|
+
"next.config.js",
|
|
17414
|
+
"next.config.mjs",
|
|
17415
|
+
"next.config.cjs"
|
|
17416
|
+
];
|
|
17417
|
+
function revalidationUrl(siteUrl) {
|
|
17418
|
+
let parsed;
|
|
17419
|
+
try {
|
|
17420
|
+
parsed = new URL(siteUrl);
|
|
17421
|
+
} catch {
|
|
17422
|
+
throw new Error(`Outbound URL is not a valid URL: ${siteUrl}`);
|
|
17423
|
+
}
|
|
17424
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
17425
|
+
throw new Error(
|
|
17426
|
+
`Outbound URL protocol "${parsed.protocol}" is not allowed (only http: and https:)`
|
|
17427
|
+
);
|
|
17428
|
+
}
|
|
17429
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
17430
|
+
if (["localhost", "broadcasthost", "ip6-localhost", "ip6-loopback"].includes(hostname) || hostname.endsWith(".localhost") || hostname.endsWith(".local")) {
|
|
17431
|
+
throw new Error(
|
|
17432
|
+
`Outbound URL hostname "${hostname}" is not allowed. The webhook is sent to your deployed site; pass its public URL as --site-url.`
|
|
17433
|
+
);
|
|
17434
|
+
}
|
|
17435
|
+
const address = hostname.replaceAll(/^\[|\]$/g, "");
|
|
17436
|
+
if (isLocalAddress(address)) {
|
|
17437
|
+
throw new Error(
|
|
17438
|
+
`Outbound URL IP "${address}" is in a private/loopback range. The webhook is sent to your deployed site; pass its public URL as --site-url.`
|
|
17439
|
+
);
|
|
17440
|
+
}
|
|
17441
|
+
const base = `${parsed.origin}${parsed.pathname.replace(/\/+$/, "")}`;
|
|
17442
|
+
return `${base}${REVALIDATE_PATH}`;
|
|
17443
|
+
}
|
|
17444
|
+
function isLocalAddress(address) {
|
|
17445
|
+
const v4 = /^(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}$/.exec(address);
|
|
17446
|
+
if (v4) {
|
|
17447
|
+
const a = Number(v4[1]);
|
|
17448
|
+
const b = Number(v4[2]);
|
|
17449
|
+
return a === 0 || a === 127 || a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 169 && b === 254;
|
|
17450
|
+
}
|
|
17451
|
+
if (!address.includes(":")) return false;
|
|
17452
|
+
return address === "::" || address === "::1" || /^f[cd][0-9a-f]{2}:/.test(address) || /^fe[89ab][0-9a-f]:/.test(address);
|
|
17453
|
+
}
|
|
17454
|
+
function assignmentOf(name) {
|
|
17455
|
+
return new RegExp(`^(\\s*(?:export\\s+)?)${name}(?:\\s*=|:\\s)(.*)$`);
|
|
17456
|
+
}
|
|
17457
|
+
function parseEnvValue(raw) {
|
|
17458
|
+
const value = raw.trim();
|
|
17459
|
+
const quote = value[0];
|
|
17460
|
+
if (quote === '"' || quote === "'" || quote === "`") {
|
|
17461
|
+
const end = value.indexOf(quote, 1);
|
|
17462
|
+
return end === -1 ? value.slice(1) : value.slice(1, end);
|
|
17463
|
+
}
|
|
17464
|
+
return (value.split("#")[0] ?? "").trim();
|
|
17465
|
+
}
|
|
17466
|
+
function readEnvValue(content, name) {
|
|
17467
|
+
if (content === null) return void 0;
|
|
17468
|
+
const pattern = assignmentOf(name);
|
|
17469
|
+
let value;
|
|
17470
|
+
for (const line of content.split(/\r?\n/)) {
|
|
17471
|
+
const match = pattern.exec(line);
|
|
17472
|
+
if (match) value = parseEnvValue(match[2] ?? "");
|
|
17473
|
+
}
|
|
17474
|
+
return value === void 0 || value === "" ? void 0 : value;
|
|
17475
|
+
}
|
|
17476
|
+
function upsertEnv(content, values) {
|
|
17477
|
+
const source = content ?? "";
|
|
17478
|
+
const eol = source.includes("\r\n") ? "\r\n" : "\n";
|
|
17479
|
+
const lines = source.split(/\r?\n/);
|
|
17480
|
+
if (lines.at(-1) === "") lines.pop();
|
|
17481
|
+
const written = [];
|
|
17482
|
+
const kept = [];
|
|
17483
|
+
for (const [name, value] of Object.entries(values)) {
|
|
17484
|
+
if (readEnvValue(source, name) !== void 0) {
|
|
17485
|
+
kept.push(name);
|
|
17486
|
+
continue;
|
|
17487
|
+
}
|
|
17488
|
+
const pattern = assignmentOf(name);
|
|
17489
|
+
let last = -1;
|
|
17490
|
+
for (const [index, line] of lines.entries()) {
|
|
17491
|
+
if (pattern.test(line)) last = index;
|
|
17492
|
+
}
|
|
17493
|
+
if (last === -1) {
|
|
17494
|
+
lines.push(`${name}=${value}`);
|
|
17495
|
+
} else {
|
|
17496
|
+
const prefix = pattern.exec(lines[last] ?? "")?.[1] ?? "";
|
|
17497
|
+
lines[last] = `${prefix}${name}=${value}`;
|
|
17498
|
+
}
|
|
17499
|
+
written.push(name);
|
|
17500
|
+
}
|
|
17501
|
+
if (written.length === 0) return { content: source, written, kept };
|
|
17502
|
+
return { content: `${lines.join(eol)}${eol}`, written, kept };
|
|
17503
|
+
}
|
|
17504
|
+
function renderNextTemplate(source, dataset) {
|
|
17505
|
+
const literal = dataset.replaceAll("\\", "\\\\").replaceAll("'", String.raw`\'`);
|
|
17506
|
+
return source.replaceAll(DATASET_PLACEHOLDER, literal);
|
|
17507
|
+
}
|
|
17508
|
+
function nextTemplateFiles(templatesDir = getTemplatesDir()) {
|
|
17509
|
+
const root = path5.join(templatesDir, FRAMEWORK_DIR);
|
|
17510
|
+
const found = [];
|
|
17511
|
+
const walk2 = (directory) => {
|
|
17512
|
+
for (const name of readdirSync(directory)) {
|
|
17513
|
+
const full = path5.join(directory, name);
|
|
17514
|
+
if (statSync(full).isDirectory()) walk2(full);
|
|
17515
|
+
else if (name.endsWith(TEMPLATE_SUFFIX)) found.push(path5.relative(root, full));
|
|
17516
|
+
}
|
|
17517
|
+
};
|
|
17518
|
+
walk2(root);
|
|
17519
|
+
return found.sort();
|
|
17520
|
+
}
|
|
17521
|
+
function writeNextScaffold(cwd, dataset, templatesDir = getTemplatesDir()) {
|
|
17522
|
+
const useSrc = existsSync(path5.join(cwd, "src", "app")) && !existsSync(path5.join(cwd, "app"));
|
|
17523
|
+
const files = [];
|
|
17524
|
+
let nextConfigToMerge;
|
|
17525
|
+
for (const template of nextTemplateFiles(templatesDir)) {
|
|
17526
|
+
const text = renderNextTemplate(
|
|
17527
|
+
readFileSync(path5.join(templatesDir, FRAMEWORK_DIR, template), "utf8"),
|
|
17528
|
+
dataset
|
|
17529
|
+
);
|
|
17530
|
+
let target = template.slice(0, -TEMPLATE_SUFFIX.length).split(path5.sep).join("/");
|
|
17531
|
+
if (target === NEXT_CONFIG) {
|
|
17532
|
+
const existing = NEXT_CONFIG_NAMES.find((name) => existsSync(path5.join(cwd, name)));
|
|
17533
|
+
if (existing !== void 0) {
|
|
17534
|
+
nextConfigToMerge = { file: existing, fragment: text };
|
|
17535
|
+
continue;
|
|
17536
|
+
}
|
|
17537
|
+
}
|
|
17538
|
+
if (useSrc && (target.startsWith("app/") || target.startsWith("lib/"))) {
|
|
17539
|
+
target = `src/${target}`;
|
|
17540
|
+
}
|
|
17541
|
+
const destination = path5.join(cwd, target);
|
|
17542
|
+
if (existsSync(destination)) {
|
|
17543
|
+
const current = readFileSync(destination, "utf8");
|
|
17544
|
+
files.push({ path: target, outcome: current === text ? "unchanged" : "kept" });
|
|
17545
|
+
continue;
|
|
17546
|
+
}
|
|
17547
|
+
mkdirSync(path5.dirname(destination), { recursive: true });
|
|
17548
|
+
writeFileSync(destination, text);
|
|
17549
|
+
files.push({ path: target, outcome: "written" });
|
|
17550
|
+
}
|
|
17551
|
+
return { files, nextConfigToMerge };
|
|
17552
|
+
}
|
|
17553
|
+
var defaultIo = () => ({
|
|
17554
|
+
cwd: process.cwd(),
|
|
17555
|
+
log: (line) => console.log(line),
|
|
17556
|
+
interactive: process.stdin.isTTY === true
|
|
17557
|
+
});
|
|
17558
|
+
function named(text, max) {
|
|
17559
|
+
return text.trim().slice(0, max);
|
|
17560
|
+
}
|
|
17561
|
+
async function runInitNext(options, io = defaultIo()) {
|
|
17562
|
+
const { cwd, log } = io;
|
|
17563
|
+
const projectId = options.project ?? config_default.getProjectId();
|
|
17564
|
+
if (projectId === void 0 || projectId === "") {
|
|
17565
|
+
throw new Error("No project. Run 'relyio link' in this directory, or pass --project <id>.");
|
|
17566
|
+
}
|
|
17567
|
+
const url = revalidationUrl(await requireSiteUrl(options.siteUrl, io.interactive));
|
|
17568
|
+
const site = new URL(url).host;
|
|
17569
|
+
const dataset = await resolveDataset(projectId, options.dataset, io.interactive);
|
|
17570
|
+
const connections = await getProjectConnections(projectId);
|
|
17571
|
+
const conflicting = connections.find(
|
|
17572
|
+
(connection) => connection.type === "webhook" && connection.config.url === url
|
|
17573
|
+
);
|
|
17574
|
+
if (conflicting !== void 0) {
|
|
17575
|
+
throw new Error(
|
|
17576
|
+
`A webhook Connection to ${url} already exists: "${conflicting.name}" (${conflicting.id}). Nothing was created. Delete it and its Automation in the dashboard, or pass another --site-url, and run again.`
|
|
17577
|
+
);
|
|
17578
|
+
}
|
|
17579
|
+
const envPath = path5.join(cwd, ENV_FILE);
|
|
17580
|
+
const envBefore = existsSync(envPath) ? readFileSync(envPath, "utf8") : null;
|
|
17581
|
+
let envNow = envBefore;
|
|
17582
|
+
const written = [];
|
|
17583
|
+
const kept = Object.values(NEXT_ENV).filter((name) => readEnvValue(envBefore, name) !== void 0);
|
|
17584
|
+
const persist = (name, value) => {
|
|
17585
|
+
const update = upsertEnv(envNow, { [name]: value });
|
|
17586
|
+
if (update.written.length === 0) return;
|
|
17587
|
+
writeFileSync(envPath, update.content, { mode: 384 });
|
|
17588
|
+
envNow = update.content;
|
|
17589
|
+
written.push(...update.written);
|
|
17590
|
+
};
|
|
17591
|
+
const created = [];
|
|
17592
|
+
try {
|
|
17593
|
+
let publishedKey;
|
|
17594
|
+
let previewKey;
|
|
17595
|
+
const signingSecret = readEnvValue(envBefore, NEXT_ENV.webhookSecret) ?? randomBytes(32).toString("hex");
|
|
17596
|
+
persist(NEXT_ENV.webhookSecret, signingSecret);
|
|
17597
|
+
if (readEnvValue(envBefore, NEXT_ENV.apiKey) === void 0) {
|
|
17598
|
+
const key = await createProjectApiKey(projectId, {
|
|
17599
|
+
name: named(`Next.js ${site} published`, 80),
|
|
17600
|
+
keyType: "production",
|
|
17601
|
+
readOnly: true,
|
|
17602
|
+
defaultDatasetId: dataset.id,
|
|
17603
|
+
allowedDatasetIds: [dataset.id]
|
|
17604
|
+
});
|
|
17605
|
+
publishedKey = { id: key.id, name: key.name };
|
|
17606
|
+
created.push(`API key "${key.name}" (${key.id})`);
|
|
17607
|
+
persist(NEXT_ENV.apiKey, requireToken(key.token, "published"));
|
|
17608
|
+
}
|
|
17609
|
+
if (readEnvValue(envBefore, NEXT_ENV.previewApiKey) === void 0) {
|
|
17610
|
+
const key = await createProjectApiKey(projectId, {
|
|
17611
|
+
name: named(`Next.js ${site} preview`, 80),
|
|
17612
|
+
keyType: "preview",
|
|
17613
|
+
previewScope: "drafts",
|
|
17614
|
+
defaultDatasetId: dataset.id,
|
|
17615
|
+
allowedDatasetIds: [dataset.id]
|
|
17616
|
+
});
|
|
17617
|
+
previewKey = { id: key.id, name: key.name };
|
|
17618
|
+
created.push(`API key "${key.name}" (${key.id})`);
|
|
17619
|
+
persist(NEXT_ENV.previewApiKey, requireToken(key.token, "preview"));
|
|
17620
|
+
}
|
|
17621
|
+
const connection = await createConnection(projectId, {
|
|
17622
|
+
name: named(`Next.js revalidation ${site}`, 100),
|
|
17623
|
+
type: "webhook",
|
|
17624
|
+
config: { url, signingSecret }
|
|
17625
|
+
});
|
|
17626
|
+
created.push(`Connection "${connection.name}" (${connection.id})`);
|
|
17627
|
+
const automation = await createAutomation(projectId, {
|
|
17628
|
+
name: named(`Revalidate ${site} on entry changes`, 100),
|
|
17629
|
+
events: [...REVALIDATION_EVENTS],
|
|
17630
|
+
connectionId: connection.id,
|
|
17631
|
+
actionSlug: WEBHOOK_ACTION_SLUG,
|
|
17632
|
+
filterDatasets: [dataset.id]
|
|
17633
|
+
});
|
|
17634
|
+
created.push(`Automation "${automation.name}" (${automation.id})`);
|
|
17635
|
+
const scaffold = writeNextScaffold(cwd, dataset.name);
|
|
17636
|
+
const result = {
|
|
17637
|
+
dataset: { id: dataset.id, name: dataset.name },
|
|
17638
|
+
publishedKey,
|
|
17639
|
+
previewKey,
|
|
17640
|
+
connection: { id: connection.id, name: connection.name, url },
|
|
17641
|
+
automation: { id: automation.id, name: automation.name },
|
|
17642
|
+
env: { written, kept },
|
|
17643
|
+
scaffold
|
|
17644
|
+
};
|
|
17645
|
+
report(result, log);
|
|
17646
|
+
return result;
|
|
17647
|
+
} catch (error2) {
|
|
17648
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
17649
|
+
const partial = created.length === 0 ? "" : `
|
|
17650
|
+
Created before the failure: ${created.join("; ")}. Keys and the secret are in ${ENV_FILE}; run again to finish.`;
|
|
17651
|
+
throw new Error(`${message}${partial}`);
|
|
17652
|
+
}
|
|
17653
|
+
}
|
|
17654
|
+
function requireToken(token, kind) {
|
|
17655
|
+
if (typeof token !== "string" || token === "") {
|
|
17656
|
+
throw new Error(`manage minted the ${kind} key but served no token for it`);
|
|
17657
|
+
}
|
|
17658
|
+
return token;
|
|
17659
|
+
}
|
|
17660
|
+
async function requireSiteUrl(siteUrl, interactive) {
|
|
17661
|
+
if (siteUrl !== void 0) return siteUrl;
|
|
17662
|
+
if (!interactive) {
|
|
17663
|
+
throw new Error(
|
|
17664
|
+
"Pass --site-url <url>: your deployed site's URL, which the revalidation webhook targets."
|
|
17665
|
+
);
|
|
17666
|
+
}
|
|
17667
|
+
const { answer } = await inquirer2.prompt([
|
|
17668
|
+
{
|
|
17669
|
+
type: "input",
|
|
17670
|
+
name: "answer",
|
|
17671
|
+
message: "Your deployed site's URL (the revalidation webhook targets it):",
|
|
17672
|
+
validate: (input) => {
|
|
17673
|
+
try {
|
|
17674
|
+
revalidationUrl(input);
|
|
17675
|
+
return true;
|
|
17676
|
+
} catch (error2) {
|
|
17677
|
+
return error2.message;
|
|
17678
|
+
}
|
|
17679
|
+
}
|
|
17680
|
+
}
|
|
17681
|
+
]);
|
|
17682
|
+
return answer;
|
|
17683
|
+
}
|
|
17684
|
+
async function resolveDataset(projectId, name, interactive) {
|
|
17685
|
+
if (name !== void 0) {
|
|
17686
|
+
const found = await getProjectDatasets(projectId, { q: name });
|
|
17687
|
+
const match = found.find((d) => d.name === name);
|
|
17688
|
+
if (match === void 0) {
|
|
17689
|
+
throw new Error(
|
|
17690
|
+
`No dataset named "${name}" in project ${projectId}. Run without --dataset to pick one.`
|
|
17691
|
+
);
|
|
17692
|
+
}
|
|
17693
|
+
return match;
|
|
17694
|
+
}
|
|
17695
|
+
const datasets = await getProjectDatasets(projectId);
|
|
17696
|
+
const names = datasets.map((d) => d.name).join(", ");
|
|
17697
|
+
if (!interactive) {
|
|
17698
|
+
throw new Error(`Pass --dataset <name>. This project's datasets: ${names}`);
|
|
17699
|
+
}
|
|
17700
|
+
const { answer } = await inquirer2.prompt([
|
|
17701
|
+
{
|
|
17702
|
+
type: "list",
|
|
17703
|
+
name: "answer",
|
|
17704
|
+
message: "Dataset the site reads:",
|
|
17705
|
+
choices: datasets.map((d) => ({ name: d.name, value: d.id })),
|
|
17706
|
+
default: datasets.find((d) => d.isDefault)?.id
|
|
17707
|
+
}
|
|
17708
|
+
]);
|
|
17709
|
+
const chosen = datasets.find((d) => d.id === answer);
|
|
17710
|
+
if (chosen === void 0) throw new Error(`No dataset with id ${answer}`);
|
|
17711
|
+
return chosen;
|
|
17712
|
+
}
|
|
17713
|
+
function report(result, log) {
|
|
17714
|
+
const row = (label, value) => log(` ${label.padEnd(15)}${value}`);
|
|
17715
|
+
const kept = (name) => `kept the ${name} already in ${ENV_FILE}; none minted`;
|
|
17716
|
+
log(success("Provisioned RelyIO for this Next.js app"));
|
|
17717
|
+
row("Dataset", `${result.dataset.name} (${result.dataset.id})`);
|
|
17718
|
+
row(
|
|
17719
|
+
"Published key",
|
|
17720
|
+
result.publishedKey ? `${result.publishedKey.name} (${result.publishedKey.id})` : kept(NEXT_ENV.apiKey)
|
|
17721
|
+
);
|
|
17722
|
+
row(
|
|
17723
|
+
"Preview key",
|
|
17724
|
+
result.previewKey ? `${result.previewKey.name} (${result.previewKey.id})` : kept(NEXT_ENV.previewApiKey)
|
|
17725
|
+
);
|
|
17726
|
+
row(
|
|
17727
|
+
"Connection",
|
|
17728
|
+
`${result.connection.name} (${result.connection.id}) \u2192 ${result.connection.url}`
|
|
17729
|
+
);
|
|
17730
|
+
row("Automation", `${result.automation.name} (${result.automation.id})`);
|
|
17731
|
+
row(
|
|
17732
|
+
ENV_FILE,
|
|
17733
|
+
[
|
|
17734
|
+
result.env.written.length > 0 ? `wrote ${result.env.written.join(", ")}` : "",
|
|
17735
|
+
result.env.kept.length > 0 ? `kept ${result.env.kept.join(", ")}` : ""
|
|
17736
|
+
].filter(Boolean).join("; ")
|
|
17737
|
+
);
|
|
17738
|
+
for (const file of result.scaffold.files) {
|
|
17739
|
+
row(file.outcome, file.outcome === "kept" ? `${file.path} (differs; left as is)` : file.path);
|
|
17740
|
+
}
|
|
17741
|
+
if (result.scaffold.nextConfigToMerge) {
|
|
17742
|
+
log(
|
|
17743
|
+
warning(
|
|
17744
|
+
`${result.scaffold.nextConfigToMerge.file} exists and was not edited. Merge its images block:`
|
|
17745
|
+
)
|
|
17746
|
+
);
|
|
17747
|
+
log(result.scaffold.nextConfigToMerge.fragment);
|
|
17748
|
+
}
|
|
17749
|
+
log(
|
|
17750
|
+
info(
|
|
17751
|
+
`Set ${Object.values(NEXT_ENV).join(", ")} in your host's environment too: the webhook reaches the deployed site, which does not read ${ENV_FILE}.`
|
|
17752
|
+
)
|
|
17753
|
+
);
|
|
17754
|
+
}
|
|
17755
|
+
|
|
17756
|
+
// src/commands/init.ts
|
|
17757
|
+
var FRAMEWORK_TEMPLATES = ["next"];
|
|
17050
17758
|
async function handleInit(options) {
|
|
17759
|
+
if (options.template !== void 0) {
|
|
17760
|
+
if (options.example !== void 0) {
|
|
17761
|
+
throw new Error(
|
|
17762
|
+
"--template scaffolds a framework app and --example picks a schema template; pass one."
|
|
17763
|
+
);
|
|
17764
|
+
}
|
|
17765
|
+
if (options.template !== "next") {
|
|
17766
|
+
throw new Error(
|
|
17767
|
+
`Unknown --template '${options.template}'. Available: ${FRAMEWORK_TEMPLATES.join(", ")}`
|
|
17768
|
+
);
|
|
17769
|
+
}
|
|
17770
|
+
await requireAuth();
|
|
17771
|
+
await runInitNext(options);
|
|
17772
|
+
return;
|
|
17773
|
+
}
|
|
17051
17774
|
console.log(heading("Initialize a new RelyIO project"));
|
|
17052
17775
|
if (config_default.isProjectInitialized()) {
|
|
17053
|
-
const { shouldReinitialize } = await
|
|
17776
|
+
const { shouldReinitialize } = await inquirer2.prompt([
|
|
17054
17777
|
{
|
|
17055
17778
|
type: "confirm",
|
|
17056
17779
|
name: "shouldReinitialize",
|
|
@@ -17084,7 +17807,7 @@ async function handleInit(options) {
|
|
|
17084
17807
|
}
|
|
17085
17808
|
}
|
|
17086
17809
|
async function collectProjectInfo(options) {
|
|
17087
|
-
const { directory } = await
|
|
17810
|
+
const { directory } = await inquirer2.prompt([
|
|
17088
17811
|
{
|
|
17089
17812
|
type: "input",
|
|
17090
17813
|
name: "directory",
|
|
@@ -17092,7 +17815,7 @@ async function collectProjectInfo(options) {
|
|
|
17092
17815
|
default: process.cwd()
|
|
17093
17816
|
}
|
|
17094
17817
|
]);
|
|
17095
|
-
const { projectName } = await
|
|
17818
|
+
const { projectName } = await inquirer2.prompt([
|
|
17096
17819
|
{
|
|
17097
17820
|
type: "input",
|
|
17098
17821
|
name: "projectName",
|
|
@@ -17106,12 +17829,7 @@ async function collectProjectInfo(options) {
|
|
|
17106
17829
|
console.error(error(`Templates directory not found at: ${templatesDir}`));
|
|
17107
17830
|
process.exit(1);
|
|
17108
17831
|
}
|
|
17109
|
-
const
|
|
17110
|
-
const templates = dirContents.filter((item) => {
|
|
17111
|
-
const fullPath = path3.join(templatesDir, item);
|
|
17112
|
-
const stats = statSync(fullPath);
|
|
17113
|
-
return stats.isDirectory() && item !== "node_modules" && !item.startsWith(".");
|
|
17114
|
-
}).map((template) => {
|
|
17832
|
+
const templates = schemaTemplateNames(templatesDir).map((template) => {
|
|
17115
17833
|
const description = (() => {
|
|
17116
17834
|
switch (template) {
|
|
17117
17835
|
case "bare": {
|
|
@@ -17139,7 +17857,7 @@ async function collectProjectInfo(options) {
|
|
|
17139
17857
|
}
|
|
17140
17858
|
console.log(heading("\nSelect a template for your project"));
|
|
17141
17859
|
console.log(info("Use \u2191 and \u2193 arrow keys to select, then press Enter\n"));
|
|
17142
|
-
const { selectedExample } = await
|
|
17860
|
+
const { selectedExample } = await inquirer2.prompt([
|
|
17143
17861
|
{
|
|
17144
17862
|
type: "list",
|
|
17145
17863
|
name: "selectedExample",
|
|
@@ -17164,7 +17882,7 @@ async function collectProjectInfo(options) {
|
|
|
17164
17882
|
try {
|
|
17165
17883
|
existingProjects = await getProjects();
|
|
17166
17884
|
if (existingProjects.length > 0) {
|
|
17167
|
-
const { linkType } = await
|
|
17885
|
+
const { linkType } = await inquirer2.prompt([
|
|
17168
17886
|
{
|
|
17169
17887
|
type: "list",
|
|
17170
17888
|
name: "linkType",
|
|
@@ -17178,7 +17896,7 @@ async function collectProjectInfo(options) {
|
|
|
17178
17896
|
]);
|
|
17179
17897
|
if (linkType === "existing") {
|
|
17180
17898
|
createProject = false;
|
|
17181
|
-
const { selectedProject } = await
|
|
17899
|
+
const { selectedProject } = await inquirer2.prompt([
|
|
17182
17900
|
{
|
|
17183
17901
|
type: "list",
|
|
17184
17902
|
name: "selectedProject",
|
|
@@ -17213,12 +17931,12 @@ async function collectProjectInfo(options) {
|
|
|
17213
17931
|
}
|
|
17214
17932
|
function createProjectStructure(context) {
|
|
17215
17933
|
const { directory, example = "bare" } = context;
|
|
17216
|
-
const relyioDir =
|
|
17934
|
+
const relyioDir = path5.resolve(directory, "relyio");
|
|
17217
17935
|
if (!existsSync(relyioDir)) {
|
|
17218
17936
|
mkdirSync(relyioDir, { recursive: true });
|
|
17219
17937
|
}
|
|
17220
17938
|
const templatesDir = getTemplatesDir();
|
|
17221
|
-
const templateDir =
|
|
17939
|
+
const templateDir = path5.resolve(templatesDir, example);
|
|
17222
17940
|
if (!existsSync(templateDir)) {
|
|
17223
17941
|
throw new Error(
|
|
17224
17942
|
`Template '${example}' not found. Available templates: ${existsSync(templatesDir) ? readdirSync(templatesDir).join(", ") : "none"}`
|
|
@@ -17231,7 +17949,7 @@ function createProjectStructure(context) {
|
|
|
17231
17949
|
if (isDirectory) {
|
|
17232
17950
|
if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
|
|
17233
17951
|
for (const childItemName of readdirSync(src)) {
|
|
17234
|
-
copyRecursive(
|
|
17952
|
+
copyRecursive(path5.join(src, childItemName), path5.join(dest, childItemName));
|
|
17235
17953
|
}
|
|
17236
17954
|
} else {
|
|
17237
17955
|
cpSync(src, dest);
|
|
@@ -17247,7 +17965,13 @@ function initCommand(program2) {
|
|
|
17247
17965
|
(options) => handleInit(options),
|
|
17248
17966
|
false
|
|
17249
17967
|
// Don't require auth for init command
|
|
17250
|
-
).option("--example <type>", "Initialize with an example template (bare or blog)")
|
|
17968
|
+
).option("--example <type>", "Initialize with an example template (bare or blog)").option(
|
|
17969
|
+
"--template <framework>",
|
|
17970
|
+
"Scaffold a framework app and provision its keys, webhook and env file (next)"
|
|
17971
|
+
).option(
|
|
17972
|
+
"--site-url <url>",
|
|
17973
|
+
"With --template next: your deployed site's URL; the revalidation webhook targets it"
|
|
17974
|
+
).option("--dataset <name>", "With --template next: the dataset the site reads").option("--project <id>", "With --template next: the project id (default: the linked project)");
|
|
17251
17975
|
}
|
|
17252
17976
|
init_config();
|
|
17253
17977
|
async function handleLogin(options) {
|
|
@@ -17273,7 +17997,7 @@ async function handleLogin(options) {
|
|
|
17273
17997
|
try {
|
|
17274
17998
|
const user = await auth_default.getCurrentUser();
|
|
17275
17999
|
console.log(warning(`You are already logged in as ${colors.highlight(user.email)}`));
|
|
17276
|
-
const { shouldLogout } = await
|
|
18000
|
+
const { shouldLogout } = await inquirer2.prompt([
|
|
17277
18001
|
{
|
|
17278
18002
|
type: "confirm",
|
|
17279
18003
|
name: "shouldLogout",
|
|
@@ -18583,60 +19307,51 @@ async function pollTaskUntilDone(projectId, taskId, options = {}) {
|
|
|
18583
19307
|
|
|
18584
19308
|
// src/commands/promote.ts
|
|
18585
19309
|
init_config();
|
|
18586
|
-
|
|
18587
|
-
|
|
18588
|
-
|
|
19310
|
+
|
|
19311
|
+
// src/dev/dev-context.ts
|
|
19312
|
+
init_dist();
|
|
19313
|
+
init_dev_handshake();
|
|
18589
19314
|
function devContextPath(projectRoot) {
|
|
18590
|
-
return
|
|
19315
|
+
return path5.join(projectRoot, DEV_CONTEXT_FILE);
|
|
18591
19316
|
}
|
|
18592
19317
|
async function writeDevContext(projectRoot, context) {
|
|
18593
|
-
|
|
18594
|
-
await writeFile(devContextPath(projectRoot), `${JSON.stringify(context, null, 2)}
|
|
18595
|
-
`, "utf8");
|
|
19318
|
+
writeSecretFile(devContextPath(projectRoot), context);
|
|
18596
19319
|
await ensureGitignore(projectRoot);
|
|
18597
19320
|
}
|
|
18598
19321
|
async function readDevContext(projectRoot) {
|
|
19322
|
+
let raw;
|
|
18599
19323
|
try {
|
|
18600
|
-
|
|
18601
|
-
const parsed = JSON.parse(raw);
|
|
18602
|
-
if (typeof parsed.datasetId === "string" && typeof parsed.previewApiKey === "string" && typeof parsed.branchId === "string") {
|
|
18603
|
-
return {
|
|
18604
|
-
datasetId: parsed.datasetId,
|
|
18605
|
-
previewApiKey: parsed.previewApiKey,
|
|
18606
|
-
branchId: parsed.branchId,
|
|
18607
|
-
expiresAt: typeof parsed.expiresAt === "string" ? parsed.expiresAt : null
|
|
18608
|
-
};
|
|
18609
|
-
}
|
|
18610
|
-
return null;
|
|
19324
|
+
raw = await readFile(devContextPath(projectRoot), "utf8");
|
|
18611
19325
|
} catch {
|
|
18612
|
-
return
|
|
19326
|
+
return { state: "absent" };
|
|
18613
19327
|
}
|
|
19328
|
+
return parseDevContextFile(raw, Date.now());
|
|
18614
19329
|
}
|
|
18615
19330
|
async function clearDevContext(projectRoot) {
|
|
18616
19331
|
await rm(devContextPath(projectRoot), { force: true }).catch(() => {
|
|
18617
19332
|
});
|
|
18618
19333
|
}
|
|
18619
19334
|
async function ensureGitignore(projectRoot) {
|
|
18620
|
-
const gitignorePath =
|
|
19335
|
+
const gitignorePath = path5.join(projectRoot, ".gitignore");
|
|
18621
19336
|
if (!existsSync(gitignorePath)) {
|
|
18622
19337
|
await writeFile(
|
|
18623
19338
|
gitignorePath,
|
|
18624
19339
|
`# RelyIO sandbox dev artifact (contains a scoped preview key \u2014 never commit)
|
|
18625
|
-
${
|
|
19340
|
+
${DEV_CONTEXT_FILE}
|
|
18626
19341
|
`,
|
|
18627
19342
|
"utf8"
|
|
18628
19343
|
);
|
|
18629
19344
|
return;
|
|
18630
19345
|
}
|
|
18631
19346
|
const current = await readFile(gitignorePath, "utf8");
|
|
18632
|
-
const alreadyIgnored = current.split(/\r?\n/).map((line) => line.trim()).some((line) => line ===
|
|
19347
|
+
const alreadyIgnored = current.split(/\r?\n/).map((line) => line.trim()).some((line) => line === DEV_CONTEXT_FILE || line === `/${DEV_CONTEXT_FILE}`);
|
|
18633
19348
|
if (alreadyIgnored) return;
|
|
18634
19349
|
const prefix = current.endsWith("\n") || current.length === 0 ? "" : "\n";
|
|
18635
19350
|
await writeFile(
|
|
18636
19351
|
gitignorePath,
|
|
18637
19352
|
`${current}${prefix}
|
|
18638
19353
|
# RelyIO sandbox dev artifact (contains a scoped preview key \u2014 never commit)
|
|
18639
|
-
${
|
|
19354
|
+
${DEV_CONTEXT_FILE}
|
|
18640
19355
|
`,
|
|
18641
19356
|
"utf8"
|
|
18642
19357
|
);
|
|
@@ -18653,12 +19368,13 @@ function requireProjectId() {
|
|
|
18653
19368
|
return projectId;
|
|
18654
19369
|
}
|
|
18655
19370
|
async function resolveActiveSandbox(projectId) {
|
|
19371
|
+
const artifact = await readDevContext(process.cwd());
|
|
18656
19372
|
const sandboxes = await sandbox_default.listSandboxes(projectId);
|
|
18657
|
-
if (sandboxes.length === 0) return null;
|
|
18658
|
-
|
|
18659
|
-
if (
|
|
18660
|
-
const byArtifact = sandboxes.find((s) => s.branch.id ===
|
|
18661
|
-
if (byArtifact) return byArtifact;
|
|
19373
|
+
if (sandboxes.length === 0) return { sandbox: null, artifact };
|
|
19374
|
+
if (artifact.state === "expired") return { sandbox: null, artifact };
|
|
19375
|
+
if (artifact.state === "active") {
|
|
19376
|
+
const byArtifact = sandboxes.find((s) => s.branch.id === artifact.context.branchId);
|
|
19377
|
+
if (byArtifact) return { sandbox: byArtifact, artifact };
|
|
18662
19378
|
}
|
|
18663
19379
|
const gitBranch = getCurrentGitBranch();
|
|
18664
19380
|
if (gitBranch) {
|
|
@@ -18667,12 +19383,25 @@ async function resolveActiveSandbox(projectId) {
|
|
|
18667
19383
|
const parent = branches.find((b) => b.name === gitBranch);
|
|
18668
19384
|
if (parent) {
|
|
18669
19385
|
const byParent = sandboxes.find((s) => s.branch.parentBranchId === parent.id);
|
|
18670
|
-
if (byParent) return byParent;
|
|
19386
|
+
if (byParent) return { sandbox: byParent, artifact };
|
|
18671
19387
|
}
|
|
18672
19388
|
} catch {
|
|
18673
19389
|
}
|
|
18674
19390
|
}
|
|
18675
|
-
return sandboxes.length === 1 ? sandboxes[0] : null;
|
|
19391
|
+
return { sandbox: sandboxes.length === 1 ? sandboxes[0] : null, artifact };
|
|
19392
|
+
}
|
|
19393
|
+
function reportArtifact(artifact) {
|
|
19394
|
+
if (artifact.state === "expired") {
|
|
19395
|
+
displayWarning(
|
|
19396
|
+
`Your sandbox's local dev artifact expired at ${artifact.expiredAt}.`,
|
|
19397
|
+
"It can no longer identify which sandbox to promote, and guessing from your git branch could promote a different one. Run `relyio dev` to refresh it, then promote."
|
|
19398
|
+
);
|
|
19399
|
+
} else if (artifact.state === "unreadable") {
|
|
19400
|
+
displayWarning(
|
|
19401
|
+
`Your \`.relyio/dev.json\` could not be read (${artifact.reason}).`,
|
|
19402
|
+
"Your app is not reading the sandbox. Delete the file and run `relyio dev` to rewrite it."
|
|
19403
|
+
);
|
|
19404
|
+
}
|
|
18676
19405
|
}
|
|
18677
19406
|
async function resolveTargetBranch(projectId, requested, defaultParentBranchId) {
|
|
18678
19407
|
const branches = await manage_default.getProjectBranches(projectId);
|
|
@@ -18693,14 +19422,16 @@ async function handlePromote(options) {
|
|
|
18693
19422
|
displayHeader("RelyIO Promote", "Flush your sandbox into a real branch");
|
|
18694
19423
|
const projectId = requireProjectId();
|
|
18695
19424
|
const spinner2 = createSpinner("Resolving your active sandbox...");
|
|
18696
|
-
const sandbox = await resolveActiveSandbox(projectId);
|
|
19425
|
+
const { sandbox, artifact } = await resolveActiveSandbox(projectId);
|
|
18697
19426
|
if (!sandbox) {
|
|
18698
19427
|
spinner2.fail("No active sandbox found");
|
|
19428
|
+
reportArtifact(artifact);
|
|
18699
19429
|
displayInfo("Start one with `relyio dev`, then run `relyio promote` again.");
|
|
18700
19430
|
process.exit(1);
|
|
18701
19431
|
return;
|
|
18702
19432
|
}
|
|
18703
19433
|
spinner2.succeed(`Sandbox: ${sandbox.branch.name}`);
|
|
19434
|
+
reportArtifact(artifact);
|
|
18704
19435
|
const target = await resolveTargetBranch(projectId, options.branch, sandbox.branch.parentBranchId);
|
|
18705
19436
|
if (!target) {
|
|
18706
19437
|
displayError(
|
|
@@ -18815,7 +19546,8 @@ async function offerPromoteWhenSandboxActive() {
|
|
|
18815
19546
|
if (!projectId) return false;
|
|
18816
19547
|
let sandbox;
|
|
18817
19548
|
try {
|
|
18818
|
-
|
|
19549
|
+
;
|
|
19550
|
+
({ sandbox } = await resolveActiveSandbox(projectId));
|
|
18819
19551
|
} catch {
|
|
18820
19552
|
return false;
|
|
18821
19553
|
}
|
|
@@ -18988,7 +19720,7 @@ async function handleDeploy(options) {
|
|
|
18988
19720
|
let notes;
|
|
18989
19721
|
if (!json && !options.yes) {
|
|
18990
19722
|
console.log();
|
|
18991
|
-
const { confirmed } = await
|
|
19723
|
+
const { confirmed } = await inquirer2.prompt([
|
|
18992
19724
|
{
|
|
18993
19725
|
type: "confirm",
|
|
18994
19726
|
name: "confirmed",
|
|
@@ -19001,7 +19733,7 @@ async function handleDeploy(options) {
|
|
|
19001
19733
|
return;
|
|
19002
19734
|
}
|
|
19003
19735
|
if (!options.skipNotes) {
|
|
19004
|
-
const answer = await
|
|
19736
|
+
const answer = await inquirer2.prompt([
|
|
19005
19737
|
{
|
|
19006
19738
|
type: "input",
|
|
19007
19739
|
name: "notes",
|
|
@@ -19708,7 +20440,7 @@ function sandboxCommands(program2) {
|
|
|
19708
20440
|
}
|
|
19709
20441
|
|
|
19710
20442
|
// src/commands/version.ts
|
|
19711
|
-
var CLI_VERSION = "0.
|
|
20443
|
+
var CLI_VERSION = "0.3.0" ;
|
|
19712
20444
|
async function handleVersion(_options) {
|
|
19713
20445
|
console.log(heading("RelyIO CLI Version Information"));
|
|
19714
20446
|
const versionInfo = [
|
|
@@ -19791,13 +20523,13 @@ var TerminalWatcher = class extends EventEmitter {
|
|
|
19791
20523
|
ignoreInitial: true,
|
|
19792
20524
|
persistent: true
|
|
19793
20525
|
});
|
|
19794
|
-
this.watcher.on("raw", (event,
|
|
20526
|
+
this.watcher.on("raw", (event, path25) => {
|
|
19795
20527
|
if (event === "change" || event === "rename") {
|
|
19796
|
-
return this.handleFileChange(
|
|
20528
|
+
return this.handleFileChange(path25);
|
|
19797
20529
|
}
|
|
19798
20530
|
});
|
|
19799
|
-
this.watcher.on("add", (
|
|
19800
|
-
this.watcher.on("unlink", (
|
|
20531
|
+
this.watcher.on("add", (path25) => this.handleFileChange(path25));
|
|
20532
|
+
this.watcher.on("unlink", (path25) => this.handleFileChange(path25));
|
|
19801
20533
|
this.watcher.on("error", (error2) => {
|
|
19802
20534
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
19803
20535
|
if (this.options.onError && error2 instanceof Error) {
|
|
@@ -20481,7 +21213,7 @@ async function handleLink(options) {
|
|
|
20481
21213
|
console.log(info("Please create an organization from the dashboard."));
|
|
20482
21214
|
process.exit(1);
|
|
20483
21215
|
}
|
|
20484
|
-
const { organizationId } = await
|
|
21216
|
+
const { organizationId } = await inquirer2.prompt([
|
|
20485
21217
|
{
|
|
20486
21218
|
type: "list",
|
|
20487
21219
|
name: "organizationId",
|
|
@@ -20501,7 +21233,7 @@ async function handleLink(options) {
|
|
|
20501
21233
|
console.log(info("Please create a project first."));
|
|
20502
21234
|
process.exit(1);
|
|
20503
21235
|
}
|
|
20504
|
-
const { projectId } = await
|
|
21236
|
+
const { projectId } = await inquirer2.prompt([
|
|
20505
21237
|
{
|
|
20506
21238
|
type: "list",
|
|
20507
21239
|
name: "projectId",
|
|
@@ -20551,172 +21283,13 @@ init_schema_loader();
|
|
|
20551
21283
|
init_schema();
|
|
20552
21284
|
init_manage();
|
|
20553
21285
|
init_manage_error();
|
|
20554
|
-
|
|
20555
|
-
var registeredPlugins = /* @__PURE__ */ new Map();
|
|
20556
|
-
function registerPlugin(language, load3) {
|
|
20557
|
-
registeredPlugins.set(language, load3);
|
|
20558
|
-
}
|
|
20559
|
-
function asPlugin(module_, describe3) {
|
|
20560
|
-
const candidate = module_?.default ?? module_;
|
|
20561
|
-
const plugin3 = candidate;
|
|
20562
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20563
|
-
throw new Error(`Invalid plugin: ${describe3}`);
|
|
20564
|
-
}
|
|
20565
|
-
return plugin3;
|
|
20566
|
-
}
|
|
20567
|
-
async function loadPlugin(language) {
|
|
20568
|
-
const registered = registeredPlugins.get(language);
|
|
20569
|
-
if (registered) {
|
|
20570
|
-
return asPlugin(await registered(), `registered ${language}`);
|
|
20571
|
-
}
|
|
20572
|
-
if (language === "typescript" || language === "python") {
|
|
20573
|
-
try {
|
|
20574
|
-
const pluginName2 = `@relyio/codegen-${language}`;
|
|
20575
|
-
const pluginModule = await import(
|
|
20576
|
-
/* webpackIgnore: true */
|
|
20577
|
-
pluginName2
|
|
20578
|
-
);
|
|
20579
|
-
const plugin3 = pluginModule.default || pluginModule;
|
|
20580
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20581
|
-
throw new Error(`Invalid built-in plugin: ${language}`);
|
|
20582
|
-
}
|
|
20583
|
-
return plugin3;
|
|
20584
|
-
} catch {
|
|
20585
|
-
try {
|
|
20586
|
-
const relativePath = path3.resolve(
|
|
20587
|
-
path3.dirname(import.meta.url.replace("file://", "")),
|
|
20588
|
-
`../../codegen-${language}/dist/index.js`
|
|
20589
|
-
);
|
|
20590
|
-
const pluginModule = await import(
|
|
20591
|
-
/* webpackIgnore: true */
|
|
20592
|
-
relativePath
|
|
20593
|
-
);
|
|
20594
|
-
const plugin3 = pluginModule.default || pluginModule;
|
|
20595
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20596
|
-
throw new Error(`Invalid built-in plugin: ${language}`);
|
|
20597
|
-
}
|
|
20598
|
-
return plugin3;
|
|
20599
|
-
} catch {
|
|
20600
|
-
throw new Error(
|
|
20601
|
-
`Built-in ${language} generator not found. Please ensure @relyio/codegen-${language} is built.`
|
|
20602
|
-
);
|
|
20603
|
-
}
|
|
20604
|
-
}
|
|
20605
|
-
}
|
|
20606
|
-
const pluginName = `@relyio/codegen-${language}`;
|
|
20607
|
-
try {
|
|
20608
|
-
const pluginModule = await import(
|
|
20609
|
-
/* webpackIgnore: true */
|
|
20610
|
-
pluginName
|
|
20611
|
-
);
|
|
20612
|
-
const plugin3 = pluginModule.default || pluginModule;
|
|
20613
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20614
|
-
throw new Error(`Invalid plugin: ${pluginName}`);
|
|
20615
|
-
}
|
|
20616
|
-
return plugin3;
|
|
20617
|
-
} catch (error2) {
|
|
20618
|
-
const code = error2 !== null && typeof error2 === "object" && "code" in error2 ? String(error2.code) : void 0;
|
|
20619
|
-
if (code === "MODULE_NOT_FOUND") {
|
|
20620
|
-
throw new Error(`Generator "${language}" not installed.
|
|
20621
|
-
Run: pnpm add -D ${pluginName}`);
|
|
20622
|
-
}
|
|
20623
|
-
throw error2;
|
|
20624
|
-
}
|
|
20625
|
-
}
|
|
20626
|
-
async function getAvailablePlugins() {
|
|
20627
|
-
try {
|
|
20628
|
-
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
20629
|
-
const packageJsonModule = await import(packageJsonPath);
|
|
20630
|
-
const packageJson = packageJsonModule.default;
|
|
20631
|
-
const dependencies = {
|
|
20632
|
-
...packageJson.dependencies,
|
|
20633
|
-
...packageJson.devDependencies
|
|
20634
|
-
};
|
|
20635
|
-
const plugins = Object.keys(dependencies).filter((name) => name.startsWith("@relyio/codegen-")).map((name) => name.replace("@relyio/codegen-", ""));
|
|
20636
|
-
if (!plugins.includes("typescript")) {
|
|
20637
|
-
plugins.unshift("typescript");
|
|
20638
|
-
}
|
|
20639
|
-
if (!plugins.includes("python")) {
|
|
20640
|
-
plugins.unshift("python");
|
|
20641
|
-
}
|
|
20642
|
-
return plugins;
|
|
20643
|
-
} catch {
|
|
20644
|
-
return ["typescript", "python"];
|
|
20645
|
-
}
|
|
20646
|
-
}
|
|
20647
|
-
function getSuggestedPlugins() {
|
|
20648
|
-
return {
|
|
20649
|
-
python: "@relyio/codegen-python",
|
|
20650
|
-
go: "@relyio/codegen-go",
|
|
20651
|
-
rust: "@relyio/codegen-rust",
|
|
20652
|
-
java: "@relyio/codegen-java",
|
|
20653
|
-
csharp: "@relyio/codegen-csharp",
|
|
20654
|
-
php: "@relyio/codegen-php",
|
|
20655
|
-
swift: "@relyio/codegen-swift",
|
|
20656
|
-
kotlin: "@relyio/codegen-kotlin"
|
|
20657
|
-
};
|
|
20658
|
-
}
|
|
20659
|
-
async function writeFiles(files, outputDir) {
|
|
20660
|
-
await fs4.mkdir(outputDir, { recursive: true });
|
|
20661
|
-
await Promise.all(
|
|
20662
|
-
files.map(async (file) => {
|
|
20663
|
-
const fullPath = path3.join(outputDir, file.path);
|
|
20664
|
-
const dir = path3.dirname(fullPath);
|
|
20665
|
-
await fs4.mkdir(dir, { recursive: true });
|
|
20666
|
-
await fs4.writeFile(fullPath, file.content, "utf8");
|
|
20667
|
-
})
|
|
20668
|
-
);
|
|
20669
|
-
}
|
|
20670
|
-
var TemplateEngine = class {
|
|
20671
|
-
handlebars;
|
|
20672
|
-
constructor() {
|
|
20673
|
-
this.handlebars = Handlebars.create();
|
|
20674
|
-
this.registerHelpers();
|
|
20675
|
-
}
|
|
20676
|
-
registerHelpers() {
|
|
20677
|
-
this.handlebars.registerHelper("pascalCase", (str) => {
|
|
20678
|
-
if (!str) return "";
|
|
20679
|
-
return str.replaceAll(/(^|_)(\w)/g, (_, __, char) => char.toUpperCase());
|
|
20680
|
-
});
|
|
20681
|
-
this.handlebars.registerHelper("camelCase", (str) => {
|
|
20682
|
-
if (!str) return "";
|
|
20683
|
-
const pascal = str.replaceAll(/(^|_)(\w)/g, (_, __, char) => char.toUpperCase());
|
|
20684
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
20685
|
-
});
|
|
20686
|
-
this.handlebars.registerHelper("snakeCase", (str) => {
|
|
20687
|
-
if (!str) return "";
|
|
20688
|
-
return str.replaceAll(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
20689
|
-
});
|
|
20690
|
-
this.handlebars.registerHelper("kebabCase", (str) => {
|
|
20691
|
-
if (!str) return "";
|
|
20692
|
-
return str.replaceAll(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
20693
|
-
});
|
|
20694
|
-
this.handlebars.registerHelper("plural", (str) => {
|
|
20695
|
-
if (!str) return "";
|
|
20696
|
-
if (str.endsWith("y")) {
|
|
20697
|
-
return str.slice(0, -1) + "ies";
|
|
20698
|
-
}
|
|
20699
|
-
if (str.endsWith("s") || str.endsWith("sh") || str.endsWith("ch")) {
|
|
20700
|
-
return str + "es";
|
|
20701
|
-
}
|
|
20702
|
-
return str + "s";
|
|
20703
|
-
});
|
|
20704
|
-
}
|
|
20705
|
-
compile(template) {
|
|
20706
|
-
const compiledTemplate = this.handlebars.compile(template);
|
|
20707
|
-
return (context) => compiledTemplate(context);
|
|
20708
|
-
}
|
|
20709
|
-
render(template, context) {
|
|
20710
|
-
const compiledTemplate = this.compile(template);
|
|
20711
|
-
return compiledTemplate(context);
|
|
20712
|
-
}
|
|
20713
|
-
};
|
|
20714
|
-
new TemplateEngine();
|
|
21286
|
+
init_dist2();
|
|
20715
21287
|
|
|
20716
21288
|
// src/codegen/built-in-generators.ts
|
|
21289
|
+
init_dist2();
|
|
20717
21290
|
var BUILT_IN_GENERATOR_LOADERS = Object.freeze({
|
|
20718
|
-
typescript: () => Promise.resolve().then(() => (
|
|
20719
|
-
python: () => Promise.resolve().then(() => (
|
|
21291
|
+
typescript: () => Promise.resolve().then(() => (init_dist4(), dist_exports)),
|
|
21292
|
+
python: () => Promise.resolve().then(() => (init_dist5(), dist_exports2))
|
|
20720
21293
|
});
|
|
20721
21294
|
function registerBuiltInGenerators() {
|
|
20722
21295
|
for (const language of BUILT_IN_LANGUAGES) {
|
|
@@ -20727,6 +21300,9 @@ registerBuiltInGenerators();
|
|
|
20727
21300
|
|
|
20728
21301
|
// src/commands/generate-types.ts
|
|
20729
21302
|
init_git();
|
|
21303
|
+
|
|
21304
|
+
// src/utils/codegen-config.ts
|
|
21305
|
+
init_dist2();
|
|
20730
21306
|
var CodegenConfigSchema = z.object({
|
|
20731
21307
|
output: z.string().optional(),
|
|
20732
21308
|
languages: z.array(z.string()).optional(),
|
|
@@ -20741,16 +21317,11 @@ var CodegenConfigSchema = z.object({
|
|
|
20741
21317
|
output: z.string().optional(),
|
|
20742
21318
|
baseModel: z.enum(["pydantic", "dataclass"]).optional(),
|
|
20743
21319
|
includeValidators: z.boolean().optional()
|
|
20744
|
-
}).optional(),
|
|
20745
|
-
go: z.object({
|
|
20746
|
-
output: z.string().optional(),
|
|
20747
|
-
packageName: z.string().optional(),
|
|
20748
|
-
includeValidators: z.boolean().optional()
|
|
20749
21320
|
}).optional()
|
|
20750
21321
|
});
|
|
20751
21322
|
async function loadCodegenConfig(configPath) {
|
|
20752
|
-
const defaultPath =
|
|
20753
|
-
const alternatePath =
|
|
21323
|
+
const defaultPath = path5.join(process.cwd(), "relyio.codegen.yaml");
|
|
21324
|
+
const alternatePath = path5.join(process.cwd(), "relyio.codegen.yml");
|
|
20754
21325
|
let targetPath = configPath;
|
|
20755
21326
|
if (!targetPath) {
|
|
20756
21327
|
try {
|
|
@@ -20794,12 +21365,11 @@ function mergeConfigWithOptions(config, options, language) {
|
|
|
20794
21365
|
moduleFormat: options.moduleFormat || languageConfig.moduleFormat || "esm"
|
|
20795
21366
|
};
|
|
20796
21367
|
}
|
|
20797
|
-
function
|
|
20798
|
-
const supportedLanguages = ["typescript", "python", "go", "rust", "csharp", "java"];
|
|
21368
|
+
function assertSupportedLanguages(languages) {
|
|
20799
21369
|
for (const language of languages) {
|
|
20800
|
-
if (!
|
|
21370
|
+
if (!BUILT_IN_LANGUAGES.includes(language)) {
|
|
20801
21371
|
throw new Error(
|
|
20802
|
-
`Unsupported language: ${language}. Supported languages: ${
|
|
21372
|
+
`Unsupported language: ${language}. Supported languages: ${BUILT_IN_LANGUAGES.join(", ")}`
|
|
20803
21373
|
);
|
|
20804
21374
|
}
|
|
20805
21375
|
}
|
|
@@ -20815,24 +21385,8 @@ function formatSchemaSource3(result) {
|
|
|
20815
21385
|
const count = files.length;
|
|
20816
21386
|
return `YAML (${count} file${count === 1 ? "" : "s"})`;
|
|
20817
21387
|
}
|
|
20818
|
-
|
|
21388
|
+
function handleGenerationError(error2) {
|
|
20819
21389
|
if (error2 instanceof Error) {
|
|
20820
|
-
if (error2.message.includes("not installed")) {
|
|
20821
|
-
const availablePlugins = await getAvailablePlugins();
|
|
20822
|
-
const suggestedPlugins = getSuggestedPlugins();
|
|
20823
|
-
displayInfo("\u{1F4CB} Available generators:");
|
|
20824
|
-
for (const plugin3 of availablePlugins) {
|
|
20825
|
-
const status = plugin3 === "typescript" || plugin3 === "python" ? " (built-in)" : "";
|
|
20826
|
-
displayInfo(` \u2705 ${plugin3}${status}`);
|
|
20827
|
-
}
|
|
20828
|
-
displayInfo("\n\u{1F4BE} Install additional generators with:");
|
|
20829
|
-
for (const [language, packageName] of Object.entries(suggestedPlugins)) {
|
|
20830
|
-
if (!availablePlugins.includes(language)) {
|
|
20831
|
-
displayInfo(` pnpm add -D ${packageName}`);
|
|
20832
|
-
}
|
|
20833
|
-
}
|
|
20834
|
-
return;
|
|
20835
|
-
}
|
|
20836
21390
|
if (error2.message.includes("Schema validation failed") || error2.message.includes("validation error")) {
|
|
20837
21391
|
displayInfo("\n\u{1F4A1} Troubleshooting steps:");
|
|
20838
21392
|
displayInfo("1. Run 'relyio status' to see validation details");
|
|
@@ -20901,14 +21455,16 @@ async function performTypeGeneration(branchName, options, watchMode = false) {
|
|
|
20901
21455
|
`Failed to load configuration: ${error2 instanceof Error ? error2.message : "Unknown error"}`
|
|
20902
21456
|
);
|
|
20903
21457
|
}
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
21458
|
+
const requested = options.languages || options.language ? [
|
|
21459
|
+
...new Set(
|
|
21460
|
+
options.languages ? options.languages.split(",") : [options.language || "typescript"]
|
|
21461
|
+
)
|
|
21462
|
+
] : (
|
|
21463
|
+
// Use config file languages if no CLI language specified
|
|
21464
|
+
[...new Set(ctx.config.languages || ["typescript"])]
|
|
21465
|
+
);
|
|
21466
|
+
assertSupportedLanguages(requested);
|
|
21467
|
+
ctx.languages = requested;
|
|
20912
21468
|
}
|
|
20913
21469
|
},
|
|
20914
21470
|
{
|
|
@@ -21046,7 +21602,7 @@ async function performTypeGeneration(branchName, options, watchMode = false) {
|
|
|
21046
21602
|
"Type generation failed",
|
|
21047
21603
|
error2 instanceof Error ? error2.message : "Unknown error"
|
|
21048
21604
|
);
|
|
21049
|
-
|
|
21605
|
+
handleGenerationError(error2);
|
|
21050
21606
|
process.exit(1);
|
|
21051
21607
|
}
|
|
21052
21608
|
}
|
|
@@ -21116,18 +21672,17 @@ function generateTypesCommand(program2) {
|
|
|
21116
21672
|
"after",
|
|
21117
21673
|
`
|
|
21118
21674
|
Examples:
|
|
21119
|
-
$ relyio generate-types
|
|
21120
|
-
$ relyio generate-types -o ./src/types
|
|
21121
|
-
$ relyio generate-types --watch
|
|
21122
|
-
$ relyio generate-types -l python
|
|
21123
|
-
$ relyio generate-types --languages
|
|
21675
|
+
$ relyio generate-types # Generate TypeScript types
|
|
21676
|
+
$ relyio generate-types -o ./src/types # Custom output directory
|
|
21677
|
+
$ relyio generate-types --watch # Watch mode
|
|
21678
|
+
$ relyio generate-types -l python # Generate Python types
|
|
21679
|
+
$ relyio generate-types --languages typescript,python # Multiple languages
|
|
21124
21680
|
|
|
21125
|
-
Supported
|
|
21126
|
-
|
|
21127
|
-
python (py) Python type hints (dataclasses)
|
|
21681
|
+
Supported languages:
|
|
21682
|
+
${BUILT_IN_LANGUAGES.join(", ")}
|
|
21128
21683
|
|
|
21129
21684
|
Configuration:
|
|
21130
|
-
Create codegen.
|
|
21685
|
+
Create relyio.codegen.yaml (or .yml) for advanced options.
|
|
21131
21686
|
`
|
|
21132
21687
|
);
|
|
21133
21688
|
}
|
|
@@ -21304,7 +21859,6 @@ function displayObjectDiff(obj, indent, mode) {
|
|
|
21304
21859
|
const color = THEME3.added ;
|
|
21305
21860
|
const prefix = "+" ;
|
|
21306
21861
|
for (const [key, value] of Object.entries(obj)) {
|
|
21307
|
-
if (key === "_tag") continue;
|
|
21308
21862
|
if (Array.isArray(value)) {
|
|
21309
21863
|
console.log(color(`${indent}${prefix} ${key}:`));
|
|
21310
21864
|
for (const item of value) {
|
|
@@ -21902,7 +22456,7 @@ Configuration:
|
|
|
21902
22456
|
relyio config set dashboardUrl <url>
|
|
21903
22457
|
|
|
21904
22458
|
For local development:
|
|
21905
|
-
relyio config set dashboardUrl http://localhost:
|
|
22459
|
+
relyio config set dashboardUrl http://localhost:3920
|
|
21906
22460
|
|
|
21907
22461
|
For production:
|
|
21908
22462
|
relyio config set dashboardUrl https://dashboard.relyio.com
|
|
@@ -22292,7 +22846,7 @@ var THEME7 = {
|
|
|
22292
22846
|
alias: chalk12.cyan,
|
|
22293
22847
|
command: chalk12.yellow
|
|
22294
22848
|
};
|
|
22295
|
-
var ALIAS_FILE =
|
|
22849
|
+
var ALIAS_FILE = path5.join(os.homedir(), ".relyio", "aliases.json");
|
|
22296
22850
|
function readAliases() {
|
|
22297
22851
|
try {
|
|
22298
22852
|
if (fs2.existsSync(ALIAS_FILE)) {
|
|
@@ -22303,7 +22857,7 @@ function readAliases() {
|
|
|
22303
22857
|
return {};
|
|
22304
22858
|
}
|
|
22305
22859
|
function writeAliases(aliases) {
|
|
22306
|
-
const dir =
|
|
22860
|
+
const dir = path5.dirname(ALIAS_FILE);
|
|
22307
22861
|
if (!fs2.existsSync(dir)) {
|
|
22308
22862
|
fs2.mkdirSync(dir, { recursive: true });
|
|
22309
22863
|
}
|
|
@@ -22443,6 +22997,7 @@ function runPreflight() {
|
|
|
22443
22997
|
}
|
|
22444
22998
|
|
|
22445
22999
|
// src/dev/cockpit.tsx
|
|
23000
|
+
init_dev_handshake();
|
|
22446
23001
|
init_app();
|
|
22447
23002
|
init_dev_cockpit_context();
|
|
22448
23003
|
var WrappedChildProcess = class {
|
|
@@ -22457,8 +23012,7 @@ var WrappedChildProcess = class {
|
|
|
22457
23012
|
cwd: this.options.cwd,
|
|
22458
23013
|
env: {
|
|
22459
23014
|
...process.env,
|
|
22460
|
-
|
|
22461
|
-
RELYIO_DEV_API_KEY: this.options.env.RELYIO_DEV_API_KEY
|
|
23015
|
+
...this.options.env
|
|
22462
23016
|
},
|
|
22463
23017
|
stdio: ["ignore", "pipe", "pipe"]
|
|
22464
23018
|
});
|
|
@@ -22683,10 +23237,14 @@ function DevCockpit({
|
|
|
22683
23237
|
command: childCommand.command,
|
|
22684
23238
|
args: childCommand.args,
|
|
22685
23239
|
cwd: projectRoot,
|
|
22686
|
-
|
|
22687
|
-
|
|
22688
|
-
|
|
22689
|
-
|
|
23240
|
+
// The wrapped child and the standalone `.relyio/dev.json` reader must see the same
|
|
23241
|
+
// sandbox, deadline included — before REL-647 the env carrier had no deadline at all, so a
|
|
23242
|
+
// lapsed sandbox kept working here for the life of the process.
|
|
23243
|
+
env: buildDevEnv({
|
|
23244
|
+
datasetId: sandbox.datasetId,
|
|
23245
|
+
previewApiKey: sandbox.previewApiKey,
|
|
23246
|
+
expiresAt: sandbox.expiresAt
|
|
23247
|
+
}),
|
|
22690
23248
|
onOutput: (chunk) => setChildLines((previous) => appendChildLines(previous, chunk)),
|
|
22691
23249
|
onExit: () => setChildRunning(false)
|
|
22692
23250
|
});
|
|
@@ -22932,22 +23490,16 @@ init_session_manager();
|
|
|
22932
23490
|
// src/ai/services/conversations-client.ts
|
|
22933
23491
|
init_wire();
|
|
22934
23492
|
init_config();
|
|
23493
|
+
init_gateway_url();
|
|
22935
23494
|
var AI_GATEWAY_CONVERSATIONS_PATH = "/ai/conversations";
|
|
22936
|
-
function getGatewayUrl5() {
|
|
22937
|
-
if (process.env.RELYIO_AI_GATEWAY_URL) {
|
|
22938
|
-
return process.env.RELYIO_AI_GATEWAY_URL.replaceAll("http://localhost", "http://127.0.0.1");
|
|
22939
|
-
}
|
|
22940
|
-
if (process.env.RELYIO_API_URL) return "http://127.0.0.1:3600";
|
|
22941
|
-
return "https://ai-gateway.relyio.com";
|
|
22942
|
-
}
|
|
22943
23495
|
function getAuthToken7() {
|
|
22944
23496
|
const token = config_default.getAuthToken();
|
|
22945
23497
|
if (token) return token;
|
|
22946
23498
|
throw new Error("Not authenticated. Run `relyio login` first.");
|
|
22947
23499
|
}
|
|
22948
23500
|
var ConversationsClient = class {
|
|
22949
|
-
async request(method,
|
|
22950
|
-
const url = new URL(`${
|
|
23501
|
+
async request(method, path25, init = {}) {
|
|
23502
|
+
const url = new URL(`${getGatewayUrl()}${AI_GATEWAY_CONVERSATIONS_PATH}${path25}`);
|
|
22951
23503
|
if (init.query) {
|
|
22952
23504
|
for (const [k, v] of Object.entries(init.query)) {
|
|
22953
23505
|
if (v === void 0) continue;
|
|
@@ -22966,7 +23518,7 @@ var ConversationsClient = class {
|
|
|
22966
23518
|
const raw = await response.text().catch(() => "");
|
|
22967
23519
|
const refusal = readError(parseJson(raw));
|
|
22968
23520
|
throw new Error(
|
|
22969
|
-
refusal === void 0 ? `Conversations API ${method} ${
|
|
23521
|
+
refusal === void 0 ? `Conversations API ${method} ${path25} \u2192 ${response.status}: ${raw}` : `Conversations API ${method} ${path25} \u2192 ${response.status} ${refusal.code}: ${refusal.messages.join(" ")}`
|
|
22970
23522
|
);
|
|
22971
23523
|
}
|
|
22972
23524
|
const text = await response.text();
|
|
@@ -23216,10 +23768,13 @@ async function resolveModelFlag(rawRef) {
|
|
|
23216
23768
|
return "invalid";
|
|
23217
23769
|
}
|
|
23218
23770
|
if (!match.available) {
|
|
23219
|
-
|
|
23220
|
-
|
|
23221
|
-
|
|
23222
|
-
|
|
23771
|
+
console.log(
|
|
23772
|
+
chalk12.red(
|
|
23773
|
+
`
|
|
23774
|
+
Cannot use ${match.name} \u2014 this model is currently disabled by the workspace admin.
|
|
23775
|
+
`
|
|
23776
|
+
)
|
|
23777
|
+
);
|
|
23223
23778
|
return "invalid";
|
|
23224
23779
|
}
|
|
23225
23780
|
return match.id;
|
|
@@ -24048,7 +24603,7 @@ Examples:
|
|
|
24048
24603
|
}
|
|
24049
24604
|
|
|
24050
24605
|
// src/index.ts
|
|
24051
|
-
var CLI_VERSION3 = "0.
|
|
24606
|
+
var CLI_VERSION3 = "0.3.0" ;
|
|
24052
24607
|
var program = new Command();
|
|
24053
24608
|
program.name("relyio").description("RelyIO CLI - Content Management, Simplified").version(CLI_VERSION3);
|
|
24054
24609
|
registerGlobalOptions(program);
|