@objectstack/cli 2.0.1 → 2.0.3

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @objectstack/cli@2.0.1 build /home/runner/work/spec/spec/packages/cli
2
+ > @objectstack/cli@2.0.3 build /home/runner/work/spec/spec/packages/cli
3
3
  > tsup
4
4
 
5
5
  CLI Building entry: src/bin.ts
@@ -15,10 +15,10 @@
15
15
  ESM Build start
16
16
  CLI Cleaning output folder
17
17
  ESM Build start
18
- ESM dist/index.js 57.98 KB
19
- ESM ⚡️ Build success in 121ms
20
- ESM dist/bin.js 60.60 KB
21
- ESM ⚡️ Build success in 124ms
18
+ ESM dist/bin.js 61.55 KB
19
+ ESM ⚡️ Build success in 148ms
20
+ ESM dist/index.js 58.94 KB
21
+ ESM ⚡️ Build success in 164ms
22
22
  DTS Build start
23
- DTS ⚡️ Build success in 9822ms
23
+ DTS ⚡️ Build success in 7756ms
24
24
  DTS dist/index.d.ts 2.93 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @objectstack/cli
2
2
 
3
+ ## 2.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Patch release for maintenance and stability improvements
8
+ - Updated dependencies
9
+ - @objectstack/spec@2.0.3
10
+ - @objectstack/core@2.0.3
11
+ - @objectstack/objectql@2.0.3
12
+ - @objectstack/runtime@2.0.3
13
+ - @objectstack/rest@2.0.3
14
+ - @objectstack/driver-memory@2.0.3
15
+ - @objectstack/plugin-hono-server@2.0.3
16
+
17
+ ## 2.0.2
18
+
19
+ ### Patch Changes
20
+
21
+ - 1db8559: chore: exclude generated json-schema from git tracking
22
+
23
+ - Add `packages/spec/json-schema/` to `.gitignore` (1277 generated files, 5MB)
24
+ - JSON schema files are still generated during `pnpm build` and included in npm publish via `files` field
25
+ - Fix studio module resolution logic for better compatibility
26
+
27
+ - Updated dependencies [1db8559]
28
+ - @objectstack/spec@2.0.2
29
+ - @objectstack/core@2.0.2
30
+ - @objectstack/objectql@2.0.2
31
+ - @objectstack/driver-memory@2.0.2
32
+ - @objectstack/plugin-hono-server@2.0.2
33
+ - @objectstack/rest@2.0.2
34
+ - @objectstack/runtime@2.0.2
35
+
3
36
  ## 2.0.1
4
37
 
5
38
  ### Patch Changes
package/dist/bin.js CHANGED
@@ -1,13 +1,7 @@
1
1
  #!/usr/bin/env node
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
2
 
9
3
  // src/bin.ts
10
- import { createRequire } from "module";
4
+ import { createRequire as createRequire2 } from "module";
11
5
  import { Command as Command12 } from "commander";
12
6
  import chalk13 from "chalk";
13
7
 
@@ -747,6 +741,8 @@ import { bundleRequire as bundleRequire2 } from "bundle-require";
747
741
  // src/utils/studio.ts
748
742
  import path6 from "path";
749
743
  import fs6 from "fs";
744
+ import { createRequire } from "module";
745
+ import { pathToFileURL } from "url";
750
746
  var STUDIO_PATH = "/_studio";
751
747
  function resolveStudioPath() {
752
748
  const cwd = process.cwd();
@@ -765,14 +761,25 @@ function resolveStudioPath() {
765
761
  }
766
762
  }
767
763
  }
