@squidcloud/cli 1.0.450 → 1.0.452
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
CHANGED
|
@@ -11221,6 +11221,43 @@ const packageJson = __webpack_require__(2108)
|
|
|
11221
11221
|
|
|
11222
11222
|
const version = packageJson.version
|
|
11223
11223
|
|
|
11224
|
+
// Array of tips to display randomly
|
|
11225
|
+
const TIPS = [
|
|
11226
|
+
'🔐 encrypt with Dotenvx: https://dotenvx.com',
|
|
11227
|
+
'🔐 prevent committing .env to code: https://dotenvx.com/precommit',
|
|
11228
|
+
'🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
|
|
11229
|
+
'🤖 agentic secret storage: https://dotenvx.com/as2',
|
|
11230
|
+
'⚡️ secrets for agents: https://dotenvx.com/as2',
|
|
11231
|
+
'🛡️ auth for agents: https://vestauth.com',
|
|
11232
|
+
'🛠️ run anywhere with `dotenvx run -- yourcommand`',
|
|
11233
|
+
'⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
|
|
11234
|
+
'⚙️ enable debug logging with { debug: true }',
|
|
11235
|
+
'⚙️ override existing env vars with { override: true }',
|
|
11236
|
+
'⚙️ suppress all logs with { quiet: true }',
|
|
11237
|
+
'⚙️ write to custom object with { processEnv: myObject }',
|
|
11238
|
+
'⚙️ load multiple .env files with { path: [\'.env.local\', \'.env\'] }'
|
|
11239
|
+
]
|
|
11240
|
+
|
|
11241
|
+
// Get a random tip from the tips array
|
|
11242
|
+
function _getRandomTip () {
|
|
11243
|
+
return TIPS[Math.floor(Math.random() * TIPS.length)]
|
|
11244
|
+
}
|
|
11245
|
+
|
|
11246
|
+
function parseBoolean (value) {
|
|
11247
|
+
if (typeof value === 'string') {
|
|
11248
|
+
return !['false', '0', 'no', 'off', ''].includes(value.toLowerCase())
|
|
11249
|
+
}
|
|
11250
|
+
return Boolean(value)
|
|
11251
|
+
}
|
|
11252
|
+
|
|
11253
|
+
function supportsAnsi () {
|
|
11254
|
+
return process.stdout.isTTY // && process.env.TERM !== 'dumb'
|
|
11255
|
+
}
|
|
11256
|
+
|
|
11257
|
+
function dim (text) {
|
|
11258
|
+
return supportsAnsi() ? `\x1b[2m${text}\x1b[0m` : text
|
|
11259
|
+
}
|
|
11260
|
+
|
|
11224
11261
|
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
|
11225
11262
|
|
|
11226
11263
|
// Parse src into an Object
|
|
@@ -11306,7 +11343,7 @@ function _parseVault (options) {
|
|
|
11306
11343
|
}
|
|
11307
11344
|
|
|
11308
11345
|
function _warn (message) {
|
|
11309
|
-
console.
|
|
11346
|
+
console.error(`[dotenv@${version}][WARN] ${message}`)
|
|
11310
11347
|
}
|
|
11311
11348
|
|
|
11312
11349
|
function _debug (message) {
|
|
@@ -11404,8 +11441,8 @@ function _resolveHome (envPath) {
|
|
|
11404
11441
|
}
|
|
11405
11442
|
|
|
11406
11443
|
function _configVault (options) {
|
|
11407
|
-
const debug =
|
|
11408
|
-
const quiet =
|
|
11444
|
+
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || (options && options.debug))
|
|
11445
|
+
const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || (options && options.quiet))
|
|
11409
11446
|
|
|
11410
11447
|
if (debug || !quiet) {
|
|
11411
11448
|
_log('Loading env from encrypted .env.vault')
|
|
@@ -11426,8 +11463,12 @@ function _configVault (options) {
|
|
|
11426
11463
|
function configDotenv (options) {
|
|
11427
11464
|
const dotenvPath = path.resolve(process.cwd(), '.env')
|
|
11428
11465
|
let encoding = 'utf8'
|
|
11429
|
-
|
|
11430
|
-
|
|
11466
|
+
let processEnv = process.env
|
|
11467
|
+
if (options && options.processEnv != null) {
|
|
11468
|
+
processEnv = options.processEnv
|
|
11469
|
+
}
|
|
11470
|
+
let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || (options && options.debug))
|
|
11471
|
+
let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || (options && options.quiet))
|
|
11431
11472
|
|
|
11432
11473
|
if (options && options.encoding) {
|
|
11433
11474
|
encoding = options.encoding
|
|
@@ -11467,15 +11508,14 @@ function configDotenv (options) {
|
|
|
11467
11508
|
}
|
|
11468
11509
|
}
|
|
11469
11510
|
|
|
11470
|
-
|
|
11471
|
-
if (options && options.processEnv != null) {
|
|
11472
|
-
processEnv = options.processEnv
|
|
11473
|
-
}
|
|
11511
|
+
const populated = DotenvModule.populate(processEnv, parsedAll, options)
|
|
11474
11512
|
|
|
11475
|
-
|
|
11513
|
+
// handle user settings DOTENV_CONFIG_ options inside .env file(s)
|
|
11514
|
+
debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug)
|
|
11515
|
+
quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet)
|
|
11476
11516
|
|
|
11477
11517
|
if (debug || !quiet) {
|
|
11478
|
-
const keysCount = Object.keys(
|
|
11518
|
+
const keysCount = Object.keys(populated).length
|
|
11479
11519
|
const shortPaths = []
|
|
11480
11520
|
for (const filePath of optionPaths) {
|
|
11481
11521
|
try {
|
|
@@ -11489,7 +11529,7 @@ function configDotenv (options) {
|
|
|
11489
11529
|
}
|
|
11490
11530
|
}
|
|
11491
11531
|
|
|
11492
|
-
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')}`)
|
|
11532
|
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(`-- tip: ${_getRandomTip()}`)}`)
|
|
11493
11533
|
}
|
|
11494
11534
|
|
|
11495
11535
|
if (lastError) {
|
|
@@ -11553,6 +11593,7 @@ function decrypt (encrypted, keyStr) {
|
|
|
11553
11593
|
function populate (processEnv, parsed, options = {}) {
|
|
11554
11594
|
const debug = Boolean(options && options.debug)
|
|
11555
11595
|
const override = Boolean(options && options.override)
|
|
11596
|
+
const populated = {}
|
|
11556
11597
|
|
|
11557
11598
|
if (typeof parsed !== 'object') {
|
|
11558
11599
|
const err = new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')
|
|
@@ -11565,6 +11606,7 @@ function populate (processEnv, parsed, options = {}) {
|
|
|
11565
11606
|
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
11566
11607
|
if (override === true) {
|
|
11567
11608
|
processEnv[key] = parsed[key]
|
|
11609
|
+
populated[key] = parsed[key]
|
|
11568
11610
|
}
|
|
11569
11611
|
|
|
11570
11612
|
if (debug) {
|
|
@@ -11576,8 +11618,11 @@ function populate (processEnv, parsed, options = {}) {
|
|
|
11576
11618
|
}
|
|
11577
11619
|
} else {
|
|
11578
11620
|
processEnv[key] = parsed[key]
|
|
11621
|
+
populated[key] = parsed[key]
|
|
11579
11622
|
}
|
|
11580
11623
|
}
|
|
11624
|
+
|
|
11625
|
+
return populated
|
|
11581
11626
|
}
|
|
11582
11627
|
|
|
11583
11628
|
const DotenvModule = {
|
|
@@ -29682,7 +29727,7 @@ exports.AI_PROVIDER_TYPES = [
|
|
|
29682
29727
|
* Public OpenAI chat model names (active models only).
|
|
29683
29728
|
* @category AI
|
|
29684
29729
|
*/
|
|
29685
|
-
exports.OPENAI_CHAT_MODEL_NAMES = ['gpt-5-mini', 'gpt-5-nano', 'gpt-5.2', 'gpt-5.2-pro'];
|
|
29730
|
+
exports.OPENAI_CHAT_MODEL_NAMES = ['gpt-5-mini', 'gpt-5-nano', 'gpt-5.2', 'gpt-5.2-pro', 'gpt-5.4'];
|
|
29686
29731
|
/**
|
|
29687
29732
|
* Public Gemini chat model names (active models only).
|
|
29688
29733
|
* @category AI
|
|
@@ -30167,6 +30212,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
30167
30212
|
exports.extractFromBuffer = extractFromBuffer;
|
|
30168
30213
|
exports.checkFileOrDirExists = checkFileOrDirExists;
|
|
30169
30214
|
exports.assertFileOrDirExists = assertFileOrDirExists;
|
|
30215
|
+
exports.getRuntimeVmLabel = getRuntimeVmLabel;
|
|
30170
30216
|
const assertic_1 = __webpack_require__(3205);
|
|
30171
30217
|
const decompress_1 = __importDefault(__webpack_require__(482));
|
|
30172
30218
|
const fs = __importStar(__webpack_require__(9896));
|
|
@@ -30187,6 +30233,14 @@ async function assertFileOrDirExists(path, errorProvider) {
|
|
|
30187
30233
|
const exists = await checkFileOrDirExists(path);
|
|
30188
30234
|
(0, assertic_1.assertTruthy)(exists, errorProvider || `File not exists: ${path}`);
|
|
30189
30235
|
}
|
|
30236
|
+
function getRuntimeVmLabel() {
|
|
30237
|
+
// @ts-expect-error Bun is not defined in Node.js types
|
|
30238
|
+
if (typeof Bun !== 'undefined') {
|
|
30239
|
+
// @ts-expect-error Bun is not defined in Node.js types
|
|
30240
|
+
return `Bun v${Bun.version}`;
|
|
30241
|
+
}
|
|
30242
|
+
return `Node ${process.version}`;
|
|
30243
|
+
}
|
|
30190
30244
|
|
|
30191
30245
|
|
|
30192
30246
|
/***/ },
|
|
@@ -30400,14 +30454,12 @@ exports.KOTLIN_CONTROLLERS = [
|
|
|
30400
30454
|
'mutation',
|
|
30401
30455
|
'native-query',
|
|
30402
30456
|
'observability',
|
|
30403
|
-
'openapi',
|
|
30404
30457
|
'query',
|
|
30405
30458
|
'queue',
|
|
30406
30459
|
'quota',
|
|
30407
30460
|
'scheduler',
|
|
30408
30461
|
'secret',
|
|
30409
30462
|
'storage',
|
|
30410
|
-
'webhooks',
|
|
30411
30463
|
'ws',
|
|
30412
30464
|
'internal-extraction',
|
|
30413
30465
|
'notification',
|
|
@@ -30564,6 +30616,7 @@ async function getOpenApiSpecAndControllersFromFile(codeDir) {
|
|
|
30564
30616
|
*/
|
|
30565
30617
|
async function populateOpenApiControllersMap(bundleData, codeDir, codeType) {
|
|
30566
30618
|
const openApiControllersMap = {};
|
|
30619
|
+
const openApiSpecsMap = {};
|
|
30567
30620
|
const openApiSpecAndControllers = await getOpenApiSpecAndControllersFromFile(codeDir);
|
|
30568
30621
|
for (const [key, value] of Object.entries(openApiSpecAndControllers.openApiControllersMap)) {
|
|
30569
30622
|
if (key === 'default' && codeType === 'connector') {
|
|
@@ -30572,7 +30625,14 @@ async function populateOpenApiControllersMap(bundleData, codeDir, codeType) {
|
|
|
30572
30625
|
}
|
|
30573
30626
|
openApiControllersMap[key] = JSON.parse(value);
|
|
30574
30627
|
}
|
|
30628
|
+
for (const [key, value] of Object.entries(openApiSpecAndControllers.openApiSpecsMap)) {
|
|
30629
|
+
if (key === 'default' && codeType === 'connector') {
|
|
30630
|
+
continue;
|
|
30631
|
+
}
|
|
30632
|
+
openApiSpecsMap[key] = value;
|
|
30633
|
+
}
|
|
30575
30634
|
bundleData.openApiControllersMap = openApiControllersMap;
|
|
30635
|
+
bundleData.openApiSpecsMap = openApiSpecsMap;
|
|
30576
30636
|
}
|
|
30577
30637
|
|
|
30578
30638
|
|
|
@@ -30879,10 +30939,15 @@ const resolve_1 = __webpack_require__(412);
|
|
|
30879
30939
|
const shell_runner_1 = __webpack_require__(3089);
|
|
30880
30940
|
class TsoaUtils {
|
|
30881
30941
|
constructor() { }
|
|
30882
|
-
|
|
30942
|
+
/**
|
|
30943
|
+
* @param projectDir - Root directory of the user's backend project.
|
|
30944
|
+
* @param supportsDefault - Include the default tsoa spec (pass false for connectors).
|
|
30945
|
+
* @param verbose - Log detailed progress and diagnostic messages.
|
|
30946
|
+
*/
|
|
30947
|
+
static async generateAllSpecs(projectDir, supportsDefault, verbose) {
|
|
30883
30948
|
const specsMap = {};
|
|
30884
30949
|
// Read files in the current directory.
|
|
30885
|
-
let files = await fsPromises.readdir(
|
|
30950
|
+
let files = await fsPromises.readdir(projectDir);
|
|
30886
30951
|
// Filter files matching the TSOA pattern (e.g. "tsoa.json", "tsoa-myapp.json", "tsoaAnother.json").
|
|
30887
30952
|
files = files.filter(file => /^tsoa.*\.json$/.test(file));
|
|
30888
30953
|
// If an exact "tsoa.json" is not present, get the fallback path.
|
|
@@ -30890,7 +30955,7 @@ class TsoaUtils {
|
|
|
30890
30955
|
const hasAnyTsoaFilesProvidedByUser = files.length > 0;
|
|
30891
30956
|
const localBackendModule = await (0, resolve_1.findModulePath)('@squidcloud/local-backend');
|
|
30892
30957
|
if (localBackendModule) {
|
|
30893
|
-
const fallback = path.relative(
|
|
30958
|
+
const fallback = path.relative(projectDir, path.resolve(localBackendModule, '../../tsoa.json'));
|
|
30894
30959
|
if (verbose) {
|
|
30895
30960
|
console.log(`"tsoa.json" not found in current directory. Using fallback: ${fallback}`);
|
|
30896
30961
|
}
|
|
@@ -30901,7 +30966,7 @@ class TsoaUtils {
|
|
|
30901
30966
|
// If this directory contains no '@Route' annotations - there are no tsoa controllers and there is no need to
|
|
30902
30967
|
// run tsoa at all.
|
|
30903
30968
|
if (!hasAnyTsoaFilesProvidedByUser) {
|
|
30904
|
-
const hasTsoaAnnotationsInUserCode = await checkUserCodeUsesTsoa(path.resolve(
|
|
30969
|
+
const hasTsoaAnnotationsInUserCode = await checkUserCodeUsesTsoa(path.resolve(projectDir, 'src'));
|
|
30905
30970
|
if (!hasTsoaAnnotationsInUserCode) {
|
|
30906
30971
|
if (verbose) {
|
|
30907
30972
|
console.log('No TSOA annotations were found in the user code; skipping API generation with TSOA.');
|
|
@@ -30928,14 +30993,16 @@ class TsoaUtils {
|
|
|
30928
30993
|
console.log(`Processing config file: ${file}`);
|
|
30929
30994
|
}
|
|
30930
30995
|
// Use native join to create the folder.
|
|
30931
|
-
|
|
30932
|
-
|
|
30933
|
-
|
|
30996
|
+
// absOutputDir is used for Node fs operations; relOutputDir is passed to tsoa (which runs in projectDir).
|
|
30997
|
+
const relOutputDir = path.join('dist', specName);
|
|
30998
|
+
const absOutputDir = path.resolve(projectDir, relOutputDir);
|
|
30999
|
+
if (!fs.existsSync(absOutputDir)) {
|
|
31000
|
+
fs.mkdirSync(absOutputDir, { recursive: true });
|
|
30934
31001
|
}
|
|
30935
31002
|
// Read the original TSOA config.
|
|
30936
31003
|
let configContent;
|
|
30937
31004
|
try {
|
|
30938
|
-
configContent = await fsPromises.readFile(file, { encoding: 'utf8' });
|
|
31005
|
+
configContent = await fsPromises.readFile(path.resolve(projectDir, file), { encoding: 'utf8' });
|
|
30939
31006
|
}
|
|
30940
31007
|
catch (e) {
|
|
30941
31008
|
if (verbose) {
|
|
@@ -30954,10 +31021,11 @@ class TsoaUtils {
|
|
|
30954
31021
|
throw e;
|
|
30955
31022
|
}
|
|
30956
31023
|
// Override the output directories for both spec and routes.
|
|
31024
|
+
// Use relative paths so tsoa (running in projectDir) resolves them correctly.
|
|
30957
31025
|
config.spec = config.spec || {};
|
|
30958
31026
|
config.routes = config.routes || {};
|
|
30959
|
-
config.spec.outputDirectory =
|
|
30960
|
-
config.routes.routesDir =
|
|
31027
|
+
config.spec.outputDirectory = relOutputDir;
|
|
31028
|
+
config.routes.routesDir = relOutputDir;
|
|
30961
31029
|
// Fix middlewareTemplate path when using fallback from local-backend
|
|
30962
31030
|
if (config.routes.middlewareTemplate && !path.isAbsolute(file)) {
|
|
30963
31031
|
const localBackendModule = await (0, resolve_1.findModulePath)('@squidcloud/local-backend');
|
|
@@ -30979,7 +31047,7 @@ class TsoaUtils {
|
|
|
30979
31047
|
// Rewrite the middlewareTemplate path to be relative to the current working directory.
|
|
30980
31048
|
const templatePath = path.resolve(packageRoot, 'dist/local-backend/openapi-template.hbs');
|
|
30981
31049
|
// Calculate relative path from current working directory (which might be backend/ or test-tsoa/backend/)
|
|
30982
|
-
config.routes.middlewareTemplate = path.relative(
|
|
31050
|
+
config.routes.middlewareTemplate = path.relative(projectDir, templatePath);
|
|
30983
31051
|
if (verbose) {
|
|
30984
31052
|
console.log(`Rewritten middlewareTemplate path to: ${config.routes.middlewareTemplate}`);
|
|
30985
31053
|
console.log(`Template absolute path: ${templatePath}`);
|
|
@@ -30988,27 +31056,28 @@ class TsoaUtils {
|
|
|
30988
31056
|
}
|
|
30989
31057
|
}
|
|
30990
31058
|
}
|
|
30991
|
-
// Use a relative
|
|
30992
|
-
const
|
|
31059
|
+
// Use a relative name for the tsoa command (tsoa runs in projectDir) and absolute path for Node fs operations.
|
|
31060
|
+
const tempConfigName = `temp-tsoa-config-${specName}.json`;
|
|
31061
|
+
const absTempConfigPath = path.resolve(projectDir, tempConfigName);
|
|
30993
31062
|
try {
|
|
30994
|
-
await fsPromises.writeFile(
|
|
31063
|
+
await fsPromises.writeFile(absTempConfigPath, JSON.stringify(config, null, 2), { encoding: 'utf8' });
|
|
30995
31064
|
}
|
|
30996
31065
|
catch (e) {
|
|
30997
31066
|
if (verbose) {
|
|
30998
|
-
console.error(`Error writing temporary config file ${
|
|
31067
|
+
console.error(`Error writing temporary config file ${absTempConfigPath}:`, e);
|
|
30999
31068
|
}
|
|
31000
31069
|
throw e;
|
|
31001
31070
|
}
|
|
31002
31071
|
// Build the TSOA commands (without using -o) that reference the temporary config.
|
|
31003
|
-
const specCmd = `npx tsoa spec -c ${
|
|
31004
|
-
const routesCmd = `npx tsoa routes -c ${
|
|
31072
|
+
const specCmd = `npx tsoa spec -c ${tempConfigName}`;
|
|
31073
|
+
const routesCmd = `npx tsoa routes -c ${tempConfigName}`;
|
|
31005
31074
|
if (verbose) {
|
|
31006
|
-
console.log(`Processing ${file} as "${specName}" with temporary config ${
|
|
31075
|
+
console.log(`Processing ${file} as "${specName}" with temporary config ${tempConfigName}`);
|
|
31007
31076
|
console.log(`Running: ${specCmd}`);
|
|
31008
31077
|
console.log(`Running: ${routesCmd}`);
|
|
31009
31078
|
}
|
|
31010
31079
|
try {
|
|
31011
|
-
await Promise.all([(0, shell_runner_1.runInShell)(specCmd, false,
|
|
31080
|
+
await Promise.all([(0, shell_runner_1.runInShell)(specCmd, false, projectDir), (0, shell_runner_1.runInShell)(routesCmd, false, projectDir)]);
|
|
31012
31081
|
}
|
|
31013
31082
|
catch (e) {
|
|
31014
31083
|
const combinedOutput = e?.combinedOutput;
|
|
@@ -31018,18 +31087,18 @@ class TsoaUtils {
|
|
|
31018
31087
|
console.log(`No controllers found for ${file}, skipping...`);
|
|
31019
31088
|
}
|
|
31020
31089
|
// Clean up the temporary config file before continuing.
|
|
31021
|
-
await fsPromises.unlink(
|
|
31090
|
+
await fsPromises.unlink(absTempConfigPath);
|
|
31022
31091
|
continue;
|
|
31023
31092
|
}
|
|
31024
31093
|
if (verbose) {
|
|
31025
31094
|
console.error(`Error processing ${file}:\n`, errorMessage);
|
|
31026
31095
|
}
|
|
31027
|
-
await fsPromises.unlink(
|
|
31096
|
+
await fsPromises.unlink(absTempConfigPath);
|
|
31028
31097
|
throw new Error(`Failed to process ${file}: ` + errorMessage);
|
|
31029
31098
|
}
|
|
31030
|
-
// Define output file paths.
|
|
31031
|
-
const swaggerOutput = path.join(
|
|
31032
|
-
const routesOutput = path.join(
|
|
31099
|
+
// Define output file paths using absolute paths for Node fs operations.
|
|
31100
|
+
const swaggerOutput = path.join(absOutputDir, 'swagger.json');
|
|
31101
|
+
const routesOutput = path.join(absOutputDir, 'routes.ts');
|
|
31033
31102
|
try {
|
|
31034
31103
|
const swaggerContent = await fsPromises.readFile(swaggerOutput, { encoding: 'utf8' });
|
|
31035
31104
|
const modifiedSwaggerContent = await TsoaUtils.attachCodeSamples(swaggerContent);
|
|
@@ -31043,11 +31112,11 @@ class TsoaUtils {
|
|
|
31043
31112
|
if (verbose) {
|
|
31044
31113
|
console.error(`Error reading generated files for ${file}:`, e);
|
|
31045
31114
|
}
|
|
31046
|
-
await fsPromises.unlink(
|
|
31115
|
+
await fsPromises.unlink(absTempConfigPath);
|
|
31047
31116
|
throw e;
|
|
31048
31117
|
}
|
|
31049
31118
|
// Clean up the temporary config file.
|
|
31050
|
-
await fsPromises.unlink(
|
|
31119
|
+
await fsPromises.unlink(absTempConfigPath);
|
|
31051
31120
|
}
|
|
31052
31121
|
const openApiControllersMap = {};
|
|
31053
31122
|
const openApiSpecsMap = {};
|
|
@@ -31261,12 +31330,38 @@ const version_check_1 = __webpack_require__(4827);
|
|
|
31261
31330
|
// - Default: colors only if TTY (stdout is a terminal).
|
|
31262
31331
|
const isTerminal = process.stdout.isTTY;
|
|
31263
31332
|
const useColorsInOutput = (0, process_env_utils_1.isEnvVarTruthy)('FORCE_COLOR') || (!(0, process_env_utils_1.isEnvVarTruthy)('NO_COLOR') && isTerminal);
|
|
31333
|
+
/**
|
|
31334
|
+
* Add Python source files and requirements.txt to a zip archive.
|
|
31335
|
+
* Used by both Python-only and hybrid builds.
|
|
31336
|
+
*/
|
|
31337
|
+
function addPythonFilesToBundle(zip) {
|
|
31338
|
+
const SKIP_DIRS = new Set(['__pycache__', '__python_deps__']);
|
|
31339
|
+
function addPyFiles(dirPath, zipDir) {
|
|
31340
|
+
for (const entry of fsSync.readdirSync(dirPath, { withFileTypes: true })) {
|
|
31341
|
+
if (entry.name.startsWith('.'))
|
|
31342
|
+
continue;
|
|
31343
|
+
const fullPath = path_1.default.join(dirPath, entry.name);
|
|
31344
|
+
if (entry.isDirectory()) {
|
|
31345
|
+
if (SKIP_DIRS.has(entry.name))
|
|
31346
|
+
continue;
|
|
31347
|
+
addPyFiles(fullPath, path_1.default.join(zipDir, entry.name));
|
|
31348
|
+
}
|
|
31349
|
+
else if (entry.isFile() && !entry.name.endsWith('.pyc')) {
|
|
31350
|
+
zip.addLocalFile(fullPath, zipDir || undefined);
|
|
31351
|
+
}
|
|
31352
|
+
}
|
|
31353
|
+
}
|
|
31354
|
+
addPyFiles('src', '');
|
|
31355
|
+
if (fsSync.existsSync('requirements.txt')) {
|
|
31356
|
+
zip.addLocalFile('requirements.txt');
|
|
31357
|
+
}
|
|
31358
|
+
}
|
|
31264
31359
|
async function build({ verbose, dev, skipVersionCheck }) {
|
|
31265
31360
|
const buildPhaseStart = Date.now();
|
|
31266
31361
|
(0, global_utils_1.enableDebugLogs)(verbose || (0, global_utils_1.isDebugEnabled)());
|
|
31267
31362
|
(0, logpipes_1.installConsoleOverrides)(enable_debug_decorator_utils_1.debugLogFilterPipe);
|
|
31268
31363
|
console.debug(`Starting Squid project build. CLI package version: ${packageJson.version}`);
|
|
31269
|
-
await (0, validate_1.validateSquidProject)();
|
|
31364
|
+
const projectInfo = await (0, validate_1.validateSquidProject)();
|
|
31270
31365
|
// Start version checks in the background if not disabled.
|
|
31271
31366
|
const shouldSkipVersionCheck = skipVersionCheck || (0, process_env_utils_1.isEnvVarTruthy)('SQUID_SKIP_BUILD_TIME_VERSION_CHECK');
|
|
31272
31367
|
// SQUID_CURRENT_CLI_VERSION_OVERRIDE is used for testing.
|
|
@@ -31278,9 +31373,23 @@ async function build({ verbose, dev, skipVersionCheck }) {
|
|
|
31278
31373
|
await fs_1.promises.rm(distPath, { recursive: true, force: true });
|
|
31279
31374
|
}
|
|
31280
31375
|
await fs_1.promises.mkdir(distPath);
|
|
31376
|
+
// Python-only projects: zip src/ + requirements.txt, no webpack.
|
|
31377
|
+
if (projectInfo.isPython && !projectInfo.isHybrid) {
|
|
31378
|
+
console.log((0, logging_1.primary)('Building Python bundle...'));
|
|
31379
|
+
const bundlePath = path_1.default.join(distPath, 'bundle.zip');
|
|
31380
|
+
const zip = new adm_zip_1.default();
|
|
31381
|
+
addPythonFilesToBundle(zip);
|
|
31382
|
+
zip.writeZip(bundlePath);
|
|
31383
|
+
const stats = fsSync.statSync(bundlePath);
|
|
31384
|
+
console.log(`Python bundle created: ${bundlePath} (${(stats.size / 1024).toFixed(1)} KB)`);
|
|
31385
|
+
await (0, version_check_1.displayVersionWarningIfOutdated)(versionCheckPromise);
|
|
31386
|
+
(0, update_skills_1.displaySkillsWarningIfOutdated)();
|
|
31387
|
+
console.debug((0, log_utils_1.timeSince)(buildPhaseStart, 'Build time '));
|
|
31388
|
+
return;
|
|
31389
|
+
}
|
|
31281
31390
|
const isSquidConnector = (0, process_env_utils_1.isEnvVarTruthy)('SQUID_CONNECTOR');
|
|
31282
31391
|
const specsStart = Date.now();
|
|
31283
|
-
const openApiSpecAndControllers = await tsoa_utils_1.TsoaUtils.generateAllSpecs(
|
|
31392
|
+
const openApiSpecAndControllers = await tsoa_utils_1.TsoaUtils.generateAllSpecs(process.cwd(), !isSquidConnector, verbose);
|
|
31284
31393
|
console.debug((0, log_utils_1.timeSince)(specsStart, 'OpenAPI specs generation time '));
|
|
31285
31394
|
await fs_1.promises.writeFile(path_1.default.join(distPath, '', 'openapi-spec-and-controllers.json'), JSON.stringify(openApiSpecAndControllers));
|
|
31286
31395
|
const isUserConfigMode = fsSync.existsSync(resolve_2.USER_WEBPACK_CONFIG_PATH);
|
|
@@ -31321,6 +31430,15 @@ async function build({ verbose, dev, skipVersionCheck }) {
|
|
|
31321
31430
|
resolve();
|
|
31322
31431
|
});
|
|
31323
31432
|
});
|
|
31433
|
+
// For hybrid projects, add Python files to the webpack-produced bundle.
|
|
31434
|
+
if (projectInfo.isHybrid) {
|
|
31435
|
+
console.log('Adding Python files to hybrid bundle...');
|
|
31436
|
+
const zipPath = path_1.default.join(distPath, 'bundle.zip');
|
|
31437
|
+
const zip = new adm_zip_1.default(zipPath);
|
|
31438
|
+
addPythonFilesToBundle(zip);
|
|
31439
|
+
zip.writeZip(zipPath);
|
|
31440
|
+
console.log('Python files added to bundle.');
|
|
31441
|
+
}
|
|
31324
31442
|
// Generate connector metadata if this is a connector build.
|
|
31325
31443
|
if (isSquidConnector) {
|
|
31326
31444
|
console.debug('Generating connector metadata...');
|
|
@@ -31461,6 +31579,7 @@ async function deploy(consoleRegion, appId, bundlePath, apiKey, verbose, direct,
|
|
|
31461
31579
|
(0, logpipes_1.installConsoleOverrides)(enable_debug_decorator_utils_1.debugLogFilterPipe);
|
|
31462
31580
|
const versionCheckPromise = (0, version_check_1.checkCliVersion)(packageJson.version);
|
|
31463
31581
|
if (!direct && !isUserSpecifiedPath && !skipBuild) {
|
|
31582
|
+
// `squid build` handles all project types: TS, Python-only, and hybrid.
|
|
31464
31583
|
console.log('Building code bundle...');
|
|
31465
31584
|
await (0, shell_runner_1.runInShell)('npm run build');
|
|
31466
31585
|
}
|
|
@@ -31708,7 +31827,8 @@ const update_skills_1 = __webpack_require__(7286);
|
|
|
31708
31827
|
const process_utils_1 = __webpack_require__(8251);
|
|
31709
31828
|
const validate_1 = __webpack_require__(2246);
|
|
31710
31829
|
function setupDotEnv(baseDir) {
|
|
31711
|
-
|
|
31830
|
+
const envPath = path_1.default.resolve(baseDir || './', '.env');
|
|
31831
|
+
dotenv.config({ path: envPath });
|
|
31712
31832
|
}
|
|
31713
31833
|
function run() {
|
|
31714
31834
|
(0, yargs_1.default)(process.argv.slice(2))
|
|
@@ -32202,6 +32322,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
32202
32322
|
};
|
|
32203
32323
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
32204
32324
|
exports.start = start;
|
|
32325
|
+
const fs_1 = __webpack_require__(9896);
|
|
32205
32326
|
const fs = __importStar(__webpack_require__(1943));
|
|
32206
32327
|
const path_1 = __importDefault(__webpack_require__(6928));
|
|
32207
32328
|
const resolve_1 = __webpack_require__(412);
|
|
@@ -32213,47 +32334,108 @@ const process_utils_1 = __webpack_require__(8251);
|
|
|
32213
32334
|
const validate_1 = __webpack_require__(2246);
|
|
32214
32335
|
const version_check_1 = __webpack_require__(4827);
|
|
32215
32336
|
async function start() {
|
|
32216
|
-
const
|
|
32337
|
+
const projectInfo = await (0, validate_1.validateSquidProject)();
|
|
32217
32338
|
const versionCheckPromise = (0, version_check_1.checkCliVersion)(cliPackageJson.version);
|
|
32218
32339
|
console.log((0, logging_1.primary)('Please note:'), 'to debug your application, you need to run the "start" npm script in your IDE in debug mode');
|
|
32219
32340
|
await (0, version_check_1.displayVersionWarningIfOutdated)(versionCheckPromise);
|
|
32220
32341
|
(0, update_skills_1.displaySkillsWarningIfOutdated)();
|
|
32221
32342
|
console.log((0, logging_1.primary)('Starting...'));
|
|
32343
|
+
if (projectInfo.isPython && !projectInfo.isHybrid) {
|
|
32344
|
+
await startPython();
|
|
32345
|
+
return;
|
|
32346
|
+
}
|
|
32347
|
+
// For hybrid projects, log Python detection
|
|
32348
|
+
if (projectInfo.isHybrid) {
|
|
32349
|
+
console.log((0, logging_1.primary)('Hybrid project detected:'), 'TypeScript + Python');
|
|
32350
|
+
}
|
|
32351
|
+
const packageJson = projectInfo.packageJson;
|
|
32352
|
+
// Check for local development override
|
|
32353
|
+
const localBackendPath = process.env['SQUID_LOCAL_BACKEND_PATH'];
|
|
32354
|
+
if (localBackendPath) {
|
|
32355
|
+
// Local development mode: use nest start from local-backend with SQUID_BACKEND_PATH
|
|
32356
|
+
console.log('Using local-backend from SQUID_LOCAL_BACKEND_PATH:', localBackendPath);
|
|
32357
|
+
const backendPath = process.cwd();
|
|
32358
|
+
await (0, shell_runner_1.runInShell)(`npx nest start --exec "node -r ts-node/register -r tsconfig-paths/register src/main.ts"`, true, localBackendPath, { SQUID_BACKEND_PATH: backendPath });
|
|
32359
|
+
return;
|
|
32360
|
+
}
|
|
32222
32361
|
const modulePath = await (0, resolve_1.findModulePath)('@squidcloud/local-backend');
|
|
32223
32362
|
if (!modulePath) {
|
|
32224
32363
|
(0, process_utils_1.exitWithError)(validate_1.INVALID_PROJECT_ERROR);
|
|
32225
32364
|
}
|
|
32226
32365
|
if (packageJson.scripts?.['start-squid']) {
|
|
32227
32366
|
await (0, shell_runner_1.runInShell)(`npm run start-squid`);
|
|
32367
|
+
return;
|
|
32228
32368
|
}
|
|
32229
|
-
|
|
32230
|
-
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
|
|
32234
|
-
|
|
32235
|
-
|
|
32236
|
-
|
|
32237
|
-
|
|
32238
|
-
|
|
32239
|
-
console.log((0, logging_1.primary)('Dev mode detected:'), `using local-backend source files: ${mainPath}`);
|
|
32240
|
-
}
|
|
32241
|
-
catch (_) {
|
|
32242
|
-
// Fall back to built version if source files not found
|
|
32243
|
-
mainPath = path_1.default.resolve(modulePath, '../main.js');
|
|
32244
|
-
}
|
|
32369
|
+
// Detect if CLI is running as TypeScript (dev mode)
|
|
32370
|
+
const isDevMode = __filename.endsWith('.ts');
|
|
32371
|
+
let mainPath;
|
|
32372
|
+
// In dev mode, try to use local-backend source files
|
|
32373
|
+
if (isDevMode) {
|
|
32374
|
+
const localBackendSrc = path_1.default.resolve(__dirname, '../../local-backend/src/main.ts');
|
|
32375
|
+
try {
|
|
32376
|
+
await fs.access(localBackendSrc);
|
|
32377
|
+
mainPath = localBackendSrc;
|
|
32378
|
+
console.log((0, logging_1.primary)('Dev mode detected:'), `using local-backend source files: ${mainPath}`);
|
|
32245
32379
|
}
|
|
32246
|
-
|
|
32380
|
+
catch (_) {
|
|
32381
|
+
// Fall back to built version if source files not found
|
|
32247
32382
|
mainPath = path_1.default.resolve(modulePath, '../main.js');
|
|
32248
32383
|
}
|
|
32249
|
-
|
|
32250
|
-
|
|
32251
|
-
|
|
32384
|
+
}
|
|
32385
|
+
else {
|
|
32386
|
+
mainPath = path_1.default.resolve(modulePath, '../main.js');
|
|
32387
|
+
}
|
|
32388
|
+
try {
|
|
32389
|
+
await fs.access(mainPath);
|
|
32390
|
+
const ext = projectInfo.isHybrid ? 'py,ts,js,json' : 'ts,js,json';
|
|
32391
|
+
const ignore = projectInfo.isHybrid ? ' --ignore __python_deps__' : '';
|
|
32392
|
+
await (0, shell_runner_1.runInShell)(`npx nodemon --watch ./src --watch ./.env${ignore} --ext ${ext} --quiet --exec node -r ts-node/register -r tsconfig-paths/register "${mainPath}"`);
|
|
32393
|
+
}
|
|
32394
|
+
catch (_) {
|
|
32395
|
+
(0, process_utils_1.exitWithError)(validate_1.INVALID_PROJECT_ERROR);
|
|
32396
|
+
}
|
|
32397
|
+
}
|
|
32398
|
+
async function startPython() {
|
|
32399
|
+
console.log((0, logging_1.primary)('Python backend detected.'));
|
|
32400
|
+
const backendPath = process.cwd();
|
|
32401
|
+
// Resolve local-backend path (realpathSync handles symlinks from npm link)
|
|
32402
|
+
const modulePath = await (0, resolve_1.findModulePath)('@squidcloud/local-backend');
|
|
32403
|
+
let localBackendDir;
|
|
32404
|
+
// This Dev Mode is referring to running using the internal codebase's CLI, as a Squid engineer.
|
|
32405
|
+
// It is NOT referring to Squid local development.
|
|
32406
|
+
const isDevMode = __filename.endsWith('.ts');
|
|
32407
|
+
if (isDevMode) {
|
|
32408
|
+
localBackendDir = path_1.default.resolve(__dirname, '../../local-backend');
|
|
32409
|
+
}
|
|
32410
|
+
else if (modulePath) {
|
|
32411
|
+
// modulePath points to the package entry (e.g. dist/index.js), resolve to package root
|
|
32412
|
+
localBackendDir = (0, fs_1.realpathSync)(path_1.default.resolve(modulePath, '..'));
|
|
32413
|
+
}
|
|
32414
|
+
else {
|
|
32415
|
+
(0, process_utils_1.exitWithError)(validate_1.INVALID_PROJECT_ERROR);
|
|
32416
|
+
}
|
|
32417
|
+
const mainPath = isDevMode ? path_1.default.resolve(localBackendDir, 'src/main.ts') : path_1.default.resolve(localBackendDir, 'main.js');
|
|
32418
|
+
// Python requirements are installed by the local-backend process (with --target for isolation).
|
|
32419
|
+
// No global pip install needed here.
|
|
32420
|
+
const envVars = {
|
|
32421
|
+
SQUID_BACKEND_PATH: backendPath,
|
|
32422
|
+
};
|
|
32423
|
+
try {
|
|
32424
|
+
await fs.access(mainPath);
|
|
32425
|
+
if (isDevMode) {
|
|
32426
|
+
// Dev mode: run TypeScript source with ts-node
|
|
32427
|
+
const tsconfigPath = path_1.default.resolve(localBackendDir, 'tsconfig.json');
|
|
32428
|
+
envVars['TS_NODE_PROJECT'] = tsconfigPath;
|
|
32429
|
+
await (0, shell_runner_1.runInShell)(`npx nodemon --watch ./src --watch ./.env --ignore __python_deps__ --ext py,ts,js,json --quiet --exec node -r ts-node/register -r tsconfig-paths/register "${mainPath}"`, true, backendPath, envVars);
|
|
32252
32430
|
}
|
|
32253
|
-
|
|
32254
|
-
|
|
32431
|
+
else {
|
|
32432
|
+
// Published package: main.js is already compiled, no ts-node needed
|
|
32433
|
+
await (0, shell_runner_1.runInShell)(`npx nodemon --watch ./src --watch ./.env --ignore __python_deps__ --ext py,ts,js,json --quiet --exec node "${mainPath}"`, true, backendPath, envVars);
|
|
32255
32434
|
}
|
|
32256
32435
|
}
|
|
32436
|
+
catch (_) {
|
|
32437
|
+
(0, process_utils_1.exitWithError)(validate_1.INVALID_PROJECT_ERROR);
|
|
32438
|
+
}
|
|
32257
32439
|
}
|
|
32258
32440
|
|
|
32259
32441
|
|
|
@@ -32589,6 +32771,7 @@ async function reportLocalBackendInitialized(consoleRegion, appId, apiKey) {
|
|
|
32589
32771
|
try {
|
|
32590
32772
|
const headers = new Headers();
|
|
32591
32773
|
headers.append('Authorization', `ApiKey ${apiKey}`);
|
|
32774
|
+
headers.append('Content-Type', 'application/json');
|
|
32592
32775
|
const response = await fetch(url, { method: 'POST', body: JSON.stringify({ appId }), headers });
|
|
32593
32776
|
if (!response.ok) {
|
|
32594
32777
|
const responseText = await response.text();
|
|
@@ -32668,15 +32851,40 @@ exports.validateSquidProject = validateSquidProject;
|
|
|
32668
32851
|
const promises_1 = __importDefault(__webpack_require__(1943));
|
|
32669
32852
|
const process_utils_1 = __webpack_require__(8251);
|
|
32670
32853
|
exports.INVALID_PROJECT_ERROR = 'Please make sure you are running this command in your Squid project directory';
|
|
32854
|
+
async function fileExists(filePath) {
|
|
32855
|
+
try {
|
|
32856
|
+
await promises_1.default.access(filePath);
|
|
32857
|
+
return true;
|
|
32858
|
+
}
|
|
32859
|
+
catch {
|
|
32860
|
+
return false;
|
|
32861
|
+
}
|
|
32862
|
+
}
|
|
32671
32863
|
async function validateSquidProject() {
|
|
32864
|
+
const hasPython = (await fileExists('src/main.py')) || (await fileExists('src/index.py'));
|
|
32865
|
+
const hasTs = await fileExists('src/index.ts');
|
|
32866
|
+
const isHybrid = hasPython && hasTs;
|
|
32867
|
+
const isPythonOnly = hasPython && !hasTs;
|
|
32868
|
+
if (isPythonOnly) {
|
|
32869
|
+
// Python-only projects may not have package.json with start scripts
|
|
32870
|
+
let packageJson = {};
|
|
32871
|
+
try {
|
|
32872
|
+
const raw = await promises_1.default.readFile('package.json', 'utf8');
|
|
32873
|
+
packageJson = JSON.parse(raw);
|
|
32874
|
+
}
|
|
32875
|
+
catch {
|
|
32876
|
+
// No package.json is fine for Python projects
|
|
32877
|
+
}
|
|
32878
|
+
return { packageJson, isPython: true, isHybrid: false };
|
|
32879
|
+
}
|
|
32672
32880
|
try {
|
|
32673
|
-
const
|
|
32674
|
-
const parsedJson = JSON.parse(
|
|
32881
|
+
const packageJsonRaw = await promises_1.default.readFile('package.json', 'utf8');
|
|
32882
|
+
const parsedJson = JSON.parse(packageJsonRaw);
|
|
32675
32883
|
const { scripts } = parsedJson;
|
|
32676
32884
|
if (!scripts?.['start-squid'] && !scripts?.['start']) {
|
|
32677
32885
|
(0, process_utils_1.exitWithError)(exports.INVALID_PROJECT_ERROR);
|
|
32678
32886
|
}
|
|
32679
|
-
return parsedJson;
|
|
32887
|
+
return { packageJson: parsedJson, isPython: hasPython, isHybrid };
|
|
32680
32888
|
}
|
|
32681
32889
|
catch (_) {
|
|
32682
32890
|
(0, process_utils_1.exitWithError)(exports.INVALID_PROJECT_ERROR);
|
|
@@ -37122,7 +37330,7 @@ terminalLink.stderr.isSupported = supports_hyperlinks.stderr;
|
|
|
37122
37330
|
(module) {
|
|
37123
37331
|
|
|
37124
37332
|
"use strict";
|
|
37125
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"dotenv","version":"
|
|
37333
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"dotenv","version":"17.3.1","description":"Loads environment variables from .env file","main":"lib/main.js","types":"lib/main.d.ts","exports":{".":{"types":"./lib/main.d.ts","require":"./lib/main.js","default":"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},"scripts":{"dts-check":"tsc --project tests/types/tsconfig.json","lint":"standard","pretest":"npm run lint && npm run dts-check","test":"tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000","test:coverage":"tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov","prerelease":"npm test","release":"standard-version"},"repository":{"type":"git","url":"git://github.com/motdotla/dotenv.git"},"homepage":"https://github.com/motdotla/dotenv#readme","funding":"https://dotenvx.com","keywords":["dotenv","env",".env","environment","variables","config","settings"],"readmeFilename":"README.md","license":"BSD-2-Clause","devDependencies":{"@types/node":"^18.11.3","decache":"^4.6.2","sinon":"^14.0.1","standard":"^17.0.0","standard-version":"^9.5.0","tap":"^19.2.0","typescript":"^4.8.4"},"engines":{"node":">=12"},"browser":{"fs":false}}');
|
|
37126
37334
|
|
|
37127
37335
|
/***/ },
|
|
37128
37336
|
|
|
@@ -37138,7 +37346,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"seek-bzip","version":"1.0.6",
|
|
|
37138
37346
|
(module) {
|
|
37139
37347
|
|
|
37140
37348
|
"use strict";
|
|
37141
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.
|
|
37349
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.452","description":"The Squid CLI","main":"dist/index.js","scripts":{"start":"node dist/index.js","start-ts":"ts-node -r tsconfig-paths/register src/index.ts","prebuild":"rimraf dist","build":"webpack --mode=production","build:dev":"webpack --mode=development","lint":"eslint","link":"npm run build && chmod 755 dist/index.js && npm link","watch":"webpack --watch","deploy":"npm run build && npm pack --silent | xargs -I {} mv {} package.tgz && npm install -g package.tgz && rm -rf package.tgz","publish:public":"npm run build && npm publish --access public"},"files":["dist/**/*"],"bin":{"squid":"dist/index.js"},"keywords":[],"author":"","license":"ISC","engines":{"node":">=18.0.0"},"dependencies":{"@squidcloud/local-backend":"^1.0.452","adm-zip":"^0.5.16","copy-webpack-plugin":"^12.0.2","decompress":"^4.2.1","logpipes":"^1.11.0","nodemon":"^3.1.9","terser-webpack-plugin":"^5.3.10","ts-loader":"^9.5.1","ts-node":"^10.9.2","tsconfig-paths":"^4.2.0","tsconfig-paths-webpack-plugin":"^4.1.0","webpack":"^5.101.3","zip-webpack-plugin":"^4.0.1"},"devDependencies":{"@types/adm-zip":"^0.5.7","@types/decompress":"^4.2.7","@types/node":"^20.19.9","terminal-link":"^3.0.0"}}');
|
|
37142
37350
|
|
|
37143
37351
|
/***/ }
|
|
37144
37352
|
|
|
@@ -393,8 +393,8 @@ export class MyService extends SquidService {
|
|
|
393
393
|
Handle client connection and disconnection events.
|
|
394
394
|
|
|
395
395
|
```typescript
|
|
396
|
-
import { SquidService, clientConnectionStateHandler
|
|
397
|
-
import { ClientId } from '@squidcloud/client';
|
|
396
|
+
import { SquidService, clientConnectionStateHandler } from '@squidcloud/backend';
|
|
397
|
+
import { ClientConnectionState, ClientId } from '@squidcloud/client';
|
|
398
398
|
|
|
399
399
|
export class MyService extends SquidService {
|
|
400
400
|
@clientConnectionStateHandler()
|
|
@@ -84,8 +84,8 @@ const docRef = collection.doc({ id1: 'part1' }); // id2 generated on insert
|
|
|
84
84
|
## CRUD Operations
|
|
85
85
|
|
|
86
86
|
```typescript
|
|
87
|
-
//
|
|
88
|
-
await userDoc.
|
|
87
|
+
// Upsert (insert or update if the document already exists)
|
|
88
|
+
await userDoc.upsert({ name: 'John', email: 'john@example.com' });
|
|
89
89
|
|
|
90
90
|
// Update (partial)
|
|
91
91
|
await userDoc.update({ name: 'Jane' });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squidcloud/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.452",
|
|
4
4
|
"description": "The Squid CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"node": ">=18.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@squidcloud/local-backend": "^1.0.
|
|
31
|
+
"@squidcloud/local-backend": "^1.0.452",
|
|
32
32
|
"adm-zip": "^0.5.16",
|
|
33
33
|
"copy-webpack-plugin": "^12.0.2",
|
|
34
34
|
"decompress": "^4.2.1",
|