@relyio/cli 0.2.2 → 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 +1329 -763
- package/package.json +5 -3
- 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
|
|
|
@@ -4060,13 +4316,214 @@ var init_deploy_service = __esm({
|
|
|
4060
4316
|
};
|
|
4061
4317
|
}
|
|
4062
4318
|
});
|
|
4319
|
+
|
|
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
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
});
|
|
4063
4520
|
function normalizeReferenceTargets(to) {
|
|
4064
4521
|
if (to == null) return [];
|
|
4065
4522
|
return Array.isArray(to) ? [...to] : [to];
|
|
4066
4523
|
}
|
|
4067
4524
|
var BaseFieldConfigSchema, ReferenceStrengthSchema, OnTargetDeleteSchema, ReferenceTargetSchema;
|
|
4068
|
-
var
|
|
4069
|
-
"../../domain/schema/dist/chunk-
|
|
4525
|
+
var init_chunk_RIJEP5Z6 = __esm({
|
|
4526
|
+
"../../domain/schema/dist/chunk-RIJEP5Z6.js"() {
|
|
4070
4527
|
BaseFieldConfigSchema = z.object({
|
|
4071
4528
|
required: z.boolean().optional(),
|
|
4072
4529
|
unique: z.boolean().optional(),
|
|
@@ -4120,10 +4577,11 @@ var init_chunk_YL47KAP2 = __esm({
|
|
|
4120
4577
|
});
|
|
4121
4578
|
}
|
|
4122
4579
|
});
|
|
4123
|
-
var
|
|
4124
|
-
"../../domain/schema/dist/chunk-
|
|
4125
|
-
|
|
4126
|
-
|
|
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();
|
|
4127
4585
|
BaseFieldConfigSchema.extend({
|
|
4128
4586
|
maxLength: z.number().min(1).optional(),
|
|
4129
4587
|
pattern: z.string().optional(),
|
|
@@ -4359,30 +4817,62 @@ var init_chunk_XTMEVLMJ = __esm({
|
|
|
4359
4817
|
}
|
|
4360
4818
|
});
|
|
4361
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
|
+
|
|
4362
4850
|
// ../../domain/schema/dist/chunk-QSWR2YJN.js
|
|
4363
4851
|
var init_chunk_QSWR2YJN = __esm({
|
|
4364
4852
|
"../../domain/schema/dist/chunk-QSWR2YJN.js"() {
|
|
4365
4853
|
}
|
|
4366
4854
|
});
|
|
4367
4855
|
|
|
4368
|
-
// ../../domain/schema/dist/chunk-
|
|
4369
|
-
var
|
|
4370
|
-
"../../domain/schema/dist/chunk-
|
|
4371
|
-
|
|
4856
|
+
// ../../domain/schema/dist/chunk-2ABFISBQ.js
|
|
4857
|
+
var init_chunk_2ABFISBQ = __esm({
|
|
4858
|
+
"../../domain/schema/dist/chunk-2ABFISBQ.js"() {
|
|
4859
|
+
init_chunk_RIJEP5Z6();
|
|
4372
4860
|
init_chunk_QSWR2YJN();
|
|
4373
|
-
|
|
4861
|
+
init_chunk_PCG6XHFD();
|
|
4374
4862
|
}
|
|
4375
4863
|
});
|
|
4376
|
-
var
|
|
4864
|
+
var init_dist3 = __esm({
|
|
4377
4865
|
"../../domain/schema/dist/index.js"() {
|
|
4378
|
-
|
|
4379
|
-
|
|
4866
|
+
init_chunk_3UOSTM65();
|
|
4867
|
+
init_chunk_2326XWZE();
|
|
4380
4868
|
init_chunk_XTMEVLMJ();
|
|
4381
4869
|
init_chunk_VGBOPF6G();
|
|
4382
|
-
|
|
4383
|
-
|
|
4870
|
+
init_chunk_73FJJM22();
|
|
4871
|
+
init_chunk_2ABFISBQ();
|
|
4872
|
+
init_chunk_RIJEP5Z6();
|
|
4384
4873
|
init_chunk_QSWR2YJN();
|
|
4385
|
-
|
|
4874
|
+
init_chunk_PCG6XHFD();
|
|
4875
|
+
init_chunk_JH6U6ENN();
|
|
4386
4876
|
new Set(FORBIDDEN_ASSET_TYPE_FIELD_TYPES);
|
|
4387
4877
|
}
|
|
4388
4878
|
});
|
|
@@ -4427,24 +4917,17 @@ function validateSchema(schema) {
|
|
|
4427
4917
|
formatted: SchemaValidator.formatErrors(errors)
|
|
4428
4918
|
};
|
|
4429
4919
|
}
|
|
4430
|
-
function toPascalCase(str) {
|
|
4431
|
-
const spaced = str.replaceAll(/([a-z])([A-Z])/g, "$1 $2");
|
|
4432
|
-
return spaced.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
4433
|
-
}
|
|
4434
|
-
function toCamelCase(str) {
|
|
4435
|
-
const pascal = toPascalCase(str);
|
|
4436
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
4437
|
-
}
|
|
4438
4920
|
async function generateTypeScriptFromSchema(rawSchema, options) {
|
|
4439
4921
|
const parsedSchema = parseSchema(rawSchema);
|
|
4440
4922
|
const generator = new TypeScriptGenerator(parsedSchema, options);
|
|
4441
4923
|
return generator.generate();
|
|
4442
4924
|
}
|
|
4443
4925
|
var ASSET_KINDS2, SchemaParser, SchemaValidator, TypeScriptGenerator, plugin, index_default;
|
|
4444
|
-
var
|
|
4926
|
+
var init_dist4 = __esm({
|
|
4445
4927
|
"../codegen-typescript/dist/index.js"() {
|
|
4446
|
-
|
|
4447
|
-
|
|
4928
|
+
init_dist3();
|
|
4929
|
+
init_dist2();
|
|
4930
|
+
init_dist3();
|
|
4448
4931
|
ASSET_KINDS2 = ["image", "video", "file"];
|
|
4449
4932
|
SchemaParser = class {
|
|
4450
4933
|
/**
|
|
@@ -4911,16 +5394,16 @@ var init_dist2 = __esm({
|
|
|
4911
5394
|
* Validate a content type
|
|
4912
5395
|
*/
|
|
4913
5396
|
validateContentType(id, contentType) {
|
|
4914
|
-
const
|
|
4915
|
-
this.validateFields(contentType.fields,
|
|
5397
|
+
const path25 = `contentTypes.${id}`;
|
|
5398
|
+
this.validateFields(contentType.fields, path25);
|
|
4916
5399
|
if (contentType.fields.length === 0) {
|
|
4917
|
-
this.addWarning(
|
|
5400
|
+
this.addWarning(path25, "Content type has no fields defined");
|
|
4918
5401
|
}
|
|
4919
5402
|
const reservedFields = /* @__PURE__ */ new Set(["id", "createdAt", "updatedAt", "_id"]);
|
|
4920
5403
|
for (const field of contentType.fields) {
|
|
4921
5404
|
if (reservedFields.has(field.id)) {
|
|
4922
5405
|
this.addError(
|
|
4923
|
-
`${
|
|
5406
|
+
`${path25}.fields.${field.id}`,
|
|
4924
5407
|
`Field name '${field.id}' is reserved by BaseContent`,
|
|
4925
5408
|
`Use a different field name`
|
|
4926
5409
|
);
|
|
@@ -4947,20 +5430,20 @@ var init_dist2 = __esm({
|
|
|
4947
5430
|
/**
|
|
4948
5431
|
* Validate field type
|
|
4949
5432
|
*/
|
|
4950
|
-
validateFieldType(field,
|
|
5433
|
+
validateFieldType(field, path25) {
|
|
4951
5434
|
if (field.type === "enum" && (!field.enumValues || field.enumValues.length === 0)) {
|
|
4952
|
-
this.addError(
|
|
5435
|
+
this.addError(path25, "Enum field has no values defined");
|
|
4953
5436
|
}
|
|
4954
5437
|
if (field.type === "reference" && !field.referenceType) {
|
|
4955
5438
|
this.addError(
|
|
4956
|
-
|
|
5439
|
+
path25,
|
|
4957
5440
|
"Reference field missing referenceType",
|
|
4958
5441
|
"Ensure the reference target (to) is specified in the schema"
|
|
4959
5442
|
);
|
|
4960
5443
|
}
|
|
4961
5444
|
if (field.type === "component" && !field.componentType) {
|
|
4962
5445
|
this.addError(
|
|
4963
|
-
|
|
5446
|
+
path25,
|
|
4964
5447
|
"Component field missing componentType",
|
|
4965
5448
|
"Ensure component type is specified as component(componentName)"
|
|
4966
5449
|
);
|
|
@@ -4970,11 +5453,11 @@ var init_dist2 = __esm({
|
|
|
4970
5453
|
* Check for circular references
|
|
4971
5454
|
*/
|
|
4972
5455
|
checkCircularReferences(schema) {
|
|
4973
|
-
const checkType = (typeName, visited,
|
|
5456
|
+
const checkType = (typeName, visited, path25) => {
|
|
4974
5457
|
if (visited.has(typeName)) {
|
|
4975
5458
|
this.addError(
|
|
4976
|
-
|
|
4977
|
-
`Circular reference detected: ${
|
|
5459
|
+
path25.join(" -> "),
|
|
5460
|
+
`Circular reference detected: ${path25.join(" -> ")} -> ${typeName}`
|
|
4978
5461
|
);
|
|
4979
5462
|
return;
|
|
4980
5463
|
}
|
|
@@ -4983,7 +5466,7 @@ var init_dist2 = __esm({
|
|
|
4983
5466
|
visited.add(typeName);
|
|
4984
5467
|
for (const field of contentType.fields) {
|
|
4985
5468
|
if (field.isReference && field.referenceType) {
|
|
4986
|
-
checkType(field.referenceType, new Set(visited), [...
|
|
5469
|
+
checkType(field.referenceType, new Set(visited), [...path25, field.referenceType]);
|
|
4987
5470
|
}
|
|
4988
5471
|
}
|
|
4989
5472
|
};
|
|
@@ -4994,10 +5477,10 @@ var init_dist2 = __esm({
|
|
|
4994
5477
|
/**
|
|
4995
5478
|
* Add an error
|
|
4996
5479
|
*/
|
|
4997
|
-
addError(
|
|
5480
|
+
addError(path25, message, suggestion) {
|
|
4998
5481
|
this.errors.push({
|
|
4999
5482
|
type: "error",
|
|
5000
|
-
path:
|
|
5483
|
+
path: path25,
|
|
5001
5484
|
message,
|
|
5002
5485
|
suggestion
|
|
5003
5486
|
});
|
|
@@ -5005,10 +5488,10 @@ var init_dist2 = __esm({
|
|
|
5005
5488
|
/**
|
|
5006
5489
|
* Add a warning
|
|
5007
5490
|
*/
|
|
5008
|
-
addWarning(
|
|
5491
|
+
addWarning(path25, message, suggestion) {
|
|
5009
5492
|
this.warnings.push({
|
|
5010
5493
|
type: "warning",
|
|
5011
|
-
path:
|
|
5494
|
+
path: path25,
|
|
5012
5495
|
message,
|
|
5013
5496
|
suggestion
|
|
5014
5497
|
});
|
|
@@ -5153,6 +5636,9 @@ ${prefix}: ${error2.path}`, ` ${error2.message}`);
|
|
|
5153
5636
|
import type {
|
|
5154
5637
|
${typeImports.join(",\n ")},
|
|
5155
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'
|
|
5156
5642
|
`);
|
|
5157
5643
|
}
|
|
5158
5644
|
/**
|
|
@@ -5183,7 +5669,7 @@ import type {
|
|
|
5183
5669
|
}
|
|
5184
5670
|
lines.push(" */");
|
|
5185
5671
|
}
|
|
5186
|
-
const varName =
|
|
5672
|
+
const varName = naming.camel(component.id) + "Component";
|
|
5187
5673
|
lines.push(`export const ${varName} = defineComponent('${component.id}', {`);
|
|
5188
5674
|
if (component.displayName) {
|
|
5189
5675
|
lines.push(` displayName: '${this.escapeString(component.displayName)}',`);
|
|
@@ -5226,7 +5712,7 @@ import type {
|
|
|
5226
5712
|
}
|
|
5227
5713
|
lines.push(" */");
|
|
5228
5714
|
}
|
|
5229
|
-
const varName =
|
|
5715
|
+
const varName = naming.camel(contentType.id);
|
|
5230
5716
|
lines.push(`export const ${varName} = defineContentType('${contentType.id}', {`);
|
|
5231
5717
|
if (contentType.displayName) {
|
|
5232
5718
|
lines.push(` displayName: '${this.escapeString(contentType.displayName)}',`);
|
|
@@ -5283,7 +5769,7 @@ import type {
|
|
|
5283
5769
|
}
|
|
5284
5770
|
lines.push(" */");
|
|
5285
5771
|
}
|
|
5286
|
-
const varName =
|
|
5772
|
+
const varName = naming.camel(assetType.id);
|
|
5287
5773
|
lines.push(`export const ${varName} = defineAssetType('${assetType.id}', {`);
|
|
5288
5774
|
if (assetType.displayName) {
|
|
5289
5775
|
lines.push(` displayName: '${this.escapeString(assetType.displayName)}',`);
|
|
@@ -5558,7 +6044,7 @@ import type {
|
|
|
5558
6044
|
}
|
|
5559
6045
|
lines.push(" */");
|
|
5560
6046
|
}
|
|
5561
|
-
const varName =
|
|
6047
|
+
const varName = naming.camel(singleton5.id);
|
|
5562
6048
|
lines.push(`export const ${varName} = defineSingleton('${singleton5.id}', {`);
|
|
5563
6049
|
if (singleton5.displayName) {
|
|
5564
6050
|
lines.push(` displayName: '${this.escapeString(singleton5.displayName)}',`);
|
|
@@ -5610,7 +6096,7 @@ import type {
|
|
|
5610
6096
|
}
|
|
5611
6097
|
lines.push(" */");
|
|
5612
6098
|
}
|
|
5613
|
-
const varName =
|
|
6099
|
+
const varName = naming.camel(group.id) + "Settings";
|
|
5614
6100
|
lines.push(`export const ${varName} = defineSettingsGroup('${group.id}', {`);
|
|
5615
6101
|
if (group.displayName) {
|
|
5616
6102
|
lines.push(` displayName: '${this.escapeString(group.displayName)}',`);
|
|
@@ -5643,7 +6129,7 @@ import type {
|
|
|
5643
6129
|
*/
|
|
5644
6130
|
generateQuery(query) {
|
|
5645
6131
|
const lines = [];
|
|
5646
|
-
const varName =
|
|
6132
|
+
const varName = naming.camel(query.id) + "Query";
|
|
5647
6133
|
lines.push(`export const ${varName} = defineQuery('${query.id}', {`);
|
|
5648
6134
|
if (query.endpoint) {
|
|
5649
6135
|
lines.push(` endpoint: '${query.endpoint}',`);
|
|
@@ -5702,7 +6188,7 @@ import type {
|
|
|
5702
6188
|
if (this.schema.contentTypes.size > 0) {
|
|
5703
6189
|
lines.push(" contentTypes: {");
|
|
5704
6190
|
for (const [id] of this.schema.contentTypes) {
|
|
5705
|
-
const varName =
|
|
6191
|
+
const varName = naming.camel(id);
|
|
5706
6192
|
lines.push(` ${id}: ${varName},`);
|
|
5707
6193
|
}
|
|
5708
6194
|
lines.push(" },");
|
|
@@ -5710,7 +6196,7 @@ import type {
|
|
|
5710
6196
|
if (this.schema.components.size > 0) {
|
|
5711
6197
|
lines.push(" components: {");
|
|
5712
6198
|
for (const [id] of this.schema.components) {
|
|
5713
|
-
const varName =
|
|
6199
|
+
const varName = naming.camel(id) + "Component";
|
|
5714
6200
|
lines.push(` ${id}: ${varName},`);
|
|
5715
6201
|
}
|
|
5716
6202
|
lines.push(" },");
|
|
@@ -5718,7 +6204,7 @@ import type {
|
|
|
5718
6204
|
if (this.schema.assetTypes.size > 0) {
|
|
5719
6205
|
lines.push(" assetTypes: {");
|
|
5720
6206
|
for (const [id] of this.schema.assetTypes) {
|
|
5721
|
-
const varName =
|
|
6207
|
+
const varName = naming.camel(id);
|
|
5722
6208
|
lines.push(` ${id}: ${varName},`);
|
|
5723
6209
|
}
|
|
5724
6210
|
lines.push(" },");
|
|
@@ -5726,7 +6212,7 @@ import type {
|
|
|
5726
6212
|
if (this.schema.singletons.size > 0) {
|
|
5727
6213
|
lines.push(" singletonContentTypes: {");
|
|
5728
6214
|
for (const [id] of this.schema.singletons) {
|
|
5729
|
-
const varName =
|
|
6215
|
+
const varName = naming.camel(id);
|
|
5730
6216
|
lines.push(` ${id}: ${varName},`);
|
|
5731
6217
|
}
|
|
5732
6218
|
lines.push(" },");
|
|
@@ -5734,7 +6220,7 @@ import type {
|
|
|
5734
6220
|
if (this.schema.queries.size > 0) {
|
|
5735
6221
|
lines.push(" queries: {");
|
|
5736
6222
|
for (const [id] of this.schema.queries) {
|
|
5737
|
-
const varName =
|
|
6223
|
+
const varName = naming.camel(id) + "Query";
|
|
5738
6224
|
lines.push(` ${id}: ${varName},`);
|
|
5739
6225
|
}
|
|
5740
6226
|
lines.push(" },");
|
|
@@ -5742,7 +6228,7 @@ import type {
|
|
|
5742
6228
|
if (this.schema.settingsGroups.size > 0) {
|
|
5743
6229
|
lines.push(" settingsGroups: {");
|
|
5744
6230
|
for (const [id] of this.schema.settingsGroups) {
|
|
5745
|
-
const varName =
|
|
6231
|
+
const varName = naming.camel(id) + "Settings";
|
|
5746
6232
|
lines.push(` ${id}: ${varName},`);
|
|
5747
6233
|
}
|
|
5748
6234
|
lines.push(" },");
|
|
@@ -5760,13 +6246,13 @@ import type {
|
|
|
5760
6246
|
`);
|
|
5761
6247
|
const lines = [];
|
|
5762
6248
|
for (const [id] of this.schema.contentTypes) {
|
|
5763
|
-
const varName =
|
|
5764
|
-
const typeName =
|
|
6249
|
+
const varName = naming.camel(id);
|
|
6250
|
+
const typeName = naming.pascal(id);
|
|
5765
6251
|
lines.push(`export type ${typeName} = InferContentType<typeof ${varName}>`);
|
|
5766
6252
|
}
|
|
5767
6253
|
for (const [, assetType] of this.schema.assetTypes) {
|
|
5768
|
-
const varName =
|
|
5769
|
-
const typeName =
|
|
6254
|
+
const varName = naming.camel(assetType.id);
|
|
6255
|
+
const typeName = naming.pascal(assetType.id);
|
|
5770
6256
|
lines.push(`export type ${typeName} = InferAssetType<typeof ${varName}>`);
|
|
5771
6257
|
if (assetType.variantIds && assetType.variantIds.length > 0) {
|
|
5772
6258
|
const union = assetType.variantIds.map((vid) => `'${this.escapeString(vid)}'`).join(" | ");
|
|
@@ -5774,8 +6260,8 @@ import type {
|
|
|
5774
6260
|
}
|
|
5775
6261
|
}
|
|
5776
6262
|
for (const [id] of this.schema.singletons) {
|
|
5777
|
-
const varName =
|
|
5778
|
-
const typeName =
|
|
6263
|
+
const varName = naming.camel(id);
|
|
6264
|
+
const typeName = naming.pascal(id);
|
|
5779
6265
|
lines.push(`export type ${typeName} = InferSingleton<typeof ${varName}>`);
|
|
5780
6266
|
}
|
|
5781
6267
|
this.output.push(
|
|
@@ -5785,6 +6271,27 @@ import type {
|
|
|
5785
6271
|
export type SchemaTypes = typeof schema
|
|
5786
6272
|
`
|
|
5787
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
|
+
`);
|
|
5788
6295
|
}
|
|
5789
6296
|
/**
|
|
5790
6297
|
* Escape string for use in generated code
|
|
@@ -5918,18 +6425,12 @@ function mapFieldTypeToPython(fieldType, config) {
|
|
|
5918
6425
|
default: {
|
|
5919
6426
|
const componentMatch = fieldType.match(/^component\(([^)]+)\)$/);
|
|
5920
6427
|
if (componentMatch) {
|
|
5921
|
-
return
|
|
6428
|
+
return naming.pascal(componentMatch[1]);
|
|
5922
6429
|
}
|
|
5923
6430
|
return "Any";
|
|
5924
6431
|
}
|
|
5925
6432
|
}
|
|
5926
6433
|
}
|
|
5927
|
-
function toPascalCase2(str) {
|
|
5928
|
-
return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
5929
|
-
}
|
|
5930
|
-
function toSnakeCase(str) {
|
|
5931
|
-
return str.replaceAll(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").replaceAll(/[-\s]+/g, "_");
|
|
5932
|
-
}
|
|
5933
6434
|
function isRecord2(value) {
|
|
5934
6435
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5935
6436
|
}
|
|
@@ -5968,7 +6469,7 @@ async function generatePython(ir, options) {
|
|
|
5968
6469
|
for (const [id, contentType] of recordEntries(ir.contentTypes)) {
|
|
5969
6470
|
const content = generateContentType(id, asSchemaType(contentType), options);
|
|
5970
6471
|
files.push({
|
|
5971
|
-
path: `content_types/${
|
|
6472
|
+
path: `content_types/${naming.snake(id)}.py`,
|
|
5972
6473
|
content
|
|
5973
6474
|
});
|
|
5974
6475
|
}
|
|
@@ -5982,7 +6483,7 @@ async function generatePython(ir, options) {
|
|
|
5982
6483
|
for (const [id, component] of recordEntries(ir.components)) {
|
|
5983
6484
|
const content = generateComponent(id, asSchemaType(component), options);
|
|
5984
6485
|
files.push({
|
|
5985
|
-
path: `components/${
|
|
6486
|
+
path: `components/${naming.snake(id)}.py`,
|
|
5986
6487
|
content
|
|
5987
6488
|
});
|
|
5988
6489
|
}
|
|
@@ -5996,7 +6497,7 @@ async function generatePython(ir, options) {
|
|
|
5996
6497
|
for (const [id, singleton5] of recordEntries(ir.singletons)) {
|
|
5997
6498
|
const content = generateSingleton(id, asSchemaType(singleton5), options);
|
|
5998
6499
|
files.push({
|
|
5999
|
-
path: `singletons/${
|
|
6500
|
+
path: `singletons/${naming.snake(id)}.py`,
|
|
6000
6501
|
content
|
|
6001
6502
|
});
|
|
6002
6503
|
}
|
|
@@ -6109,7 +6610,7 @@ __all__ = ['RichTextContent', 'ImageField', 'FileField', 'Reference']
|
|
|
6109
6610
|
`;
|
|
6110
6611
|
}
|
|
6111
6612
|
function generateContentType(id, contentType, options) {
|
|
6112
|
-
const className =
|
|
6613
|
+
const className = naming.pascal(id);
|
|
6113
6614
|
const fields = generateFields(contentType.fields || [], options);
|
|
6114
6615
|
const imports = ["from ..base_types import RichTextContent, ImageField, FileField, Reference"];
|
|
6115
6616
|
if (options.baseModel === "pydantic") {
|
|
@@ -6147,7 +6648,7 @@ __all__ = ['${className}', 'Create${className}Input', 'Update${className}Input']
|
|
|
6147
6648
|
}
|
|
6148
6649
|
}
|
|
6149
6650
|
function generateComponent(id, component, options) {
|
|
6150
|
-
const className =
|
|
6651
|
+
const className = naming.pascal(id);
|
|
6151
6652
|
const fields = generateFields(component.fields || [], options);
|
|
6152
6653
|
const imports = ["from ..base_types import RichTextContent, ImageField, FileField, Reference"];
|
|
6153
6654
|
if (options.baseModel === "pydantic") {
|
|
@@ -6178,7 +6679,7 @@ __all__ = ['${className}']
|
|
|
6178
6679
|
}
|
|
6179
6680
|
}
|
|
6180
6681
|
function generateSingleton(id, singleton5, options) {
|
|
6181
|
-
const className =
|
|
6682
|
+
const className = naming.pascal(id);
|
|
6182
6683
|
const fields = generateFields(singleton5.fields || [], options);
|
|
6183
6684
|
const imports = ["from ..base_types import RichTextContent, ImageField, FileField, Reference"];
|
|
6184
6685
|
if (options.baseModel === "pydantic") {
|
|
@@ -6214,12 +6715,12 @@ __all__ = ['${className}', 'Update${className}Input']
|
|
|
6214
6715
|
}
|
|
6215
6716
|
function generateFields(fields, options) {
|
|
6216
6717
|
return fields.map((field) => {
|
|
6217
|
-
const fieldName =
|
|
6718
|
+
const fieldName = naming.snake(field.id);
|
|
6218
6719
|
const pythonType = mapFieldTypeToPython(field.type, field.config);
|
|
6219
6720
|
const isOptional = !field.required;
|
|
6220
6721
|
const fieldType = isOptional ? `Optional[${pythonType}]` : pythonType;
|
|
6221
6722
|
const defaultValue = isOptional ? " = None" : "";
|
|
6222
|
-
if (options.baseModel === "pydantic" && field.id !==
|
|
6723
|
+
if (options.baseModel === "pydantic" && field.id !== naming.snake(field.id)) {
|
|
6223
6724
|
return `${fieldName}: ${fieldType} = Field(${defaultValue.slice(3)}, alias='${field.id}')`;
|
|
6224
6725
|
}
|
|
6225
6726
|
return `${fieldName}: ${fieldType}${defaultValue}`;
|
|
@@ -6339,8 +6840,8 @@ class TenantContext(BaseModel):
|
|
|
6339
6840
|
`);
|
|
6340
6841
|
if (isRecord2(ir.contentTypes)) {
|
|
6341
6842
|
for (const id of Object.keys(ir.contentTypes)) {
|
|
6342
|
-
const className =
|
|
6343
|
-
imports.push(`from .content_types.${
|
|
6843
|
+
const className = naming.pascal(id);
|
|
6844
|
+
imports.push(`from .content_types.${naming.snake(id)} import ${className}`);
|
|
6344
6845
|
tenantTypes.push(`
|
|
6345
6846
|
class Tenant${className}(${className}):
|
|
6346
6847
|
"""Tenant-scoped ${className}"""
|
|
@@ -6359,8 +6860,8 @@ class TenantContext:
|
|
|
6359
6860
|
`);
|
|
6360
6861
|
if (isRecord2(ir.contentTypes)) {
|
|
6361
6862
|
for (const id of Object.keys(ir.contentTypes)) {
|
|
6362
|
-
const className =
|
|
6363
|
-
imports.push(`from .content_types.${
|
|
6863
|
+
const className = naming.pascal(id);
|
|
6864
|
+
imports.push(`from .content_types.${naming.snake(id)} import ${className}`);
|
|
6364
6865
|
tenantTypes.push(`
|
|
6365
6866
|
@dataclass
|
|
6366
6867
|
class Tenant${className}(${className}):
|
|
@@ -6373,7 +6874,7 @@ class Tenant${className}(${className}):
|
|
|
6373
6874
|
const exportList = ["TenantContext"];
|
|
6374
6875
|
if (isRecord2(ir.contentTypes)) {
|
|
6375
6876
|
for (const id of Object.keys(ir.contentTypes)) {
|
|
6376
|
-
exportList.push(`Tenant${
|
|
6877
|
+
exportList.push(`Tenant${naming.pascal(id)}`);
|
|
6377
6878
|
}
|
|
6378
6879
|
}
|
|
6379
6880
|
return `${imports.join("\n")}
|
|
@@ -6416,10 +6917,10 @@ __all__ = ['validate_data', 'to_dict', 'to_json']
|
|
|
6416
6917
|
}
|
|
6417
6918
|
function generateContentTypesIndex(contentTypeIds, _options) {
|
|
6418
6919
|
const imports = contentTypeIds.map(
|
|
6419
|
-
(id) => `from .${
|
|
6920
|
+
(id) => `from .${naming.snake(id)} import ${naming.pascal(id)}, Create${naming.pascal(id)}Input, Update${naming.pascal(id)}Input`
|
|
6420
6921
|
);
|
|
6421
6922
|
const exports = contentTypeIds.flatMap((id) => {
|
|
6422
|
-
const className =
|
|
6923
|
+
const className = naming.pascal(id);
|
|
6423
6924
|
return [`'${className}'`, `'Create${className}Input'`, `'Update${className}Input'`];
|
|
6424
6925
|
});
|
|
6425
6926
|
return `${imports.join("\n")}
|
|
@@ -6428,8 +6929,8 @@ __all__ = [${exports.join(", ")}]
|
|
|
6428
6929
|
`;
|
|
6429
6930
|
}
|
|
6430
6931
|
function generateComponentsIndex(componentIds, _options) {
|
|
6431
|
-
const imports = componentIds.map((id) => `from .${
|
|
6432
|
-
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)}'`);
|
|
6433
6934
|
return `${imports.join("\n")}
|
|
6434
6935
|
|
|
6435
6936
|
__all__ = [${exports.join(", ")}]
|
|
@@ -6437,10 +6938,10 @@ __all__ = [${exports.join(", ")}]
|
|
|
6437
6938
|
}
|
|
6438
6939
|
function generateSingletonsIndex(singletonIds, _options) {
|
|
6439
6940
|
const imports = singletonIds.map(
|
|
6440
|
-
(id) => `from .${
|
|
6941
|
+
(id) => `from .${naming.snake(id)} import ${naming.pascal(id)}, Update${naming.pascal(id)}Input`
|
|
6441
6942
|
);
|
|
6442
6943
|
const exports = singletonIds.flatMap((id) => {
|
|
6443
|
-
const className =
|
|
6944
|
+
const className = naming.pascal(id);
|
|
6444
6945
|
return [`'${className}'`, `'Update${className}Input'`];
|
|
6445
6946
|
});
|
|
6446
6947
|
return `${imports.join("\n")}
|
|
@@ -6449,8 +6950,10 @@ __all__ = [${exports.join(", ")}]
|
|
|
6449
6950
|
`;
|
|
6450
6951
|
}
|
|
6451
6952
|
var plugin2, index_default2;
|
|
6452
|
-
var
|
|
6953
|
+
var init_dist5 = __esm({
|
|
6453
6954
|
"../codegen-python/dist/index.js"() {
|
|
6955
|
+
init_dist2();
|
|
6956
|
+
init_dist2();
|
|
6454
6957
|
plugin2 = {
|
|
6455
6958
|
language: "python",
|
|
6456
6959
|
async generate(ir, options) {
|
|
@@ -6862,7 +7365,8 @@ async function fetchHandoffSummary(req) {
|
|
|
6862
7365
|
body: JSON.stringify({
|
|
6863
7366
|
fromAgent: req.fromAgent,
|
|
6864
7367
|
toAgent: req.toAgent,
|
|
6865
|
-
messages: req.messages
|
|
7368
|
+
messages: req.messages,
|
|
7369
|
+
projectId: req.projectId
|
|
6866
7370
|
}),
|
|
6867
7371
|
signal: controller.signal
|
|
6868
7372
|
});
|
|
@@ -8045,7 +8549,7 @@ var init_agent_loop = __esm({
|
|
|
8045
8549
|
async tryReadFile(relPath) {
|
|
8046
8550
|
if (!this.projectRoot) return void 0;
|
|
8047
8551
|
try {
|
|
8048
|
-
const fullPath =
|
|
8552
|
+
const fullPath = path5.resolve(this.projectRoot, relPath);
|
|
8049
8553
|
if (!fullPath.startsWith(this.projectRoot)) return void 0;
|
|
8050
8554
|
return await readFile(fullPath, "utf8");
|
|
8051
8555
|
} catch {
|
|
@@ -8206,7 +8710,9 @@ var init_agent_loop = __esm({
|
|
|
8206
8710
|
const result = await fetchHandoffSummary({
|
|
8207
8711
|
fromAgent,
|
|
8208
8712
|
toAgent,
|
|
8209
|
-
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
|
|
8210
8716
|
});
|
|
8211
8717
|
if (result) {
|
|
8212
8718
|
this.messages = [
|
|
@@ -8302,10 +8808,10 @@ var init_permission_gate = __esm({
|
|
|
8302
8808
|
return PROTECTED_PATHS.some((p) => normalized.startsWith(p) || normalized.includes(`/${p}`));
|
|
8303
8809
|
}
|
|
8304
8810
|
isOutsideProjectRoot(filePath) {
|
|
8305
|
-
if (
|
|
8811
|
+
if (path5.isAbsolute(filePath)) {
|
|
8306
8812
|
return !filePath.startsWith(this.projectRoot);
|
|
8307
8813
|
}
|
|
8308
|
-
const resolved =
|
|
8814
|
+
const resolved = path5.resolve(this.projectRoot, filePath);
|
|
8309
8815
|
return !resolved.startsWith(this.projectRoot);
|
|
8310
8816
|
}
|
|
8311
8817
|
};
|
|
@@ -8454,7 +8960,7 @@ var init_context_provider = __esm({
|
|
|
8454
8960
|
});
|
|
8455
8961
|
const schemaFiles = [];
|
|
8456
8962
|
for (const filePath of files) {
|
|
8457
|
-
const fullPath =
|
|
8963
|
+
const fullPath = path5.join(projectRoot, filePath);
|
|
8458
8964
|
try {
|
|
8459
8965
|
const stats = await stat2(fullPath);
|
|
8460
8966
|
const contentType = this.inferContentType(filePath);
|
|
@@ -8522,7 +9028,7 @@ var init_read_file_handler = __esm({
|
|
|
8522
9028
|
}
|
|
8523
9029
|
async execute(input) {
|
|
8524
9030
|
const filePath = input.path;
|
|
8525
|
-
const fullPath =
|
|
9031
|
+
const fullPath = path5.resolve(this.projectRoot, filePath);
|
|
8526
9032
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
8527
9033
|
return { error: "Path is outside project root" };
|
|
8528
9034
|
}
|
|
@@ -8605,12 +9111,12 @@ var init_write_file_handler = __esm({
|
|
|
8605
9111
|
async execute(input) {
|
|
8606
9112
|
const filePath = input.path;
|
|
8607
9113
|
const content = input.content;
|
|
8608
|
-
const fullPath =
|
|
9114
|
+
const fullPath = path5.resolve(this.projectRoot, filePath);
|
|
8609
9115
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
8610
9116
|
return { error: "Path is outside project root" };
|
|
8611
9117
|
}
|
|
8612
9118
|
try {
|
|
8613
|
-
await mkdir(
|
|
9119
|
+
await mkdir(path5.dirname(fullPath), { recursive: true });
|
|
8614
9120
|
await writeFile(fullPath, content, "utf8");
|
|
8615
9121
|
return { success: true, path: filePath, bytesWritten: content.length };
|
|
8616
9122
|
} catch (error2) {
|
|
@@ -8634,7 +9140,7 @@ var init_apply_patch_handler = __esm({
|
|
|
8634
9140
|
const filePath = input.path;
|
|
8635
9141
|
const searchBlock = input.searchBlock;
|
|
8636
9142
|
const replaceBlock = input.replaceBlock;
|
|
8637
|
-
const fullPath =
|
|
9143
|
+
const fullPath = path5.resolve(this.projectRoot, filePath);
|
|
8638
9144
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
8639
9145
|
return { error: "Path is outside project root" };
|
|
8640
9146
|
}
|
|
@@ -10142,7 +10648,7 @@ function Banner() {
|
|
|
10142
10648
|
label: "App",
|
|
10143
10649
|
value: dev.sandbox.wiredEnv ? "wired" : "manual",
|
|
10144
10650
|
valueColor: dev.sandbox.wiredEnv ? "green" : void 0,
|
|
10145
|
-
suffix: dev.sandbox.wiredEnv ? void 0 :
|
|
10651
|
+
suffix: dev.sandbox.wiredEnv ? void 0 : DEV_CONTEXT_FILE
|
|
10146
10652
|
}
|
|
10147
10653
|
];
|
|
10148
10654
|
} else {
|
|
@@ -10208,11 +10714,12 @@ function FieldRow({ field }) {
|
|
|
10208
10714
|
var CLI_VERSION2, BRAND_GLYPH, BRAND_NAME, LABEL_WIDTH, TWO_COLUMN_MIN_COLS;
|
|
10209
10715
|
var init_banner = __esm({
|
|
10210
10716
|
"src/ai/repl/components/banner.tsx"() {
|
|
10717
|
+
init_dev_handshake();
|
|
10211
10718
|
init_runtime_context();
|
|
10212
10719
|
init_dev_cockpit_context();
|
|
10213
10720
|
init_dev_cockpit_format();
|
|
10214
10721
|
init_startup_info();
|
|
10215
|
-
CLI_VERSION2 = "0.
|
|
10722
|
+
CLI_VERSION2 = "0.3.0" ;
|
|
10216
10723
|
BRAND_GLYPH = "\u25B6";
|
|
10217
10724
|
BRAND_NAME = "RelyIO";
|
|
10218
10725
|
LABEL_WIDTH = 9;
|
|
@@ -10472,8 +10979,8 @@ function entryLabel(fields, contentType) {
|
|
|
10472
10979
|
return title || contentType || "";
|
|
10473
10980
|
}
|
|
10474
10981
|
function itemTarget(tc) {
|
|
10475
|
-
const
|
|
10476
|
-
if (
|
|
10982
|
+
const path25 = tc.input.path;
|
|
10983
|
+
if (path25) return path25;
|
|
10477
10984
|
switch (tc.toolName) {
|
|
10478
10985
|
case "getSchemaReference": {
|
|
10479
10986
|
const topic = tc.input.topic;
|
|
@@ -11201,8 +11708,8 @@ var init_input_preprocessor = __esm({
|
|
|
11201
11708
|
var HISTORY_DIR, HISTORY_FILE, MAX_HISTORY_ENTRIES, PersistentHistory;
|
|
11202
11709
|
var init_input_history = __esm({
|
|
11203
11710
|
"src/ai/services/input-history.ts"() {
|
|
11204
|
-
HISTORY_DIR =
|
|
11205
|
-
HISTORY_FILE =
|
|
11711
|
+
HISTORY_DIR = path5.join(os.homedir(), ".relyio");
|
|
11712
|
+
HISTORY_FILE = path5.join(HISTORY_DIR, "ai-history");
|
|
11206
11713
|
MAX_HISTORY_ENTRIES = 1e3;
|
|
11207
11714
|
PersistentHistory = class {
|
|
11208
11715
|
entries = [];
|
|
@@ -11213,7 +11720,7 @@ var init_input_history = __esm({
|
|
|
11213
11720
|
}
|
|
11214
11721
|
load() {
|
|
11215
11722
|
try {
|
|
11216
|
-
fs2.mkdirSync(
|
|
11723
|
+
fs2.mkdirSync(path5.dirname(this.filePath), { recursive: true });
|
|
11217
11724
|
if (fs2.existsSync(this.filePath)) {
|
|
11218
11725
|
const content = fs2.readFileSync(this.filePath, "utf8");
|
|
11219
11726
|
this.entries = content.split("\n").filter(Boolean);
|
|
@@ -11243,7 +11750,7 @@ var init_input_history = __esm({
|
|
|
11243
11750
|
}
|
|
11244
11751
|
save() {
|
|
11245
11752
|
try {
|
|
11246
|
-
fs2.mkdirSync(
|
|
11753
|
+
fs2.mkdirSync(path5.dirname(this.filePath), { recursive: true });
|
|
11247
11754
|
fs2.writeFileSync(this.filePath, this.entries.join("\n") + "\n");
|
|
11248
11755
|
} catch {
|
|
11249
11756
|
}
|
|
@@ -11252,18 +11759,18 @@ var init_input_history = __esm({
|
|
|
11252
11759
|
}
|
|
11253
11760
|
});
|
|
11254
11761
|
function readMentionedFile(filePath, projectRoot) {
|
|
11255
|
-
const resolved =
|
|
11762
|
+
const resolved = path5.isAbsolute(filePath) ? filePath : path5.resolve(projectRoot, filePath);
|
|
11256
11763
|
try {
|
|
11257
11764
|
const stat2 = fs2.statSync(resolved);
|
|
11258
11765
|
if (stat2.size > MAX_FILE_SIZE) {
|
|
11259
11766
|
const content2 = fs2.readFileSync(resolved, "utf8").slice(0, MAX_FILE_SIZE);
|
|
11260
11767
|
const lines2 = content2.split("\n").length;
|
|
11261
|
-
const relativePath2 =
|
|
11768
|
+
const relativePath2 = path5.relative(projectRoot, resolved);
|
|
11262
11769
|
return { filePath: relativePath2, content: content2, lines: lines2, truncated: true };
|
|
11263
11770
|
}
|
|
11264
11771
|
const content = fs2.readFileSync(resolved, "utf8");
|
|
11265
11772
|
const lines = content.split("\n").length;
|
|
11266
|
-
const relativePath =
|
|
11773
|
+
const relativePath = path5.relative(projectRoot, resolved);
|
|
11267
11774
|
return { filePath: relativePath, content, lines, truncated: false };
|
|
11268
11775
|
} catch {
|
|
11269
11776
|
return null;
|
|
@@ -12135,11 +12642,11 @@ var init_autocomplete = __esm({
|
|
|
12135
12642
|
const schemaMatches = this.schemaFiles.filter((f) => f.toLowerCase().includes(query.toLowerCase())).slice(0, 15).map((f) => ({ value: f, label: f, kind: "file" }));
|
|
12136
12643
|
if (schemaMatches.length > 0) return schemaMatches;
|
|
12137
12644
|
try {
|
|
12138
|
-
const dir = query.includes("/") ?
|
|
12139
|
-
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;
|
|
12140
12647
|
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
12141
12648
|
return entries.filter((e) => e.name.startsWith(prefix) && !e.name.startsWith(".")).map((e) => {
|
|
12142
|
-
const rel =
|
|
12649
|
+
const rel = path5.relative(this.projectRoot, path5.join(dir, e.name));
|
|
12143
12650
|
const value = e.isDirectory() ? `${rel}/` : rel;
|
|
12144
12651
|
return { value, label: value, kind: "file" };
|
|
12145
12652
|
}).slice(0, 15);
|
|
@@ -12600,8 +13107,7 @@ function ModelPicker() {
|
|
|
12600
13107
|
description = `${description} \xB7 now routing to ${resolvedModelId}`;
|
|
12601
13108
|
}
|
|
12602
13109
|
if (!m.available) {
|
|
12603
|
-
|
|
12604
|
-
description = `${description} \xB7 ${reason}`;
|
|
13110
|
+
description = `${description} \xB7 admin-disabled for this workspace`;
|
|
12605
13111
|
}
|
|
12606
13112
|
return {
|
|
12607
13113
|
id: m.id,
|
|
@@ -13991,7 +14497,7 @@ var init_use_confirmation = __esm({
|
|
|
13991
14497
|
var SESSIONS_DIR, SESSION_VERSION, SessionManager;
|
|
13992
14498
|
var init_session_manager = __esm({
|
|
13993
14499
|
"src/ai/services/session-manager.ts"() {
|
|
13994
|
-
SESSIONS_DIR =
|
|
14500
|
+
SESSIONS_DIR = path5.join(os.homedir(), ".relyio", "ai-sessions");
|
|
13995
14501
|
SESSION_VERSION = 4;
|
|
13996
14502
|
SessionManager = class {
|
|
13997
14503
|
sessionsDir;
|
|
@@ -14000,13 +14506,13 @@ var init_session_manager = __esm({
|
|
|
14000
14506
|
fs2.mkdirSync(this.sessionsDir, { recursive: true });
|
|
14001
14507
|
}
|
|
14002
14508
|
save(session) {
|
|
14003
|
-
const filePath =
|
|
14509
|
+
const filePath = path5.join(this.sessionsDir, `${session.id}.json`);
|
|
14004
14510
|
session.version = SESSION_VERSION;
|
|
14005
14511
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14006
14512
|
fs2.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
14007
14513
|
}
|
|
14008
14514
|
load(sessionId) {
|
|
14009
|
-
const filePath =
|
|
14515
|
+
const filePath = path5.join(this.sessionsDir, `${sessionId}.json`);
|
|
14010
14516
|
try {
|
|
14011
14517
|
const content = fs2.readFileSync(filePath, "utf8");
|
|
14012
14518
|
const parsed = JSON.parse(content);
|
|
@@ -14063,7 +14569,7 @@ var init_session_manager = __esm({
|
|
|
14063
14569
|
const files = fs2.readdirSync(this.sessionsDir).filter((f) => f.endsWith(".json"));
|
|
14064
14570
|
return files.map((f) => {
|
|
14065
14571
|
try {
|
|
14066
|
-
const content = fs2.readFileSync(
|
|
14572
|
+
const content = fs2.readFileSync(path5.join(this.sessionsDir, f), "utf8");
|
|
14067
14573
|
const parsed = JSON.parse(content);
|
|
14068
14574
|
if (parsed.version !== SESSION_VERSION && parsed.version !== 3 && parsed.version !== 2) {
|
|
14069
14575
|
return null;
|
|
@@ -14081,7 +14587,7 @@ var init_session_manager = __esm({
|
|
|
14081
14587
|
return this.listAll().slice(0, count);
|
|
14082
14588
|
}
|
|
14083
14589
|
delete(sessionId) {
|
|
14084
|
-
const filePath =
|
|
14590
|
+
const filePath = path5.join(this.sessionsDir, `${sessionId}.json`);
|
|
14085
14591
|
try {
|
|
14086
14592
|
fs2.unlinkSync(filePath);
|
|
14087
14593
|
return true;
|
|
@@ -14119,7 +14625,7 @@ var init_snapshot_store = __esm({
|
|
|
14119
14625
|
SnapshotStore = class {
|
|
14120
14626
|
dir;
|
|
14121
14627
|
constructor(sessionDir) {
|
|
14122
|
-
this.dir =
|
|
14628
|
+
this.dir = path5.join(sessionDir, "snapshots");
|
|
14123
14629
|
fs2.mkdirSync(this.dir, { recursive: true });
|
|
14124
14630
|
}
|
|
14125
14631
|
/**
|
|
@@ -14180,7 +14686,7 @@ var init_snapshot_store = __esm({
|
|
|
14180
14686
|
const hash = entry.slice(0, -4);
|
|
14181
14687
|
if (keepHashes.has(hash)) continue;
|
|
14182
14688
|
try {
|
|
14183
|
-
fs2.unlinkSync(
|
|
14689
|
+
fs2.unlinkSync(path5.join(this.dir, entry));
|
|
14184
14690
|
removed++;
|
|
14185
14691
|
} catch {
|
|
14186
14692
|
}
|
|
@@ -14188,7 +14694,7 @@ var init_snapshot_store = __esm({
|
|
|
14188
14694
|
return removed;
|
|
14189
14695
|
}
|
|
14190
14696
|
pathFor(hash) {
|
|
14191
|
-
return
|
|
14697
|
+
return path5.join(this.dir, `${hash}.bin`);
|
|
14192
14698
|
}
|
|
14193
14699
|
};
|
|
14194
14700
|
}
|
|
@@ -14203,7 +14709,7 @@ var init_decision_log = __esm({
|
|
|
14203
14709
|
DecisionLog = class {
|
|
14204
14710
|
filePath;
|
|
14205
14711
|
constructor(sessionDir) {
|
|
14206
|
-
this.filePath =
|
|
14712
|
+
this.filePath = path5.join(sessionDir, "decisions.jsonl");
|
|
14207
14713
|
if (!fs2.existsSync(this.filePath)) {
|
|
14208
14714
|
fs2.writeFileSync(this.filePath, "", "utf8");
|
|
14209
14715
|
}
|
|
@@ -14328,7 +14834,7 @@ var init_session_history = __esm({
|
|
|
14328
14834
|
"src/ai/sessions/session-history.ts"() {
|
|
14329
14835
|
init_snapshot_store();
|
|
14330
14836
|
init_decision_log();
|
|
14331
|
-
SESSIONS_ROOT =
|
|
14837
|
+
SESSIONS_ROOT = path5.join(os.homedir(), ".relyio", "ai-sessions");
|
|
14332
14838
|
MAX_UNDOABLE_EVENTS = 200;
|
|
14333
14839
|
SessionHistory = class {
|
|
14334
14840
|
sessionDir;
|
|
@@ -14337,7 +14843,7 @@ var init_session_history = __esm({
|
|
|
14337
14843
|
projectRoot;
|
|
14338
14844
|
constructor(args) {
|
|
14339
14845
|
const root = args.sessionsRoot ?? SESSIONS_ROOT;
|
|
14340
|
-
this.sessionDir =
|
|
14846
|
+
this.sessionDir = path5.join(root, args.sessionId);
|
|
14341
14847
|
fs2.mkdirSync(this.sessionDir, { recursive: true });
|
|
14342
14848
|
this.snapshots = new SnapshotStore(this.sessionDir);
|
|
14343
14849
|
this.log = new DecisionLog(this.sessionDir);
|
|
@@ -14498,11 +15004,11 @@ var init_session_history = __esm({
|
|
|
14498
15004
|
* files via a malformed log entry.
|
|
14499
15005
|
*/
|
|
14500
15006
|
async writeFileSafe(relPath, content) {
|
|
14501
|
-
const fullPath =
|
|
15007
|
+
const fullPath = path5.resolve(this.projectRoot, relPath);
|
|
14502
15008
|
if (!fullPath.startsWith(this.projectRoot)) {
|
|
14503
15009
|
throw new Error(`Refusing to write outside project root: ${relPath}`);
|
|
14504
15010
|
}
|
|
14505
|
-
await fs2.promises.mkdir(
|
|
15011
|
+
await fs2.promises.mkdir(path5.dirname(fullPath), { recursive: true });
|
|
14506
15012
|
await fs2.promises.writeFile(fullPath, content, "utf8");
|
|
14507
15013
|
}
|
|
14508
15014
|
};
|
|
@@ -14510,10 +15016,10 @@ var init_session_history = __esm({
|
|
|
14510
15016
|
});
|
|
14511
15017
|
function renameLocalSessionArtifacts(oldId, newId) {
|
|
14512
15018
|
if (oldId === newId) return;
|
|
14513
|
-
const oldTranscript =
|
|
14514
|
-
const newTranscript =
|
|
14515
|
-
const oldHistoryDir =
|
|
14516
|
-
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);
|
|
14517
15023
|
try {
|
|
14518
15024
|
if (fs2.existsSync(oldTranscript) && !fs2.existsSync(newTranscript)) {
|
|
14519
15025
|
fs2.renameSync(oldTranscript, newTranscript);
|
|
@@ -14617,7 +15123,7 @@ var init_use_session_persistence = __esm({
|
|
|
14617
15123
|
init_runtime_context();
|
|
14618
15124
|
init_session_manager();
|
|
14619
15125
|
init_session_history();
|
|
14620
|
-
SESSIONS_DIR2 =
|
|
15126
|
+
SESSIONS_DIR2 = path5.join(os.homedir(), ".relyio", "ai-sessions");
|
|
14621
15127
|
}
|
|
14622
15128
|
});
|
|
14623
15129
|
|
|
@@ -14639,8 +15145,8 @@ var init_proposals_client = __esm({
|
|
|
14639
15145
|
init_gateway_url();
|
|
14640
15146
|
AI_GATEWAY_PROPOSALS_PATH = "/ai/proposals";
|
|
14641
15147
|
ProposalsClient = class {
|
|
14642
|
-
async request(method,
|
|
14643
|
-
const url = new URL(`${getGatewayUrl()}${AI_GATEWAY_PROPOSALS_PATH}${
|
|
15148
|
+
async request(method, path25, init = {}) {
|
|
15149
|
+
const url = new URL(`${getGatewayUrl()}${AI_GATEWAY_PROPOSALS_PATH}${path25}`);
|
|
14644
15150
|
if (init.query) {
|
|
14645
15151
|
for (const [k, v] of Object.entries(init.query)) url.searchParams.set(k, v);
|
|
14646
15152
|
}
|
|
@@ -14656,7 +15162,7 @@ var init_proposals_client = __esm({
|
|
|
14656
15162
|
const raw = await response.text().catch(() => "");
|
|
14657
15163
|
const refusal = readError(parseJson(raw));
|
|
14658
15164
|
throw new Error(
|
|
14659
|
-
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(" ")}`
|
|
14660
15166
|
);
|
|
14661
15167
|
}
|
|
14662
15168
|
return readPayload(await response.json());
|
|
@@ -15434,8 +15940,8 @@ function formatHistoryEntries(entries, status, limit) {
|
|
|
15434
15940
|
const rows = entries.map((e) => {
|
|
15435
15941
|
const time = new Date(e.timestamp).toLocaleTimeString();
|
|
15436
15942
|
const glyph = decisionGlyph(e.kind);
|
|
15437
|
-
const
|
|
15438
|
-
return ` ${time} ${glyph} ${
|
|
15943
|
+
const path25 = e.path || "\u2014";
|
|
15944
|
+
return ` ${time} ${glyph} ${path25}`;
|
|
15439
15945
|
});
|
|
15440
15946
|
return [header, "", ...rows, "", footer].join("\n");
|
|
15441
15947
|
}
|
|
@@ -15673,11 +16179,10 @@ Tip: just type \`/model\` (no args) to pick interactively.`
|
|
|
15673
16179
|
return;
|
|
15674
16180
|
}
|
|
15675
16181
|
if (!match.available) {
|
|
15676
|
-
const reason = match.disabledReason === "paused" ? "AI is paused globally" : "this model is currently disabled by the workspace admin";
|
|
15677
16182
|
ctx.dispatch({
|
|
15678
16183
|
type: "SYSTEM_MESSAGE_APPENDED",
|
|
15679
16184
|
label: "/model",
|
|
15680
|
-
text: `Cannot switch to ${match.name} \u2014
|
|
16185
|
+
text: `Cannot switch to ${match.name} \u2014 this model is currently disabled by the workspace admin.`
|
|
15681
16186
|
});
|
|
15682
16187
|
return;
|
|
15683
16188
|
}
|
|
@@ -16063,7 +16568,7 @@ async function resolveContext(spec, flags, pins = {}) {
|
|
|
16063
16568
|
acc.datasetId = pins.datasetId;
|
|
16064
16569
|
acc.datasetName = await safeDatasetName(projectId, acc.branchId, pins.datasetId);
|
|
16065
16570
|
} else {
|
|
16066
|
-
const datasetOutcome = await
|
|
16571
|
+
const datasetOutcome = await resolveDataset2(projectId, acc.branchId, flags.dataset);
|
|
16067
16572
|
if (datasetOutcome.kind === "needs-pick") {
|
|
16068
16573
|
return { ...datasetOutcome, partial: acc };
|
|
16069
16574
|
}
|
|
@@ -16137,7 +16642,7 @@ async function safeBranchName(projectId, branchId) {
|
|
|
16137
16642
|
return void 0;
|
|
16138
16643
|
}
|
|
16139
16644
|
}
|
|
16140
|
-
async function
|
|
16645
|
+
async function resolveDataset2(projectId, branchId, flag) {
|
|
16141
16646
|
let datasets;
|
|
16142
16647
|
try {
|
|
16143
16648
|
datasets = await manage_default.getProjectDatasets(projectId, { branchId });
|
|
@@ -16717,223 +17222,55 @@ function confirm(message) {
|
|
|
16717
17222
|
// src/api/auth.ts
|
|
16718
17223
|
init_client();
|
|
16719
17224
|
init_config();
|
|
17225
|
+
init_dist();
|
|
16720
17226
|
var isDebug3 = () => process.env.DEBUG === "true" || process.env.DEBUG === "1";
|
|
16721
|
-
var
|
|
16722
|
-
success: (tokenName) => `
|
|
16723
|
-
<html>
|
|
16724
|
-
<head>
|
|
16725
|
-
<title>RelyIO Authentication</title>
|
|
16726
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16727
|
-
<style>
|
|
16728
|
-
body {
|
|
16729
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16730
|
-
text-align: center;
|
|
16731
|
-
padding: 2rem;
|
|
16732
|
-
max-width: 600px;
|
|
16733
|
-
margin: 0 auto;
|
|
16734
|
-
line-height: 1.5;
|
|
16735
|
-
color: #333;
|
|
16736
|
-
}
|
|
16737
|
-
h1 { color: #38a169; margin-bottom: 1rem; }
|
|
16738
|
-
p { margin-bottom: 1rem; }
|
|
16739
|
-
</style>
|
|
16740
|
-
</head>
|
|
16741
|
-
<body>
|
|
16742
|
-
<h1>Authentication Successful</h1>
|
|
16743
|
-
<p>${tokenName ? `Personal access token "${tokenName}" created successfully.` : "You have successfully authenticated."}</p>
|
|
16744
|
-
<p>You can close this window and return to the CLI.</p>
|
|
16745
|
-
</body>
|
|
16746
|
-
</html>
|
|
16747
|
-
`,
|
|
16748
|
-
error: (message) => `
|
|
16749
|
-
<html>
|
|
16750
|
-
<head>
|
|
16751
|
-
<title>RelyIO Authentication Error</title>
|
|
16752
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16753
|
-
<style>
|
|
16754
|
-
body {
|
|
16755
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16756
|
-
text-align: center;
|
|
16757
|
-
padding: 2rem;
|
|
16758
|
-
max-width: 600px;
|
|
16759
|
-
margin: 0 auto;
|
|
16760
|
-
line-height: 1.5;
|
|
16761
|
-
color: #333;
|
|
16762
|
-
}
|
|
16763
|
-
h1 { color: #e53e3e; margin-bottom: 1rem; }
|
|
16764
|
-
p { margin-bottom: 1rem; }
|
|
16765
|
-
</style>
|
|
16766
|
-
</head>
|
|
16767
|
-
<body>
|
|
16768
|
-
<h1>Authentication Failed</h1>
|
|
16769
|
-
<p>${message}</p>
|
|
16770
|
-
<p>Please try again or contact support if the issue persists.</p>
|
|
16771
|
-
</body>
|
|
16772
|
-
</html>
|
|
16773
|
-
`,
|
|
16774
|
-
serverError: (message) => `
|
|
16775
|
-
<html>
|
|
16776
|
-
<head>
|
|
16777
|
-
<title>RelyIO Server Error</title>
|
|
16778
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16779
|
-
<style>
|
|
16780
|
-
body {
|
|
16781
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16782
|
-
text-align: center;
|
|
16783
|
-
padding: 2rem;
|
|
16784
|
-
max-width: 600px;
|
|
16785
|
-
margin: 0 auto;
|
|
16786
|
-
line-height: 1.5;
|
|
16787
|
-
color: #333;
|
|
16788
|
-
}
|
|
16789
|
-
h1 { color: #e53e3e; margin-bottom: 1rem; }
|
|
16790
|
-
p { margin-bottom: 1rem; }
|
|
16791
|
-
</style>
|
|
16792
|
-
</head>
|
|
16793
|
-
<body>
|
|
16794
|
-
<h1>Internal Error</h1>
|
|
16795
|
-
<p>An unexpected error occurred during authentication:</p>
|
|
16796
|
-
<p>${message}</p>
|
|
16797
|
-
<p>Please try again or contact support if the issue persists.</p>
|
|
16798
|
-
</body>
|
|
16799
|
-
</html>
|
|
16800
|
-
`
|
|
16801
|
-
};
|
|
17227
|
+
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
16802
17228
|
async function login(email, password) {
|
|
16803
17229
|
const response = await client_default.post("/auth/login", { email, password });
|
|
16804
17230
|
await config_default.storeAuthToken(response.token);
|
|
16805
17231
|
return response;
|
|
16806
17232
|
}
|
|
16807
17233
|
async function browserLogin() {
|
|
16808
|
-
const server = http.createServer();
|
|
16809
|
-
await new Promise((resolve) => server.listen(0, resolve));
|
|
16810
|
-
const { port } = server.address();
|
|
16811
|
-
const callbackUrl = `http://localhost:${port}`;
|
|
16812
|
-
const deviceName = os__default.hostname();
|
|
16813
17234
|
const dashboardUrl = config_default.getDashboardUrl();
|
|
16814
17235
|
if (!dashboardUrl) {
|
|
16815
17236
|
throw new Error(
|
|
16816
17237
|
"Dashboard URL is not configured. Please run the command with --dashboard-url option."
|
|
16817
17238
|
);
|
|
16818
17239
|
}
|
|
16819
|
-
const
|
|
17240
|
+
const state = randomBytes(32).toString("base64url");
|
|
17241
|
+
const server = await startCallbackServer({ callbackPath: "/" });
|
|
16820
17242
|
try {
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
(
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
);
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
if (!authProcessed && token) {
|
|
16845
|
-
authProcessed = true;
|
|
16846
|
-
clearTimeout(timeoutId);
|
|
16847
|
-
try {
|
|
16848
|
-
await (token_name && expires_at ? config_default.storePAT(token, token_name, expires_at) : config_default.storeAuthToken(token));
|
|
16849
|
-
sendHtmlResponse(res, 200, HTML_TEMPLATES.success(token_name || void 0));
|
|
16850
|
-
let user;
|
|
16851
|
-
try {
|
|
16852
|
-
user = await getCurrentUser();
|
|
16853
|
-
} catch (userError) {
|
|
16854
|
-
if (isDebug3()) console.error("[relyio-cli][debug] fetch user failed:", userError);
|
|
16855
|
-
user = {
|
|
16856
|
-
id: "unknown",
|
|
16857
|
-
email: "unknown",
|
|
16858
|
-
name: "Unknown User"
|
|
16859
|
-
};
|
|
16860
|
-
}
|
|
16861
|
-
cleanupServer(server);
|
|
16862
|
-
resolve({
|
|
16863
|
-
token,
|
|
16864
|
-
user
|
|
16865
|
-
});
|
|
16866
|
-
} catch (storageError) {
|
|
16867
|
-
if (isDebug3()) console.error("[relyio-cli][debug] token storage:", storageError);
|
|
16868
|
-
sendHtmlResponse(
|
|
16869
|
-
res,
|
|
16870
|
-
500,
|
|
16871
|
-
HTML_TEMPLATES.serverError("Failed to store authentication token")
|
|
16872
|
-
);
|
|
16873
|
-
cleanupServer(server);
|
|
16874
|
-
reject(storageError);
|
|
16875
|
-
}
|
|
16876
|
-
} else if (!authProcessed && params.has("error")) {
|
|
16877
|
-
authProcessed = true;
|
|
16878
|
-
const errorMsg = params.get("error") || "Authentication failed or was canceled.";
|
|
16879
|
-
sendHtmlResponse(res, 400, HTML_TEMPLATES.error(errorMsg));
|
|
16880
|
-
cleanupServer(server);
|
|
16881
|
-
reject(new Error(errorMsg));
|
|
16882
|
-
} else {
|
|
16883
|
-
if (!token && !authProcessed) {
|
|
16884
|
-
if (!res.headersSent) {
|
|
16885
|
-
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
16886
|
-
res.end("Waiting for authentication to complete...");
|
|
16887
|
-
}
|
|
16888
|
-
} else if (authProcessed && !res.headersSent) {
|
|
16889
|
-
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
16890
|
-
res.end("Authentication already processed. You can close this window.");
|
|
16891
|
-
}
|
|
16892
|
-
}
|
|
16893
|
-
} catch (error2) {
|
|
16894
|
-
if (isDebug3()) console.error("[relyio-cli][debug] callback processing:", error2);
|
|
16895
|
-
if (authProcessed) {
|
|
16896
|
-
if (!res.headersSent) {
|
|
16897
|
-
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
16898
|
-
res.end("Error occurred, but authentication was already processed.");
|
|
16899
|
-
}
|
|
16900
|
-
} else {
|
|
16901
|
-
authProcessed = true;
|
|
16902
|
-
if (!res.headersSent) {
|
|
16903
|
-
sendHtmlResponse(
|
|
16904
|
-
res,
|
|
16905
|
-
500,
|
|
16906
|
-
HTML_TEMPLATES.serverError(error2.message || "Unknown error")
|
|
16907
|
-
);
|
|
16908
|
-
}
|
|
16909
|
-
cleanupServer(server);
|
|
16910
|
-
reject(error2);
|
|
16911
|
-
}
|
|
16912
|
-
}
|
|
16913
|
-
});
|
|
16914
|
-
});
|
|
16915
|
-
return tokenData;
|
|
16916
|
-
}
|
|
16917
|
-
function sendHtmlResponse(res, statusCode, html) {
|
|
16918
|
-
if (!res.headersSent) {
|
|
16919
|
-
res.writeHead(statusCode, {
|
|
16920
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
16921
|
-
"Cache-Control": "no-store, no-cache, must-revalidate"
|
|
16922
|
-
});
|
|
16923
|
-
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();
|
|
16924
17266
|
}
|
|
16925
17267
|
}
|
|
16926
|
-
function
|
|
17268
|
+
async function currentUserOrStub() {
|
|
16927
17269
|
try {
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
}
|
|
16932
|
-
const exitTimeout = setTimeout(() => {
|
|
16933
|
-
}, 100);
|
|
16934
|
-
exitTimeout.unref();
|
|
16935
|
-
} catch (error2) {
|
|
16936
|
-
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" };
|
|
16937
17274
|
}
|
|
16938
17275
|
}
|
|
16939
17276
|
async function logout() {
|
|
@@ -17020,18 +17357,17 @@ init_client();
|
|
|
17020
17357
|
async function getProjects() {
|
|
17021
17358
|
return await client_default.get("/projects");
|
|
17022
17359
|
}
|
|
17023
|
-
var
|
|
17024
|
-
var __dirname = path3.dirname(__filename);
|
|
17360
|
+
var __dirname = path5.dirname(fileURLToPath(import.meta.url));
|
|
17025
17361
|
function getTemplatesDir() {
|
|
17026
17362
|
const override = process.env.RELYIO_CLI_TEMPLATES_DIR;
|
|
17027
17363
|
const candidates = [
|
|
17028
|
-
override ?
|
|
17364
|
+
override ? path5.resolve(override) : null,
|
|
17029
17365
|
// dist/index.js → ../templates (built layout)
|
|
17030
|
-
|
|
17031
|
-
// src/
|
|
17032
|
-
|
|
17033
|
-
// src/
|
|
17034
|
-
|
|
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")
|
|
17035
17371
|
].filter((p) => p !== null);
|
|
17036
17372
|
for (const candidate of candidates) {
|
|
17037
17373
|
if (existsSync(candidate)) return candidate;
|
|
@@ -17042,10 +17378,402 @@ function getTemplatesDir() {
|
|
|
17042
17378
|
Set RELYIO_CLI_TEMPLATES_DIR to point at the templates folder, or reinstall the CLI.`
|
|
17043
17379
|
);
|
|
17044
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"];
|
|
17045
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
|
+
}
|
|
17046
17774
|
console.log(heading("Initialize a new RelyIO project"));
|
|
17047
17775
|
if (config_default.isProjectInitialized()) {
|
|
17048
|
-
const { shouldReinitialize } = await
|
|
17776
|
+
const { shouldReinitialize } = await inquirer2.prompt([
|
|
17049
17777
|
{
|
|
17050
17778
|
type: "confirm",
|
|
17051
17779
|
name: "shouldReinitialize",
|
|
@@ -17079,7 +17807,7 @@ async function handleInit(options) {
|
|
|
17079
17807
|
}
|
|
17080
17808
|
}
|
|
17081
17809
|
async function collectProjectInfo(options) {
|
|
17082
|
-
const { directory } = await
|
|
17810
|
+
const { directory } = await inquirer2.prompt([
|
|
17083
17811
|
{
|
|
17084
17812
|
type: "input",
|
|
17085
17813
|
name: "directory",
|
|
@@ -17087,7 +17815,7 @@ async function collectProjectInfo(options) {
|
|
|
17087
17815
|
default: process.cwd()
|
|
17088
17816
|
}
|
|
17089
17817
|
]);
|
|
17090
|
-
const { projectName } = await
|
|
17818
|
+
const { projectName } = await inquirer2.prompt([
|
|
17091
17819
|
{
|
|
17092
17820
|
type: "input",
|
|
17093
17821
|
name: "projectName",
|
|
@@ -17101,12 +17829,7 @@ async function collectProjectInfo(options) {
|
|
|
17101
17829
|
console.error(error(`Templates directory not found at: ${templatesDir}`));
|
|
17102
17830
|
process.exit(1);
|
|
17103
17831
|
}
|
|
17104
|
-
const
|
|
17105
|
-
const templates = dirContents.filter((item) => {
|
|
17106
|
-
const fullPath = path3.join(templatesDir, item);
|
|
17107
|
-
const stats = statSync(fullPath);
|
|
17108
|
-
return stats.isDirectory() && item !== "node_modules" && !item.startsWith(".");
|
|
17109
|
-
}).map((template) => {
|
|
17832
|
+
const templates = schemaTemplateNames(templatesDir).map((template) => {
|
|
17110
17833
|
const description = (() => {
|
|
17111
17834
|
switch (template) {
|
|
17112
17835
|
case "bare": {
|
|
@@ -17134,7 +17857,7 @@ async function collectProjectInfo(options) {
|
|
|
17134
17857
|
}
|
|
17135
17858
|
console.log(heading("\nSelect a template for your project"));
|
|
17136
17859
|
console.log(info("Use \u2191 and \u2193 arrow keys to select, then press Enter\n"));
|
|
17137
|
-
const { selectedExample } = await
|
|
17860
|
+
const { selectedExample } = await inquirer2.prompt([
|
|
17138
17861
|
{
|
|
17139
17862
|
type: "list",
|
|
17140
17863
|
name: "selectedExample",
|
|
@@ -17159,7 +17882,7 @@ async function collectProjectInfo(options) {
|
|
|
17159
17882
|
try {
|
|
17160
17883
|
existingProjects = await getProjects();
|
|
17161
17884
|
if (existingProjects.length > 0) {
|
|
17162
|
-
const { linkType } = await
|
|
17885
|
+
const { linkType } = await inquirer2.prompt([
|
|
17163
17886
|
{
|
|
17164
17887
|
type: "list",
|
|
17165
17888
|
name: "linkType",
|
|
@@ -17173,7 +17896,7 @@ async function collectProjectInfo(options) {
|
|
|
17173
17896
|
]);
|
|
17174
17897
|
if (linkType === "existing") {
|
|
17175
17898
|
createProject = false;
|
|
17176
|
-
const { selectedProject } = await
|
|
17899
|
+
const { selectedProject } = await inquirer2.prompt([
|
|
17177
17900
|
{
|
|
17178
17901
|
type: "list",
|
|
17179
17902
|
name: "selectedProject",
|
|
@@ -17208,12 +17931,12 @@ async function collectProjectInfo(options) {
|
|
|
17208
17931
|
}
|
|
17209
17932
|
function createProjectStructure(context) {
|
|
17210
17933
|
const { directory, example = "bare" } = context;
|
|
17211
|
-
const relyioDir =
|
|
17934
|
+
const relyioDir = path5.resolve(directory, "relyio");
|
|
17212
17935
|
if (!existsSync(relyioDir)) {
|
|
17213
17936
|
mkdirSync(relyioDir, { recursive: true });
|
|
17214
17937
|
}
|
|
17215
17938
|
const templatesDir = getTemplatesDir();
|
|
17216
|
-
const templateDir =
|
|
17939
|
+
const templateDir = path5.resolve(templatesDir, example);
|
|
17217
17940
|
if (!existsSync(templateDir)) {
|
|
17218
17941
|
throw new Error(
|
|
17219
17942
|
`Template '${example}' not found. Available templates: ${existsSync(templatesDir) ? readdirSync(templatesDir).join(", ") : "none"}`
|
|
@@ -17226,7 +17949,7 @@ function createProjectStructure(context) {
|
|
|
17226
17949
|
if (isDirectory) {
|
|
17227
17950
|
if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
|
|
17228
17951
|
for (const childItemName of readdirSync(src)) {
|
|
17229
|
-
copyRecursive(
|
|
17952
|
+
copyRecursive(path5.join(src, childItemName), path5.join(dest, childItemName));
|
|
17230
17953
|
}
|
|
17231
17954
|
} else {
|
|
17232
17955
|
cpSync(src, dest);
|
|
@@ -17242,7 +17965,13 @@ function initCommand(program2) {
|
|
|
17242
17965
|
(options) => handleInit(options),
|
|
17243
17966
|
false
|
|
17244
17967
|
// Don't require auth for init command
|
|
17245
|
-
).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)");
|
|
17246
17975
|
}
|
|
17247
17976
|
init_config();
|
|
17248
17977
|
async function handleLogin(options) {
|
|
@@ -17268,7 +17997,7 @@ async function handleLogin(options) {
|
|
|
17268
17997
|
try {
|
|
17269
17998
|
const user = await auth_default.getCurrentUser();
|
|
17270
17999
|
console.log(warning(`You are already logged in as ${colors.highlight(user.email)}`));
|
|
17271
|
-
const { shouldLogout } = await
|
|
18000
|
+
const { shouldLogout } = await inquirer2.prompt([
|
|
17272
18001
|
{
|
|
17273
18002
|
type: "confirm",
|
|
17274
18003
|
name: "shouldLogout",
|
|
@@ -18578,60 +19307,51 @@ async function pollTaskUntilDone(projectId, taskId, options = {}) {
|
|
|
18578
19307
|
|
|
18579
19308
|
// src/commands/promote.ts
|
|
18580
19309
|
init_config();
|
|
18581
|
-
|
|
18582
|
-
|
|
18583
|
-
|
|
19310
|
+
|
|
19311
|
+
// src/dev/dev-context.ts
|
|
19312
|
+
init_dist();
|
|
19313
|
+
init_dev_handshake();
|
|
18584
19314
|
function devContextPath(projectRoot) {
|
|
18585
|
-
return
|
|
19315
|
+
return path5.join(projectRoot, DEV_CONTEXT_FILE);
|
|
18586
19316
|
}
|
|
18587
19317
|
async function writeDevContext(projectRoot, context) {
|
|
18588
|
-
|
|
18589
|
-
await writeFile(devContextPath(projectRoot), `${JSON.stringify(context, null, 2)}
|
|
18590
|
-
`, "utf8");
|
|
19318
|
+
writeSecretFile(devContextPath(projectRoot), context);
|
|
18591
19319
|
await ensureGitignore(projectRoot);
|
|
18592
19320
|
}
|
|
18593
19321
|
async function readDevContext(projectRoot) {
|
|
19322
|
+
let raw;
|
|
18594
19323
|
try {
|
|
18595
|
-
|
|
18596
|
-
const parsed = JSON.parse(raw);
|
|
18597
|
-
if (typeof parsed.datasetId === "string" && typeof parsed.previewApiKey === "string" && typeof parsed.branchId === "string") {
|
|
18598
|
-
return {
|
|
18599
|
-
datasetId: parsed.datasetId,
|
|
18600
|
-
previewApiKey: parsed.previewApiKey,
|
|
18601
|
-
branchId: parsed.branchId,
|
|
18602
|
-
expiresAt: typeof parsed.expiresAt === "string" ? parsed.expiresAt : null
|
|
18603
|
-
};
|
|
18604
|
-
}
|
|
18605
|
-
return null;
|
|
19324
|
+
raw = await readFile(devContextPath(projectRoot), "utf8");
|
|
18606
19325
|
} catch {
|
|
18607
|
-
return
|
|
19326
|
+
return { state: "absent" };
|
|
18608
19327
|
}
|
|
19328
|
+
return parseDevContextFile(raw, Date.now());
|
|
18609
19329
|
}
|
|
18610
19330
|
async function clearDevContext(projectRoot) {
|
|
18611
19331
|
await rm(devContextPath(projectRoot), { force: true }).catch(() => {
|
|
18612
19332
|
});
|
|
18613
19333
|
}
|
|
18614
19334
|
async function ensureGitignore(projectRoot) {
|
|
18615
|
-
const gitignorePath =
|
|
19335
|
+
const gitignorePath = path5.join(projectRoot, ".gitignore");
|
|
18616
19336
|
if (!existsSync(gitignorePath)) {
|
|
18617
19337
|
await writeFile(
|
|
18618
19338
|
gitignorePath,
|
|
18619
19339
|
`# RelyIO sandbox dev artifact (contains a scoped preview key \u2014 never commit)
|
|
18620
|
-
${
|
|
19340
|
+
${DEV_CONTEXT_FILE}
|
|
18621
19341
|
`,
|
|
18622
19342
|
"utf8"
|
|
18623
19343
|
);
|
|
18624
19344
|
return;
|
|
18625
19345
|
}
|
|
18626
19346
|
const current = await readFile(gitignorePath, "utf8");
|
|
18627
|
-
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}`);
|
|
18628
19348
|
if (alreadyIgnored) return;
|
|
18629
19349
|
const prefix = current.endsWith("\n") || current.length === 0 ? "" : "\n";
|
|
18630
19350
|
await writeFile(
|
|
18631
19351
|
gitignorePath,
|
|
18632
19352
|
`${current}${prefix}
|
|
18633
19353
|
# RelyIO sandbox dev artifact (contains a scoped preview key \u2014 never commit)
|
|
18634
|
-
${
|
|
19354
|
+
${DEV_CONTEXT_FILE}
|
|
18635
19355
|
`,
|
|
18636
19356
|
"utf8"
|
|
18637
19357
|
);
|
|
@@ -18648,12 +19368,13 @@ function requireProjectId() {
|
|
|
18648
19368
|
return projectId;
|
|
18649
19369
|
}
|
|
18650
19370
|
async function resolveActiveSandbox(projectId) {
|
|
19371
|
+
const artifact = await readDevContext(process.cwd());
|
|
18651
19372
|
const sandboxes = await sandbox_default.listSandboxes(projectId);
|
|
18652
|
-
if (sandboxes.length === 0) return null;
|
|
18653
|
-
|
|
18654
|
-
if (
|
|
18655
|
-
const byArtifact = sandboxes.find((s) => s.branch.id ===
|
|
18656
|
-
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 };
|
|
18657
19378
|
}
|
|
18658
19379
|
const gitBranch = getCurrentGitBranch();
|
|
18659
19380
|
if (gitBranch) {
|
|
@@ -18662,12 +19383,25 @@ async function resolveActiveSandbox(projectId) {
|
|
|
18662
19383
|
const parent = branches.find((b) => b.name === gitBranch);
|
|
18663
19384
|
if (parent) {
|
|
18664
19385
|
const byParent = sandboxes.find((s) => s.branch.parentBranchId === parent.id);
|
|
18665
|
-
if (byParent) return byParent;
|
|
19386
|
+
if (byParent) return { sandbox: byParent, artifact };
|
|
18666
19387
|
}
|
|
18667
19388
|
} catch {
|
|
18668
19389
|
}
|
|
18669
19390
|
}
|
|
18670
|
-
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
|
+
}
|
|
18671
19405
|
}
|
|
18672
19406
|
async function resolveTargetBranch(projectId, requested, defaultParentBranchId) {
|
|
18673
19407
|
const branches = await manage_default.getProjectBranches(projectId);
|
|
@@ -18688,14 +19422,16 @@ async function handlePromote(options) {
|
|
|
18688
19422
|
displayHeader("RelyIO Promote", "Flush your sandbox into a real branch");
|
|
18689
19423
|
const projectId = requireProjectId();
|
|
18690
19424
|
const spinner2 = createSpinner("Resolving your active sandbox...");
|
|
18691
|
-
const sandbox = await resolveActiveSandbox(projectId);
|
|
19425
|
+
const { sandbox, artifact } = await resolveActiveSandbox(projectId);
|
|
18692
19426
|
if (!sandbox) {
|
|
18693
19427
|
spinner2.fail("No active sandbox found");
|
|
19428
|
+
reportArtifact(artifact);
|
|
18694
19429
|
displayInfo("Start one with `relyio dev`, then run `relyio promote` again.");
|
|
18695
19430
|
process.exit(1);
|
|
18696
19431
|
return;
|
|
18697
19432
|
}
|
|
18698
19433
|
spinner2.succeed(`Sandbox: ${sandbox.branch.name}`);
|
|
19434
|
+
reportArtifact(artifact);
|
|
18699
19435
|
const target = await resolveTargetBranch(projectId, options.branch, sandbox.branch.parentBranchId);
|
|
18700
19436
|
if (!target) {
|
|
18701
19437
|
displayError(
|
|
@@ -18810,7 +19546,8 @@ async function offerPromoteWhenSandboxActive() {
|
|
|
18810
19546
|
if (!projectId) return false;
|
|
18811
19547
|
let sandbox;
|
|
18812
19548
|
try {
|
|
18813
|
-
|
|
19549
|
+
;
|
|
19550
|
+
({ sandbox } = await resolveActiveSandbox(projectId));
|
|
18814
19551
|
} catch {
|
|
18815
19552
|
return false;
|
|
18816
19553
|
}
|
|
@@ -18983,7 +19720,7 @@ async function handleDeploy(options) {
|
|
|
18983
19720
|
let notes;
|
|
18984
19721
|
if (!json && !options.yes) {
|
|
18985
19722
|
console.log();
|
|
18986
|
-
const { confirmed } = await
|
|
19723
|
+
const { confirmed } = await inquirer2.prompt([
|
|
18987
19724
|
{
|
|
18988
19725
|
type: "confirm",
|
|
18989
19726
|
name: "confirmed",
|
|
@@ -18996,7 +19733,7 @@ async function handleDeploy(options) {
|
|
|
18996
19733
|
return;
|
|
18997
19734
|
}
|
|
18998
19735
|
if (!options.skipNotes) {
|
|
18999
|
-
const answer = await
|
|
19736
|
+
const answer = await inquirer2.prompt([
|
|
19000
19737
|
{
|
|
19001
19738
|
type: "input",
|
|
19002
19739
|
name: "notes",
|
|
@@ -19703,7 +20440,7 @@ function sandboxCommands(program2) {
|
|
|
19703
20440
|
}
|
|
19704
20441
|
|
|
19705
20442
|
// src/commands/version.ts
|
|
19706
|
-
var CLI_VERSION = "0.
|
|
20443
|
+
var CLI_VERSION = "0.3.0" ;
|
|
19707
20444
|
async function handleVersion(_options) {
|
|
19708
20445
|
console.log(heading("RelyIO CLI Version Information"));
|
|
19709
20446
|
const versionInfo = [
|
|
@@ -19786,13 +20523,13 @@ var TerminalWatcher = class extends EventEmitter {
|
|
|
19786
20523
|
ignoreInitial: true,
|
|
19787
20524
|
persistent: true
|
|
19788
20525
|
});
|
|
19789
|
-
this.watcher.on("raw", (event,
|
|
20526
|
+
this.watcher.on("raw", (event, path25) => {
|
|
19790
20527
|
if (event === "change" || event === "rename") {
|
|
19791
|
-
return this.handleFileChange(
|
|
20528
|
+
return this.handleFileChange(path25);
|
|
19792
20529
|
}
|
|
19793
20530
|
});
|
|
19794
|
-
this.watcher.on("add", (
|
|
19795
|
-
this.watcher.on("unlink", (
|
|
20531
|
+
this.watcher.on("add", (path25) => this.handleFileChange(path25));
|
|
20532
|
+
this.watcher.on("unlink", (path25) => this.handleFileChange(path25));
|
|
19796
20533
|
this.watcher.on("error", (error2) => {
|
|
19797
20534
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
19798
20535
|
if (this.options.onError && error2 instanceof Error) {
|
|
@@ -20476,7 +21213,7 @@ async function handleLink(options) {
|
|
|
20476
21213
|
console.log(info("Please create an organization from the dashboard."));
|
|
20477
21214
|
process.exit(1);
|
|
20478
21215
|
}
|
|
20479
|
-
const { organizationId } = await
|
|
21216
|
+
const { organizationId } = await inquirer2.prompt([
|
|
20480
21217
|
{
|
|
20481
21218
|
type: "list",
|
|
20482
21219
|
name: "organizationId",
|
|
@@ -20496,7 +21233,7 @@ async function handleLink(options) {
|
|
|
20496
21233
|
console.log(info("Please create a project first."));
|
|
20497
21234
|
process.exit(1);
|
|
20498
21235
|
}
|
|
20499
|
-
const { projectId } = await
|
|
21236
|
+
const { projectId } = await inquirer2.prompt([
|
|
20500
21237
|
{
|
|
20501
21238
|
type: "list",
|
|
20502
21239
|
name: "projectId",
|
|
@@ -20546,172 +21283,13 @@ init_schema_loader();
|
|
|
20546
21283
|
init_schema();
|
|
20547
21284
|
init_manage();
|
|
20548
21285
|
init_manage_error();
|
|
20549
|
-
|
|
20550
|
-
var registeredPlugins = /* @__PURE__ */ new Map();
|
|
20551
|
-
function registerPlugin(language, load3) {
|
|
20552
|
-
registeredPlugins.set(language, load3);
|
|
20553
|
-
}
|
|
20554
|
-
function asPlugin(module_, describe3) {
|
|
20555
|
-
const candidate = module_?.default ?? module_;
|
|
20556
|
-
const plugin3 = candidate;
|
|
20557
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20558
|
-
throw new Error(`Invalid plugin: ${describe3}`);
|
|
20559
|
-
}
|
|
20560
|
-
return plugin3;
|
|
20561
|
-
}
|
|
20562
|
-
async function loadPlugin(language) {
|
|
20563
|
-
const registered = registeredPlugins.get(language);
|
|
20564
|
-
if (registered) {
|
|
20565
|
-
return asPlugin(await registered(), `registered ${language}`);
|
|
20566
|
-
}
|
|
20567
|
-
if (language === "typescript" || language === "python") {
|
|
20568
|
-
try {
|
|
20569
|
-
const pluginName2 = `@relyio/codegen-${language}`;
|
|
20570
|
-
const pluginModule = await import(
|
|
20571
|
-
/* webpackIgnore: true */
|
|
20572
|
-
pluginName2
|
|
20573
|
-
);
|
|
20574
|
-
const plugin3 = pluginModule.default || pluginModule;
|
|
20575
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20576
|
-
throw new Error(`Invalid built-in plugin: ${language}`);
|
|
20577
|
-
}
|
|
20578
|
-
return plugin3;
|
|
20579
|
-
} catch {
|
|
20580
|
-
try {
|
|
20581
|
-
const relativePath = path3.resolve(
|
|
20582
|
-
path3.dirname(import.meta.url.replace("file://", "")),
|
|
20583
|
-
`../../codegen-${language}/dist/index.js`
|
|
20584
|
-
);
|
|
20585
|
-
const pluginModule = await import(
|
|
20586
|
-
/* webpackIgnore: true */
|
|
20587
|
-
relativePath
|
|
20588
|
-
);
|
|
20589
|
-
const plugin3 = pluginModule.default || pluginModule;
|
|
20590
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20591
|
-
throw new Error(`Invalid built-in plugin: ${language}`);
|
|
20592
|
-
}
|
|
20593
|
-
return plugin3;
|
|
20594
|
-
} catch {
|
|
20595
|
-
throw new Error(
|
|
20596
|
-
`Built-in ${language} generator not found. Please ensure @relyio/codegen-${language} is built.`
|
|
20597
|
-
);
|
|
20598
|
-
}
|
|
20599
|
-
}
|
|
20600
|
-
}
|
|
20601
|
-
const pluginName = `@relyio/codegen-${language}`;
|
|
20602
|
-
try {
|
|
20603
|
-
const pluginModule = await import(
|
|
20604
|
-
/* webpackIgnore: true */
|
|
20605
|
-
pluginName
|
|
20606
|
-
);
|
|
20607
|
-
const plugin3 = pluginModule.default || pluginModule;
|
|
20608
|
-
if (!plugin3 || typeof plugin3.generate !== "function") {
|
|
20609
|
-
throw new Error(`Invalid plugin: ${pluginName}`);
|
|
20610
|
-
}
|
|
20611
|
-
return plugin3;
|
|
20612
|
-
} catch (error2) {
|
|
20613
|
-
const code = error2 !== null && typeof error2 === "object" && "code" in error2 ? String(error2.code) : void 0;
|
|
20614
|
-
if (code === "MODULE_NOT_FOUND") {
|
|
20615
|
-
throw new Error(`Generator "${language}" not installed.
|
|
20616
|
-
Run: pnpm add -D ${pluginName}`);
|
|
20617
|
-
}
|
|
20618
|
-
throw error2;
|
|
20619
|
-
}
|
|
20620
|
-
}
|
|
20621
|
-
async function getAvailablePlugins() {
|
|
20622
|
-
try {
|
|
20623
|
-
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
20624
|
-
const packageJsonModule = await import(packageJsonPath);
|
|
20625
|
-
const packageJson = packageJsonModule.default;
|
|
20626
|
-
const dependencies = {
|
|
20627
|
-
...packageJson.dependencies,
|
|
20628
|
-
...packageJson.devDependencies
|
|
20629
|
-
};
|
|
20630
|
-
const plugins = Object.keys(dependencies).filter((name) => name.startsWith("@relyio/codegen-")).map((name) => name.replace("@relyio/codegen-", ""));
|
|
20631
|
-
if (!plugins.includes("typescript")) {
|
|
20632
|
-
plugins.unshift("typescript");
|
|
20633
|
-
}
|
|
20634
|
-
if (!plugins.includes("python")) {
|
|
20635
|
-
plugins.unshift("python");
|
|
20636
|
-
}
|
|
20637
|
-
return plugins;
|
|
20638
|
-
} catch {
|
|
20639
|
-
return ["typescript", "python"];
|
|
20640
|
-
}
|
|
20641
|
-
}
|
|
20642
|
-
function getSuggestedPlugins() {
|
|
20643
|
-
return {
|
|
20644
|
-
python: "@relyio/codegen-python",
|
|
20645
|
-
go: "@relyio/codegen-go",
|
|
20646
|
-
rust: "@relyio/codegen-rust",
|
|
20647
|
-
java: "@relyio/codegen-java",
|
|
20648
|
-
csharp: "@relyio/codegen-csharp",
|
|
20649
|
-
php: "@relyio/codegen-php",
|
|
20650
|
-
swift: "@relyio/codegen-swift",
|
|
20651
|
-
kotlin: "@relyio/codegen-kotlin"
|
|
20652
|
-
};
|
|
20653
|
-
}
|
|
20654
|
-
async function writeFiles(files, outputDir) {
|
|
20655
|
-
await fs4.mkdir(outputDir, { recursive: true });
|
|
20656
|
-
await Promise.all(
|
|
20657
|
-
files.map(async (file) => {
|
|
20658
|
-
const fullPath = path3.join(outputDir, file.path);
|
|
20659
|
-
const dir = path3.dirname(fullPath);
|
|
20660
|
-
await fs4.mkdir(dir, { recursive: true });
|
|
20661
|
-
await fs4.writeFile(fullPath, file.content, "utf8");
|
|
20662
|
-
})
|
|
20663
|
-
);
|
|
20664
|
-
}
|
|
20665
|
-
var TemplateEngine = class {
|
|
20666
|
-
handlebars;
|
|
20667
|
-
constructor() {
|
|
20668
|
-
this.handlebars = Handlebars.create();
|
|
20669
|
-
this.registerHelpers();
|
|
20670
|
-
}
|
|
20671
|
-
registerHelpers() {
|
|
20672
|
-
this.handlebars.registerHelper("pascalCase", (str) => {
|
|
20673
|
-
if (!str) return "";
|
|
20674
|
-
return str.replaceAll(/(^|_)(\w)/g, (_, __, char) => char.toUpperCase());
|
|
20675
|
-
});
|
|
20676
|
-
this.handlebars.registerHelper("camelCase", (str) => {
|
|
20677
|
-
if (!str) return "";
|
|
20678
|
-
const pascal = str.replaceAll(/(^|_)(\w)/g, (_, __, char) => char.toUpperCase());
|
|
20679
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
20680
|
-
});
|
|
20681
|
-
this.handlebars.registerHelper("snakeCase", (str) => {
|
|
20682
|
-
if (!str) return "";
|
|
20683
|
-
return str.replaceAll(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
20684
|
-
});
|
|
20685
|
-
this.handlebars.registerHelper("kebabCase", (str) => {
|
|
20686
|
-
if (!str) return "";
|
|
20687
|
-
return str.replaceAll(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
20688
|
-
});
|
|
20689
|
-
this.handlebars.registerHelper("plural", (str) => {
|
|
20690
|
-
if (!str) return "";
|
|
20691
|
-
if (str.endsWith("y")) {
|
|
20692
|
-
return str.slice(0, -1) + "ies";
|
|
20693
|
-
}
|
|
20694
|
-
if (str.endsWith("s") || str.endsWith("sh") || str.endsWith("ch")) {
|
|
20695
|
-
return str + "es";
|
|
20696
|
-
}
|
|
20697
|
-
return str + "s";
|
|
20698
|
-
});
|
|
20699
|
-
}
|
|
20700
|
-
compile(template) {
|
|
20701
|
-
const compiledTemplate = this.handlebars.compile(template);
|
|
20702
|
-
return (context) => compiledTemplate(context);
|
|
20703
|
-
}
|
|
20704
|
-
render(template, context) {
|
|
20705
|
-
const compiledTemplate = this.compile(template);
|
|
20706
|
-
return compiledTemplate(context);
|
|
20707
|
-
}
|
|
20708
|
-
};
|
|
20709
|
-
new TemplateEngine();
|
|
21286
|
+
init_dist2();
|
|
20710
21287
|
|
|
20711
21288
|
// src/codegen/built-in-generators.ts
|
|
21289
|
+
init_dist2();
|
|
20712
21290
|
var BUILT_IN_GENERATOR_LOADERS = Object.freeze({
|
|
20713
|
-
typescript: () => Promise.resolve().then(() => (
|
|
20714
|
-
python: () => Promise.resolve().then(() => (
|
|
21291
|
+
typescript: () => Promise.resolve().then(() => (init_dist4(), dist_exports)),
|
|
21292
|
+
python: () => Promise.resolve().then(() => (init_dist5(), dist_exports2))
|
|
20715
21293
|
});
|
|
20716
21294
|
function registerBuiltInGenerators() {
|
|
20717
21295
|
for (const language of BUILT_IN_LANGUAGES) {
|
|
@@ -20722,6 +21300,9 @@ registerBuiltInGenerators();
|
|
|
20722
21300
|
|
|
20723
21301
|
// src/commands/generate-types.ts
|
|
20724
21302
|
init_git();
|
|
21303
|
+
|
|
21304
|
+
// src/utils/codegen-config.ts
|
|
21305
|
+
init_dist2();
|
|
20725
21306
|
var CodegenConfigSchema = z.object({
|
|
20726
21307
|
output: z.string().optional(),
|
|
20727
21308
|
languages: z.array(z.string()).optional(),
|
|
@@ -20736,16 +21317,11 @@ var CodegenConfigSchema = z.object({
|
|
|
20736
21317
|
output: z.string().optional(),
|
|
20737
21318
|
baseModel: z.enum(["pydantic", "dataclass"]).optional(),
|
|
20738
21319
|
includeValidators: z.boolean().optional()
|
|
20739
|
-
}).optional(),
|
|
20740
|
-
go: z.object({
|
|
20741
|
-
output: z.string().optional(),
|
|
20742
|
-
packageName: z.string().optional(),
|
|
20743
|
-
includeValidators: z.boolean().optional()
|
|
20744
21320
|
}).optional()
|
|
20745
21321
|
});
|
|
20746
21322
|
async function loadCodegenConfig(configPath) {
|
|
20747
|
-
const defaultPath =
|
|
20748
|
-
const alternatePath =
|
|
21323
|
+
const defaultPath = path5.join(process.cwd(), "relyio.codegen.yaml");
|
|
21324
|
+
const alternatePath = path5.join(process.cwd(), "relyio.codegen.yml");
|
|
20749
21325
|
let targetPath = configPath;
|
|
20750
21326
|
if (!targetPath) {
|
|
20751
21327
|
try {
|
|
@@ -20789,12 +21365,11 @@ function mergeConfigWithOptions(config, options, language) {
|
|
|
20789
21365
|
moduleFormat: options.moduleFormat || languageConfig.moduleFormat || "esm"
|
|
20790
21366
|
};
|
|
20791
21367
|
}
|
|
20792
|
-
function
|
|
20793
|
-
const supportedLanguages = ["typescript", "python", "go", "rust", "csharp", "java"];
|
|
21368
|
+
function assertSupportedLanguages(languages) {
|
|
20794
21369
|
for (const language of languages) {
|
|
20795
|
-
if (!
|
|
21370
|
+
if (!BUILT_IN_LANGUAGES.includes(language)) {
|
|
20796
21371
|
throw new Error(
|
|
20797
|
-
`Unsupported language: ${language}. Supported languages: ${
|
|
21372
|
+
`Unsupported language: ${language}. Supported languages: ${BUILT_IN_LANGUAGES.join(", ")}`
|
|
20798
21373
|
);
|
|
20799
21374
|
}
|
|
20800
21375
|
}
|
|
@@ -20810,24 +21385,8 @@ function formatSchemaSource3(result) {
|
|
|
20810
21385
|
const count = files.length;
|
|
20811
21386
|
return `YAML (${count} file${count === 1 ? "" : "s"})`;
|
|
20812
21387
|
}
|
|
20813
|
-
|
|
21388
|
+
function handleGenerationError(error2) {
|
|
20814
21389
|
if (error2 instanceof Error) {
|
|
20815
|
-
if (error2.message.includes("not installed")) {
|
|
20816
|
-
const availablePlugins = await getAvailablePlugins();
|
|
20817
|
-
const suggestedPlugins = getSuggestedPlugins();
|
|
20818
|
-
displayInfo("\u{1F4CB} Available generators:");
|
|
20819
|
-
for (const plugin3 of availablePlugins) {
|
|
20820
|
-
const status = plugin3 === "typescript" || plugin3 === "python" ? " (built-in)" : "";
|
|
20821
|
-
displayInfo(` \u2705 ${plugin3}${status}`);
|
|
20822
|
-
}
|
|
20823
|
-
displayInfo("\n\u{1F4BE} Install additional generators with:");
|
|
20824
|
-
for (const [language, packageName] of Object.entries(suggestedPlugins)) {
|
|
20825
|
-
if (!availablePlugins.includes(language)) {
|
|
20826
|
-
displayInfo(` pnpm add -D ${packageName}`);
|
|
20827
|
-
}
|
|
20828
|
-
}
|
|
20829
|
-
return;
|
|
20830
|
-
}
|
|
20831
21390
|
if (error2.message.includes("Schema validation failed") || error2.message.includes("validation error")) {
|
|
20832
21391
|
displayInfo("\n\u{1F4A1} Troubleshooting steps:");
|
|
20833
21392
|
displayInfo("1. Run 'relyio status' to see validation details");
|
|
@@ -20896,14 +21455,16 @@ async function performTypeGeneration(branchName, options, watchMode = false) {
|
|
|
20896
21455
|
`Failed to load configuration: ${error2 instanceof Error ? error2.message : "Unknown error"}`
|
|
20897
21456
|
);
|
|
20898
21457
|
}
|
|
20899
|
-
|
|
20900
|
-
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
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;
|
|
20907
21468
|
}
|
|
20908
21469
|
},
|
|
20909
21470
|
{
|
|
@@ -21041,7 +21602,7 @@ async function performTypeGeneration(branchName, options, watchMode = false) {
|
|
|
21041
21602
|
"Type generation failed",
|
|
21042
21603
|
error2 instanceof Error ? error2.message : "Unknown error"
|
|
21043
21604
|
);
|
|
21044
|
-
|
|
21605
|
+
handleGenerationError(error2);
|
|
21045
21606
|
process.exit(1);
|
|
21046
21607
|
}
|
|
21047
21608
|
}
|
|
@@ -21111,18 +21672,17 @@ function generateTypesCommand(program2) {
|
|
|
21111
21672
|
"after",
|
|
21112
21673
|
`
|
|
21113
21674
|
Examples:
|
|
21114
|
-
$ relyio generate-types
|
|
21115
|
-
$ relyio generate-types -o ./src/types
|
|
21116
|
-
$ relyio generate-types --watch
|
|
21117
|
-
$ relyio generate-types -l python
|
|
21118
|
-
$ 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
|
|
21119
21680
|
|
|
21120
|
-
Supported
|
|
21121
|
-
|
|
21122
|
-
python (py) Python type hints (dataclasses)
|
|
21681
|
+
Supported languages:
|
|
21682
|
+
${BUILT_IN_LANGUAGES.join(", ")}
|
|
21123
21683
|
|
|
21124
21684
|
Configuration:
|
|
21125
|
-
Create codegen.
|
|
21685
|
+
Create relyio.codegen.yaml (or .yml) for advanced options.
|
|
21126
21686
|
`
|
|
21127
21687
|
);
|
|
21128
21688
|
}
|
|
@@ -21299,7 +21859,6 @@ function displayObjectDiff(obj, indent, mode) {
|
|
|
21299
21859
|
const color = THEME3.added ;
|
|
21300
21860
|
const prefix = "+" ;
|
|
21301
21861
|
for (const [key, value] of Object.entries(obj)) {
|
|
21302
|
-
if (key === "_tag") continue;
|
|
21303
21862
|
if (Array.isArray(value)) {
|
|
21304
21863
|
console.log(color(`${indent}${prefix} ${key}:`));
|
|
21305
21864
|
for (const item of value) {
|
|
@@ -22287,7 +22846,7 @@ var THEME7 = {
|
|
|
22287
22846
|
alias: chalk12.cyan,
|
|
22288
22847
|
command: chalk12.yellow
|
|
22289
22848
|
};
|
|
22290
|
-
var ALIAS_FILE =
|
|
22849
|
+
var ALIAS_FILE = path5.join(os.homedir(), ".relyio", "aliases.json");
|
|
22291
22850
|
function readAliases() {
|
|
22292
22851
|
try {
|
|
22293
22852
|
if (fs2.existsSync(ALIAS_FILE)) {
|
|
@@ -22298,7 +22857,7 @@ function readAliases() {
|
|
|
22298
22857
|
return {};
|
|
22299
22858
|
}
|
|
22300
22859
|
function writeAliases(aliases) {
|
|
22301
|
-
const dir =
|
|
22860
|
+
const dir = path5.dirname(ALIAS_FILE);
|
|
22302
22861
|
if (!fs2.existsSync(dir)) {
|
|
22303
22862
|
fs2.mkdirSync(dir, { recursive: true });
|
|
22304
22863
|
}
|
|
@@ -22438,6 +22997,7 @@ function runPreflight() {
|
|
|
22438
22997
|
}
|
|
22439
22998
|
|
|
22440
22999
|
// src/dev/cockpit.tsx
|
|
23000
|
+
init_dev_handshake();
|
|
22441
23001
|
init_app();
|
|
22442
23002
|
init_dev_cockpit_context();
|
|
22443
23003
|
var WrappedChildProcess = class {
|
|
@@ -22452,8 +23012,7 @@ var WrappedChildProcess = class {
|
|
|
22452
23012
|
cwd: this.options.cwd,
|
|
22453
23013
|
env: {
|
|
22454
23014
|
...process.env,
|
|
22455
|
-
|
|
22456
|
-
RELYIO_DEV_API_KEY: this.options.env.RELYIO_DEV_API_KEY
|
|
23015
|
+
...this.options.env
|
|
22457
23016
|
},
|
|
22458
23017
|
stdio: ["ignore", "pipe", "pipe"]
|
|
22459
23018
|
});
|
|
@@ -22678,10 +23237,14 @@ function DevCockpit({
|
|
|
22678
23237
|
command: childCommand.command,
|
|
22679
23238
|
args: childCommand.args,
|
|
22680
23239
|
cwd: projectRoot,
|
|
22681
|
-
|
|
22682
|
-
|
|
22683
|
-
|
|
22684
|
-
|
|
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
|
+
}),
|
|
22685
23248
|
onOutput: (chunk) => setChildLines((previous) => appendChildLines(previous, chunk)),
|
|
22686
23249
|
onExit: () => setChildRunning(false)
|
|
22687
23250
|
});
|
|
@@ -22935,8 +23498,8 @@ function getAuthToken7() {
|
|
|
22935
23498
|
throw new Error("Not authenticated. Run `relyio login` first.");
|
|
22936
23499
|
}
|
|
22937
23500
|
var ConversationsClient = class {
|
|
22938
|
-
async request(method,
|
|
22939
|
-
const url = new URL(`${getGatewayUrl()}${AI_GATEWAY_CONVERSATIONS_PATH}${
|
|
23501
|
+
async request(method, path25, init = {}) {
|
|
23502
|
+
const url = new URL(`${getGatewayUrl()}${AI_GATEWAY_CONVERSATIONS_PATH}${path25}`);
|
|
22940
23503
|
if (init.query) {
|
|
22941
23504
|
for (const [k, v] of Object.entries(init.query)) {
|
|
22942
23505
|
if (v === void 0) continue;
|
|
@@ -22955,7 +23518,7 @@ var ConversationsClient = class {
|
|
|
22955
23518
|
const raw = await response.text().catch(() => "");
|
|
22956
23519
|
const refusal = readError(parseJson(raw));
|
|
22957
23520
|
throw new Error(
|
|
22958
|
-
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(" ")}`
|
|
22959
23522
|
);
|
|
22960
23523
|
}
|
|
22961
23524
|
const text = await response.text();
|
|
@@ -23205,10 +23768,13 @@ async function resolveModelFlag(rawRef) {
|
|
|
23205
23768
|
return "invalid";
|
|
23206
23769
|
}
|
|
23207
23770
|
if (!match.available) {
|
|
23208
|
-
|
|
23209
|
-
|
|
23210
|
-
|
|
23211
|
-
|
|
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
|
+
);
|
|
23212
23778
|
return "invalid";
|
|
23213
23779
|
}
|
|
23214
23780
|
return match.id;
|
|
@@ -24037,7 +24603,7 @@ Examples:
|
|
|
24037
24603
|
}
|
|
24038
24604
|
|
|
24039
24605
|
// src/index.ts
|
|
24040
|
-
var CLI_VERSION3 = "0.
|
|
24606
|
+
var CLI_VERSION3 = "0.3.0" ;
|
|
24041
24607
|
var program = new Command();
|
|
24042
24608
|
program.name("relyio").description("RelyIO CLI - Content Management, Simplified").version(CLI_VERSION3);
|
|
24043
24609
|
registerGlobalOptions(program);
|