768
- try {
769
- const { createRequire: createRequire2 } = __require("module");
770
- const req = createRequire2(import.meta.url);
771
- const resolved = req.resolve("@objectstack/studio/package.json");
772
- return path6.dirname(resolved);
773
- } catch {
774
- return null;
764
+ const resolutionBases = [
765
+ pathToFileURL(path6.join(cwd, "package.json")).href,
766
+ // consumer workspace
767
+ import.meta.url
768
+ // CLI package itself
769
+ ];
770
+ for (const base of resolutionBases) {
771
+ try {
772
+ const req = createRequire(base);
773
+ const resolved = req.resolve("@objectstack/studio/package.json");
774
+ return path6.dirname(resolved);
775
+ } catch {
776
+ }
777
+ }
778
+ const directPath = path6.join(cwd, "node_modules", "@objectstack", "studio");
779
+ if (fs6.existsSync(path6.join(directPath, "package.json"))) {
780
+ return directPath;
775
781
  }
782
+ return null;
776
783
  }
777
784
  function hasStudioDist(studioPath) {
778
785
  return fs6.existsSync(path6.join(studioPath, "dist", "index.html"));
@@ -979,6 +986,13 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
979
986
  throw new Error(`Failed to import plugin '${plugin}': ${importError.message}`);
980
987
  }
981
988
  }
989
+ if (pluginToLoad && typeof pluginToLoad === "object" && !pluginToLoad.init) {
990
+ try {
991
+ const { AppPlugin } = await import("@objectstack/runtime");
992
+ pluginToLoad = new AppPlugin(pluginToLoad);
993
+ } catch (e) {
994
+ }
995
+ }
982
996
  await kernel.use(pluginToLoad);
983
997
  const pluginName = plugin.name || plugin.constructor?.name || "unnamed";
984
998
  trackPlugin(pluginName);
@@ -1082,6 +1096,28 @@ import chalk8 from "chalk";
1082
1096
  import path8 from "path";
1083
1097
  import fs8 from "fs";
1084
1098
  import { QA as CoreQA } from "@objectstack/core";
1099
+ function resolveGlob(pattern) {
1100
+ if (!pattern.includes("*")) {
1101
+ return fs8.existsSync(pattern) ? [pattern] : [];
1102
+ }
1103
+ const parts = pattern.split(path8.sep.replace("\\", "/"));
1104
+ const segments = pattern.includes("/") ? pattern.split("/") : parts;
1105
+ let baseDir = ".";
1106
+ let globStart = 0;
1107
+ for (let i = 0; i < segments.length; i++) {
1108
+ if (segments[i].includes("*")) {
1109
+ globStart = i;
1110
+ break;
1111
+ }
1112
+ baseDir = i === 0 ? segments[i] : path8.join(baseDir, segments[i]);
1113
+ }
1114
+ if (!fs8.existsSync(baseDir)) return [];
1115
+ const globPortion = segments.slice(globStart).join("/");
1116
+ const regexStr = globPortion.replace(/\./g, "\\.").replace(/\*\*\//g, "(.+/)?").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
1117
+ const regex = new RegExp(`^${regexStr}$`);
1118
+ const entries = fs8.readdirSync(baseDir, { recursive: true, encoding: "utf-8" });
1119
+ return entries.filter((entry) => regex.test(entry.replace(/\\/g, "/"))).map((entry) => path8.join(baseDir, entry)).filter((fullPath) => fs8.statSync(fullPath).isFile());
1120
+ }
1085
1121
  var testCommand = new Command7("test").description("Run Quality Protocol test scenarios against a running server").argument("[files]", 'Glob pattern for test files (e.g. "qa/*.test.json")', "qa/*.test.json").option("--url <url>", "Target base URL", "http://localhost:3000").option("--token <token>", "Authentication token").action(async (filesPattern, options) => {
1086
1122
  console.log(chalk8.bold(`
1087
1123
  \u{1F9EA} ObjectStack Quality Protocol Runner`));
@@ -1089,18 +1125,7 @@ var testCommand = new Command7("test").description("Run Quality Protocol test sc
1089
1125
  console.log(`Target: ${chalk8.blue(options.url)}`);
1090
1126
  const adapter = new CoreQA.HttpTestAdapter(options.url, options.token);
1091
1127
  const runner = new CoreQA.TestRunner(adapter);
1092
- const cwd = process.cwd();
1093
- const testFiles = [];
1094
- if (fs8.existsSync(filesPattern)) {
1095
- testFiles.push(filesPattern);
1096
- } else {
1097
- const dir = path8.dirname(filesPattern);
1098
- const ext = path8.extname(filesPattern);
1099
- if (fs8.existsSync(dir)) {
1100
- const files = fs8.readdirSync(dir).filter((f) => f.endsWith(ext) || f.endsWith(".json"));
1101
- files.forEach((f) => testFiles.push(path8.join(dir, f)));
1102
- }
1103
- }
1128
+ const testFiles = resolveGlob(filesPattern);
1104
1129
  if (testFiles.length === 0) {
1105
1130
  console.warn(chalk8.yellow(`No test files found matching: ${filesPattern}`));
1106
1131
  return;
@@ -1850,7 +1875,7 @@ var generateCommand = new Command11("generate").alias("g").description("Generate
1850
1875
  });
1851
1876
 
1852
1877
  // src/bin.ts
1853
- var require2 = createRequire(import.meta.url);
1878
+ var require2 = createRequire2(import.meta.url);
1854
1879
  var pkg = require2("../package.json");
1855
1880
  process.on("unhandledRejection", (err) => {
1856
1881
  console.error(chalk13.red(`
package/dist/index.js CHANGED
@@ -1,10 +1,3 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
1
  // src/commands/compile.ts
9
2
  import { Command } from "commander";
10
3
  import path2 from "path";
@@ -1300,6 +1293,8 @@ import { bundleRequire as bundleRequire2 } from "bundle-require";
1300
1293
  // src/utils/studio.ts
1301
1294
  import path7 from "path";
1302
1295
  import fs7 from "fs";
1296
+ import { createRequire } from "module";
1297
+ import { pathToFileURL } from "url";
1303
1298
  var STUDIO_PATH = "/_studio";
1304
1299
  function resolveStudioPath() {
1305
1300
  const cwd = process.cwd();
@@ -1318,14 +1313,25 @@ function resolveStudioPath() {
1318
1313
  }
1319
1314
  }
1320
1315
  }
1321
- try {
1322
- const { createRequire } = __require("module");
1323
- const req = createRequire(import.meta.url);
1324
- const resolved = req.resolve("@objectstack/studio/package.json");
1325
- return path7.dirname(resolved);
1326
- } catch {
1327
- return null;
1316
+ const resolutionBases = [
1317
+ pathToFileURL(path7.join(cwd, "package.json")).href,
1318
+ // consumer workspace
1319
+ import.meta.url
1320
+ // CLI package itself
1321
+ ];
1322
+ for (const base of resolutionBases) {
1323
+ try {
1324
+ const req = createRequire(base);
1325
+ const resolved = req.resolve("@objectstack/studio/package.json");
1326
+ return path7.dirname(resolved);
1327
+ } catch {
1328
+ }
1329
+ }
1330
+ const directPath = path7.join(cwd, "node_modules", "@objectstack", "studio");
1331
+ if (fs7.existsSync(path7.join(directPath, "package.json"))) {
1332
+ return directPath;
1328
1333
  }
1334
+ return null;
1329
1335
  }
1330
1336
  function hasStudioDist(studioPath) {
1331
1337
  return fs7.existsSync(path7.join(studioPath, "dist", "index.html"));
@@ -1532,6 +1538,13 @@ var serveCommand = new Command8("serve").description("Start ObjectStack server w
1532
1538
  throw new Error(`Failed to import plugin '${plugin}': ${importError.message}`);
1533
1539
  }
1534
1540
  }
1541
+ if (pluginToLoad && typeof pluginToLoad === "object" && !pluginToLoad.init) {
1542
+ try {
1543
+ const { AppPlugin } = await import("@objectstack/runtime");
1544
+ pluginToLoad = new AppPlugin(pluginToLoad);
1545
+ } catch (e) {
1546
+ }
1547
+ }
1535
1548
  await kernel.use(pluginToLoad);
1536
1549
  const pluginName = plugin.name || plugin.constructor?.name || "unnamed";
1537
1550
  trackPlugin(pluginName);
@@ -1610,6 +1623,28 @@ import chalk11 from "chalk";
1610
1623
  import path9 from "path";
1611
1624
  import fs9 from "fs";
1612
1625
  import { QA as CoreQA } from "@objectstack/core";
1626
+ function resolveGlob(pattern) {
1627
+ if (!pattern.includes("*")) {
1628
+ return fs9.existsSync(pattern) ? [pattern] : [];
1629
+ }
1630
+ const parts = pattern.split(path9.sep.replace("\\", "/"));
1631
+ const segments = pattern.includes("/") ? pattern.split("/") : parts;
1632
+ let baseDir = ".";
1633
+ let globStart = 0;
1634
+ for (let i = 0; i < segments.length; i++) {
1635
+ if (segments[i].includes("*")) {
1636
+ globStart = i;
1637
+ break;
1638
+ }
1639
+ baseDir = i === 0 ? segments[i] : path9.join(baseDir, segments[i]);
1640
+ }
1641
+ if (!fs9.existsSync(baseDir)) return [];
1642
+ const globPortion = segments.slice(globStart).join("/");
1643
+ const regexStr = globPortion.replace(/\./g, "\\.").replace(/\*\*\//g, "(.+/)?").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
1644
+ const regex = new RegExp(`^${regexStr}$`);
1645
+ const entries = fs9.readdirSync(baseDir, { recursive: true, encoding: "utf-8" });
1646
+ return entries.filter((entry) => regex.test(entry.replace(/\\/g, "/"))).map((entry) => path9.join(baseDir, entry)).filter((fullPath) => fs9.statSync(fullPath).isFile());
1647
+ }
1613
1648
  var testCommand = new Command9("test").description("Run Quality Protocol test scenarios against a running server").argument("[files]", 'Glob pattern for test files (e.g. "qa/*.test.json")', "qa/*.test.json").option("--url <url>", "Target base URL", "http://localhost:3000").option("--token <token>", "Authentication token").action(async (filesPattern, options) => {
1614
1649
  console.log(chalk11.bold(`
1615
1650
  \u{1F9EA} ObjectStack Quality Protocol Runner`));
@@ -1617,18 +1652,7 @@ var testCommand = new Command9("test").description("Run Quality Protocol test sc
1617
1652
  console.log(`Target: ${chalk11.blue(options.url)}`);
1618
1653
  const adapter = new CoreQA.HttpTestAdapter(options.url, options.token);
1619
1654
  const runner = new CoreQA.TestRunner(adapter);
1620
- const cwd = process.cwd();
1621
- const testFiles = [];
1622
- if (fs9.existsSync(filesPattern)) {
1623
- testFiles.push(filesPattern);
1624
- } else {
1625
- const dir = path9.dirname(filesPattern);
1626
- const ext = path9.extname(filesPattern);
1627
- if (fs9.existsSync(dir)) {
1628
- const files = fs9.readdirSync(dir).filter((f) => f.endsWith(ext) || f.endsWith(".json"));
1629
- files.forEach((f) => testFiles.push(path9.join(dir, f)));
1630
- }
1631
- }
1655
+ const testFiles = resolveGlob(filesPattern);
1632
1656
  if (testFiles.length === 0) {
1633
1657
  console.warn(chalk11.yellow(`No test files found matching: ${filesPattern}`));
1634
1658
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/cli",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Command Line Interface for ObjectStack Protocol",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -21,20 +21,20 @@
21
21
  "chalk": "^5.3.0",
22
22
  "commander": "^14.0.3",
23
23
  "tsx": "^4.7.1",
24
- "zod": "^3.24.1",
25
- "@objectstack/core": "2.0.1",
26
- "@objectstack/driver-memory": "^2.0.1",
27
- "@objectstack/objectql": "^2.0.1",
28
- "@objectstack/plugin-hono-server": "2.0.1",
29
- "@objectstack/rest": "2.0.1",
30
- "@objectstack/runtime": "^2.0.1",
31
- "@objectstack/spec": "2.0.1"
24
+ "zod": "^4.3.6",
25
+ "@objectstack/core": "2.0.3",
26
+ "@objectstack/driver-memory": "^2.0.3",
27
+ "@objectstack/objectql": "^2.0.3",
28
+ "@objectstack/plugin-hono-server": "2.0.3",
29
+ "@objectstack/rest": "2.0.3",
30
+ "@objectstack/runtime": "^2.0.3",
31
+ "@objectstack/spec": "2.0.3"
32
32
  },
33
33
  "peerDependencies": {
34
- "@objectstack/core": "2.0.1"
34
+ "@objectstack/core": "2.0.3"
35
35
  },
36
36
  "devDependencies": {
37
- "@types/node": "^25.1.0",
37
+ "@types/node": "^25.2.2",
38
38
  "tsup": "^8.0.2",
39
39
  "typescript": "^5.3.3",
40
40
  "vitest": "^4.0.18"
@@ -207,6 +207,17 @@ export const serveCommand = new Command('serve')
207
207
  }
208
208
  }
209
209
 
210
+ // Wrap raw config objects (no init/start) into AppPlugin
211
+ // This handles plugins defined as plain { name, objects, ... } bundles
212
+ if (pluginToLoad && typeof pluginToLoad === 'object' && !pluginToLoad.init) {
213
+ try {
214
+ const { AppPlugin } = await import('@objectstack/runtime');
215
+ pluginToLoad = new AppPlugin(pluginToLoad);
216
+ } catch (e: any) {
217
+ // Fall through to kernel.use which will report the error
218
+ }
219
+ }
220
+
210
221
  await kernel.use(pluginToLoad);
211
222
  const pluginName = plugin.name || plugin.constructor?.name || 'unnamed';
212
223
  trackPlugin(pluginName);
@@ -7,6 +7,51 @@ import fs from 'fs';
7
7
  import { QA as CoreQA } from '@objectstack/core';
8
8
  import { QA } from '@objectstack/spec';
9
9
 
10
+ /**
11
+ * Resolve a glob-like pattern to matching file paths.
12
+ * Supports `*` (single segment wildcard) and `**` (recursive wildcard).
13
+ * Falls back to direct file path if no glob characters are present.
14
+ */
15
+ function resolveGlob(pattern: string): string[] {
16
+ // Direct file path — no wildcards
17
+ if (!pattern.includes('*')) {
18
+ return fs.existsSync(pattern) ? [pattern] : [];
19
+ }
20
+
21
+ // Split pattern into the static base directory and the glob portion
22
+ const parts = pattern.split(path.sep.replace('\\', '/'));
23
+ // Also handle forward-slash on Windows
24
+ const segments = pattern.includes('/') ? pattern.split('/') : parts;
25
+
26
+ let baseDir = '.';
27
+ let globStart = 0;
28
+ for (let i = 0; i < segments.length; i++) {
29
+ if (segments[i].includes('*')) {
30
+ globStart = i;
31
+ break;
32
+ }
33
+ baseDir = i === 0 ? segments[i] : path.join(baseDir, segments[i]);
34
+ }
35
+
36
+ if (!fs.existsSync(baseDir)) return [];
37
+
38
+ // Convert the glob portion into a RegExp
39
+ const globPortion = segments.slice(globStart).join('/');
40
+ const regexStr = globPortion
41
+ .replace(/\./g, '\\.') // escape dots
42
+ .replace(/\*\*\//g, '(.+/)?') // ** matches any directory depth
43
+ .replace(/\*\*/g, '.*') // trailing ** without slash
44
+ .replace(/\*/g, '[^/]*'); // * matches within a single segment
45
+ const regex = new RegExp(`^${regexStr}$`);
46
+
47
+ // Recursively read all files under baseDir
48
+ const entries = fs.readdirSync(baseDir, { recursive: true, encoding: 'utf-8' }) as string[];
49
+ return entries
50
+ .filter(entry => regex.test(entry.replace(/\\/g, '/')))
51
+ .map(entry => path.join(baseDir, entry))
52
+ .filter(fullPath => fs.statSync(fullPath).isFile());
53
+ }
54
+
10
55
  export const testCommand = new Command('test')
11
56
  .description('Run Quality Protocol test scenarios against a running server')
12
57
  .argument('[files]', 'Glob pattern for test files (e.g. "qa/*.test.json")', 'qa/*.test.json')
@@ -21,23 +66,8 @@ export const testCommand = new Command('test')
21
66
  const adapter = new CoreQA.HttpTestAdapter(options.url, options.token);
22
67
  const runner = new CoreQA.TestRunner(adapter);
23
68
 
24
- // 2. Find Files (Simple implementation for now)
25
- // TODO: Use glob
26
- const cwd = process.cwd();
27
- const testFiles: string[] = [];
28
-
29
- // Very basic file finding for demo - assume explicit path or check local dir
30
- if (fs.existsSync(filesPattern)) {
31
- testFiles.push(filesPattern);
32
- } else {
33
- // Simple directory scan
34
- const dir = path.dirname(filesPattern);
35
- const ext = path.extname(filesPattern);
36
- if (fs.existsSync(dir)) {
37
- const files = fs.readdirSync(dir).filter(f => f.endsWith(ext) || f.endsWith('.json'));
38
- files.forEach(f => testFiles.push(path.join(dir, f)));
39
- }
40
- }
69
+ // 2. Find test files using glob-style pattern matching
70
+ const testFiles: string[] = resolveGlob(filesPattern);
41
71
 
42
72
  if (testFiles.length === 0) {
43
73
  console.warn(chalk.yellow(`No test files found matching: ${filesPattern}`));
@@ -9,6 +9,8 @@
9
9
  import path from 'path';
10
10
  import fs from 'fs';
11
11
  import net from 'net';
12
+ import { createRequire } from 'module';
13
+ import { pathToFileURL } from 'url';
12
14
  import { spawn, type ChildProcess } from 'child_process';
13
15
  import chalk from 'chalk';
14
16
 
@@ -48,15 +50,31 @@ export function resolveStudioPath(): string | null {
48
50
  }
49
51
  }
50
52
 
51
- // Fallback: resolve from node_modules
52
- try {
53
- const { createRequire } = require('module');
54
- const req = createRequire(import.meta.url);
55
- const resolved = req.resolve('@objectstack/studio/package.json');
56
- return path.dirname(resolved);
57
- } catch {
58
- return null;
53
+ // Fallback: resolve from node_modules via createRequire.
54
+ // Try the consumer's cwd first (pnpm strict isolation means the CLI's own
55
+ // import.meta.url cannot see the consumer's dependencies), then the CLI itself.
56
+ const resolutionBases = [
57
+ pathToFileURL(path.join(cwd, 'package.json')).href, // consumer workspace
58
+ import.meta.url, // CLI package itself
59
+ ];
60
+
61
+ for (const base of resolutionBases) {
62
+ try {
63
+ const req = createRequire(base);
64
+ const resolved = req.resolve('@objectstack/studio/package.json');
65
+ return path.dirname(resolved);
66
+ } catch {
67
+ // Not resolvable from this base — try next
68
+ }
59
69
  }
70
+
71
+ // Last resort: direct filesystem check in cwd/node_modules
72
+ const directPath = path.join(cwd, 'node_modules', '@objectstack', 'studio');
73
+ if (fs.existsSync(path.join(directPath, 'package.json'))) {
74
+ return directPath;
75
+ }
76
+
77
+ return null;
60
78
  }
61
79
 
62
80
  /**