sb-mig 5.6.0-beta.1 → 5.6.0-beta.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.
Files changed (173) hide show
  1. package/README.md +20 -19
  2. package/dist/api/assets/assets.js +2 -15
  3. package/dist/api/auth/auth.types.d.ts +1 -1
  4. package/dist/api/components/components.js +2 -1
  5. package/dist/api/components/components.sync.d.ts +8 -0
  6. package/dist/api/components/components.sync.js +193 -0
  7. package/dist/api/data-migration/component-data-migration.js +2 -2
  8. package/dist/api/datasources/datasource-entries.js +4 -5
  9. package/dist/api/datasources/datasources.d.ts +5 -2
  10. package/dist/api/datasources/datasources.js +42 -35
  11. package/dist/api/datasources/datasources.sync.d.ts +2 -0
  12. package/dist/api/datasources/datasources.sync.js +11 -0
  13. package/dist/api/datasources/datasources.types.d.ts +1 -1
  14. package/dist/api/datasources/index.d.ts +2 -1
  15. package/dist/api/datasources/index.js +2 -1
  16. package/dist/api/managementApi.d.ts +2 -2
  17. package/dist/api/migrate.d.ts +1 -1
  18. package/dist/api/migrate.js +3 -48
  19. package/dist/api/plugins/index.d.ts +2 -1
  20. package/dist/api/plugins/index.js +2 -1
  21. package/dist/api/plugins/plugins.d.ts +7 -2
  22. package/dist/api/plugins/plugins.js +28 -15
  23. package/dist/api/plugins/plugins.sync.d.ts +2 -0
  24. package/dist/api/plugins/plugins.sync.js +11 -0
  25. package/dist/api/roles/index.d.ts +2 -1
  26. package/dist/api/roles/index.js +2 -1
  27. package/dist/api/roles/roles.d.ts +5 -2
  28. package/dist/api/roles/roles.js +34 -11
  29. package/dist/api/roles/roles.sync.d.ts +2 -0
  30. package/dist/api/roles/roles.sync.js +6 -0
  31. package/dist/api/roles/roles.types.d.ts +1 -1
  32. package/dist/api/stories/stories.js +3 -11
  33. package/dist/api/sync/sync.types.d.ts +30 -0
  34. package/dist/api/sync/sync.types.js +1 -0
  35. package/dist/api/testApi.d.ts +2 -2
  36. package/dist/api/utils/helper-functions.d.ts +5 -1
  37. package/dist/api/utils/helper-functions.js +6 -1
  38. package/dist/api/utils/request.d.ts +1 -1
  39. package/dist/api/utils/request.js +11 -2
  40. package/dist/api/utils/resolverTransformations.js +2 -57
  41. package/dist/api-v2/assets/index.d.ts +13 -0
  42. package/dist/api-v2/assets/index.js +25 -0
  43. package/dist/api-v2/auth/index.d.ts +3 -0
  44. package/dist/api-v2/auth/index.js +8 -0
  45. package/dist/api-v2/client.d.ts +13 -0
  46. package/dist/api-v2/client.js +17 -0
  47. package/dist/api-v2/components/index.d.ts +10 -0
  48. package/dist/api-v2/components/index.js +29 -0
  49. package/dist/api-v2/datasources/index.d.ts +8 -0
  50. package/dist/api-v2/datasources/index.js +58 -0
  51. package/dist/api-v2/discover/discover.d.ts +47 -0
  52. package/dist/api-v2/discover/discover.js +328 -0
  53. package/dist/api-v2/discover/index.d.ts +2 -0
  54. package/dist/api-v2/discover/index.js +1 -0
  55. package/dist/api-v2/index.d.ts +19 -0
  56. package/dist/api-v2/index.js +21 -0
  57. package/dist/api-v2/plugins/index.d.ts +9 -0
  58. package/dist/api-v2/plugins/index.js +42 -0
  59. package/dist/api-v2/precompile/index.d.ts +2 -0
  60. package/dist/api-v2/precompile/index.js +1 -0
  61. package/dist/api-v2/precompile/precompile.d.ts +65 -0
  62. package/dist/api-v2/precompile/precompile.js +127 -0
  63. package/dist/api-v2/presets/index.d.ts +13 -0
  64. package/dist/api-v2/presets/index.js +25 -0
  65. package/dist/api-v2/requestConfig.d.ts +5 -0
  66. package/dist/api-v2/requestConfig.js +34 -0
  67. package/dist/api-v2/roles/index.d.ts +5 -0
  68. package/dist/api-v2/roles/index.js +35 -0
  69. package/dist/api-v2/spaces/index.d.ts +7 -0
  70. package/dist/api-v2/spaces/index.js +11 -0
  71. package/dist/api-v2/stories/index.d.ts +34 -0
  72. package/dist/api-v2/stories/index.js +172 -0
  73. package/dist/api-v2/stories/types.d.ts +28 -0
  74. package/dist/api-v2/stories/types.js +1 -0
  75. package/dist/api-v2/sync/index.d.ts +24 -0
  76. package/dist/api-v2/sync/index.js +109 -0
  77. package/dist/api-v2/sync/types.d.ts +1 -0
  78. package/dist/api-v2/sync/types.js +1 -0
  79. package/dist/api-v2/test.d.ts +15 -0
  80. package/dist/api-v2/test.js +21 -0
  81. package/dist/cli/commands/backup.js +7 -3
  82. package/dist/cli/commands/copy.js +2 -2
  83. package/dist/cli/commands/migrate.js +1 -2
  84. package/dist/cli/commands/migrations.js +2 -2
  85. package/dist/cli/commands/remove.js +1 -1
  86. package/dist/cli/commands/revert.js +2 -2
  87. package/dist/cli/commands/sync.js +1 -2
  88. package/dist/cli/index.js +1 -1
  89. package/dist/cli/utils/cli-utils.d.ts +69 -0
  90. package/dist/cli/utils/cli-utils.js +100 -0
  91. package/dist/cli/utils/discover.d.ts +3 -22
  92. package/dist/cli/utils/discover.js +53 -100
  93. package/dist/config/config.d.ts +2 -39
  94. package/dist/config/config.types.d.ts +40 -0
  95. package/dist/config/config.types.js +1 -0
  96. package/dist/config/defaultConfig.d.ts +1 -1
  97. package/dist/config/defaultConfig.js +2 -2
  98. package/dist/utils/array-utils.d.ts +20 -0
  99. package/dist/utils/array-utils.js +20 -0
  100. package/dist/utils/async-utils.d.ts +13 -0
  101. package/dist/utils/async-utils.js +13 -0
  102. package/dist/utils/date-utils.d.ts +14 -0
  103. package/dist/utils/date-utils.js +21 -0
  104. package/dist/utils/files.d.ts +35 -0
  105. package/dist/utils/files.js +57 -2
  106. package/dist/utils/main.d.ts +8 -18
  107. package/dist/utils/main.js +12 -104
  108. package/dist/utils/migrations.d.ts +9 -3
  109. package/dist/utils/object-utils.d.ts +46 -0
  110. package/dist/utils/object-utils.js +71 -0
  111. package/dist/utils/others.d.ts +6 -9
  112. package/dist/utils/others.js +8 -15
  113. package/dist/utils/path-utils.d.ts +89 -0
  114. package/dist/utils/path-utils.js +106 -0
  115. package/dist/utils/pkg.d.ts +16 -2
  116. package/dist/utils/pkg.js +16 -3
  117. package/dist/utils/string-utils.d.ts +33 -0
  118. package/dist/utils/string-utils.js +45 -0
  119. package/dist/utils/transform-utils.d.ts +62 -0
  120. package/dist/utils/transform-utils.js +113 -0
  121. package/dist-cjs/api/auth/auth.js +28 -0
  122. package/dist-cjs/api/auth/auth.types.js +2 -0
  123. package/dist-cjs/api/components/components.js +202 -0
  124. package/dist-cjs/api/components/components.sync.js +199 -0
  125. package/dist-cjs/api/components/components.types.js +2 -0
  126. package/dist-cjs/api/datasources/datasource-entries.js +166 -0
  127. package/dist-cjs/api/datasources/datasources.js +166 -0
  128. package/dist-cjs/api/datasources/datasources.types.js +2 -0
  129. package/dist-cjs/api/plugins/plugins.js +132 -0
  130. package/dist-cjs/api/plugins/plugins.types.js +2 -0
  131. package/dist-cjs/api/presets/componentPresets.js +25 -0
  132. package/dist-cjs/api/presets/presets.js +92 -0
  133. package/dist-cjs/api/presets/presets.types.js +2 -0
  134. package/dist-cjs/api/presets/resolvePresets.js +49 -0
  135. package/dist-cjs/api/roles/roles.js +131 -0
  136. package/dist-cjs/api/roles/roles.types.js +2 -0
  137. package/dist-cjs/api/spaces/spaces.js +34 -0
  138. package/dist-cjs/api/spaces/spaces.types.js +2 -0
  139. package/dist-cjs/api/stories/stories.js +214 -0
  140. package/dist-cjs/api/stories/stories.types.js +2 -0
  141. package/dist-cjs/api/sync/sync.types.js +2 -0
  142. package/dist-cjs/api/utils/request.js +48 -0
  143. package/dist-cjs/api/utils/resolvers.types.js +2 -0
  144. package/dist-cjs/api-v2/assets/index.js +30 -0
  145. package/dist-cjs/api-v2/auth/index.js +12 -0
  146. package/dist-cjs/api-v2/client.js +23 -0
  147. package/dist-cjs/api-v2/components/index.js +40 -0
  148. package/dist-cjs/api-v2/datasources/index.js +64 -0
  149. package/dist-cjs/api-v2/discover/discover.js +368 -0
  150. package/dist-cjs/api-v2/discover/index.js +9 -0
  151. package/dist-cjs/api-v2/index.js +60 -0
  152. package/dist-cjs/api-v2/plugins/index.js +49 -0
  153. package/dist-cjs/api-v2/precompile/index.js +7 -0
  154. package/dist-cjs/api-v2/precompile/precompile.js +136 -0
  155. package/dist-cjs/api-v2/presets/index.js +33 -0
  156. package/dist-cjs/api-v2/requestConfig.js +37 -0
  157. package/dist-cjs/api-v2/roles/index.js +41 -0
  158. package/dist-cjs/api-v2/spaces/index.js +16 -0
  159. package/dist-cjs/api-v2/stories/index.js +180 -0
  160. package/dist-cjs/api-v2/stories/types.js +2 -0
  161. package/dist-cjs/api-v2/sync/index.js +115 -0
  162. package/dist-cjs/api-v2/sync/types.js +2 -0
  163. package/dist-cjs/api-v2/test.js +25 -0
  164. package/dist-cjs/config/config.types.js +2 -0
  165. package/dist-cjs/config/constants.js +29 -0
  166. package/dist-cjs/package.json +3 -0
  167. package/dist-cjs/utils/array-utils.js +24 -0
  168. package/dist-cjs/utils/logger.js +32 -0
  169. package/dist-cjs/utils/object-utils.js +77 -0
  170. package/dist-cjs/utils/path-utils.js +115 -0
  171. package/package.json +43 -27
  172. package/dist/utils/pkg-require.d.ts +0 -2
  173. package/dist/utils/pkg-require.js +0 -4
@@ -0,0 +1,29 @@
1
+ import { createComponent as apiCreateComponent, getAllComponents as apiGetAllComponents, getComponent as apiGetComponent, getAllComponentsGroups as apiGetAllComponentsGroups, createComponentsGroup as apiCreateComponentsGroup, getComponentsGroup as apiGetComponentsGroup, removeComponent as apiRemoveComponent, removeComponentGroup as apiRemoveComponentGroup, updateComponent as apiUpdateComponent, } from "../../api/components/components.js";
2
+ import { toRequestConfig } from "../requestConfig.js";
3
+ export async function getAllComponents(client) {
4
+ return await apiGetAllComponents(toRequestConfig(client));
5
+ }
6
+ export async function getComponent(client, componentName) {
7
+ return await apiGetComponent(componentName, toRequestConfig(client));
8
+ }
9
+ export async function getAllComponentsGroups(client) {
10
+ return await apiGetAllComponentsGroups(toRequestConfig(client));
11
+ }
12
+ export async function getComponentsGroup(client, groupName) {
13
+ return await apiGetComponentsGroup(groupName, toRequestConfig(client));
14
+ }
15
+ export async function createComponentsGroup(client, groupName) {
16
+ return await apiCreateComponentsGroup(groupName, toRequestConfig(client));
17
+ }
18
+ export async function removeComponentGroup(client, componentGroup) {
19
+ return await apiRemoveComponentGroup(componentGroup, toRequestConfig(client));
20
+ }
21
+ export async function removeComponent(client, component) {
22
+ return await apiRemoveComponent(component, toRequestConfig(client));
23
+ }
24
+ export async function createComponent(client, component, presets = false) {
25
+ return await apiCreateComponent(component, presets, toRequestConfig(client));
26
+ }
27
+ export async function updateComponent(client, component, presets = false) {
28
+ return await apiUpdateComponent(component, presets, toRequestConfig(client));
29
+ }
@@ -0,0 +1,8 @@
1
+ import type { ApiClient } from "../client.js";
2
+ export declare function getAllDatasources(client: ApiClient): Promise<any>;
3
+ export declare function getDatasource(client: ApiClient, datasourceName: string): Promise<any>;
4
+ export declare function createDatasource(client: ApiClient, datasource: any): Promise<any>;
5
+ export declare function updateDatasource(client: ApiClient, args: {
6
+ datasource: any;
7
+ datasourceToBeUpdated: any;
8
+ }): Promise<any>;
@@ -0,0 +1,58 @@
1
+ import { getAllItemsWithPagination } from "../../api/utils/request.js";
2
+ export async function getAllDatasources(client) {
3
+ const spaceId = client.spaceId;
4
+ return getAllItemsWithPagination({
5
+ apiFn: ({ per_page, page }) => client.sbApi.get(`spaces/${spaceId}/datasources/`, {
6
+ per_page,
7
+ page,
8
+ }),
9
+ params: { spaceId },
10
+ itemsKey: "datasources",
11
+ });
12
+ }
13
+ export async function getDatasource(client, datasourceName) {
14
+ const datasources = await getAllDatasources(client);
15
+ const match = datasources.filter((d) => d.name === datasourceName);
16
+ if (Array.isArray(match) && match.length === 0)
17
+ return false;
18
+ return match;
19
+ }
20
+ export async function createDatasource(client, datasource) {
21
+ const spaceId = client.spaceId;
22
+ const finalDatasource = {
23
+ name: datasource.name,
24
+ slug: datasource.slug,
25
+ dimensions: [...(datasource.dimensions ?? [])],
26
+ dimensions_attributes: [...(datasource.dimensions ?? [])],
27
+ };
28
+ return client.sbApi
29
+ .post(`spaces/${spaceId}/datasources/`, {
30
+ datasource: finalDatasource,
31
+ })
32
+ .then((res) => res.data);
33
+ }
34
+ export async function updateDatasource(client, args) {
35
+ const spaceId = client.spaceId;
36
+ const { datasource, datasourceToBeUpdated } = args;
37
+ const dimensionsToCreate = (datasource.dimensions ?? []).filter((dimension) => {
38
+ const isDimensionInRemoteDatasource = datasourceToBeUpdated.dimensions?.find((d) => dimension.name === d.name);
39
+ return !isDimensionInRemoteDatasource;
40
+ });
41
+ return client.sbApi
42
+ .put(`spaces/${spaceId}/datasources/${datasourceToBeUpdated.id}`, {
43
+ datasource: {
44
+ id: datasourceToBeUpdated.id,
45
+ name: datasource.name,
46
+ slug: datasource.slug,
47
+ dimensions: [
48
+ ...(datasourceToBeUpdated.dimensions ?? []),
49
+ ...dimensionsToCreate,
50
+ ],
51
+ dimensions_attributes: [
52
+ ...(datasourceToBeUpdated.dimensions ?? []),
53
+ ...dimensionsToCreate,
54
+ ],
55
+ },
56
+ })
57
+ .then((res) => res.data);
58
+ }
@@ -0,0 +1,47 @@
1
+ export interface DiscoveredResource {
2
+ name: string;
3
+ filePath: string;
4
+ type: "local" | "external";
5
+ }
6
+ export interface LoadedResource {
7
+ name: string;
8
+ filePath: string;
9
+ data: any;
10
+ error?: string;
11
+ }
12
+ /**
13
+ * Load the content of a resource file (.sb.js, .datasource.js, etc.)
14
+ * Uses dynamic import to load ES modules and CommonJS
15
+ */
16
+ export declare function loadResourceContent(filePath: string): Promise<any>;
17
+ /**
18
+ * Load multiple resources by file path
19
+ */
20
+ export declare function loadResources(filePaths: string[]): Promise<LoadedResource[]>;
21
+ /**
22
+ * Options for component discovery
23
+ */
24
+ export interface DiscoverComponentsOptions {
25
+ /** File extensions to search for (default: [".sb.ts", ".sb.cjs"]) */
26
+ extensions?: string[];
27
+ /** Whether to include external (node_modules) components (default: true) */
28
+ includeExternal?: boolean;
29
+ /** Maximum depth to scan (default: 20, prevents runaway scanning) */
30
+ maxDepth?: number;
31
+ }
32
+ /**
33
+ * Discover components in the working directory
34
+ * Prefers .ts for local files and .cjs for external (node_modules) files
35
+ * to avoid duplicates when both ESM and CJS versions exist
36
+ *
37
+ * Security: Stays within project bounds and doesn't follow symlinks outside
38
+ */
39
+ export declare function discoverComponents(workingDir: string, options?: DiscoverComponentsOptions): Promise<DiscoveredResource[]>;
40
+ /**
41
+ * Discover datasources in the working directory
42
+ */
43
+ export declare function discoverDatasources(workingDir: string): Promise<DiscoveredResource[]>;
44
+ /**
45
+ * Discover roles in the working directory
46
+ */
47
+ export declare function discoverRoles(workingDir: string): Promise<DiscoveredResource[]>;
@@ -0,0 +1,328 @@
1
+ import { readdir, stat, readFile, realpath } from "fs/promises";
2
+ import { join, resolve } from "path";
3
+ import { pathToFileURL } from "url";
4
+ /**
5
+ * Load the content of a resource file (.sb.js, .datasource.js, etc.)
6
+ * Uses dynamic import to load ES modules and CommonJS
7
+ */
8
+ export async function loadResourceContent(filePath) {
9
+ try {
10
+ // Use dynamic import which works for both ESM and CJS
11
+ const fileUrl = pathToFileURL(filePath).href;
12
+ const module = await import(fileUrl);
13
+ return module.default || module;
14
+ }
15
+ catch (error) {
16
+ throw new Error(`Failed to load ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
17
+ }
18
+ }
19
+ /**
20
+ * Load multiple resources by file path
21
+ */
22
+ export async function loadResources(filePaths) {
23
+ const results = [];
24
+ for (const filePath of filePaths) {
25
+ const name = filePath
26
+ .split("/")
27
+ .pop()
28
+ ?.replace(/\.sb\.(js|cjs|mjs|ts)$/, "")
29
+ .replace(/\.(datasource|roles)\.(js|cjs|ts)$/, "")
30
+ .replace(/\.sb\.(datasource|roles)\.(js|cjs|ts)$/, "") ||
31
+ "unknown";
32
+ try {
33
+ const data = await loadResourceContent(filePath);
34
+ results.push({ name, filePath, data });
35
+ }
36
+ catch (error) {
37
+ results.push({
38
+ name,
39
+ filePath,
40
+ data: null,
41
+ error: error instanceof Error ? error.message : String(error),
42
+ });
43
+ }
44
+ }
45
+ return results;
46
+ }
47
+ /**
48
+ * Read componentsDirectories from storyblok.config.js if it exists
49
+ */
50
+ async function readComponentDirectories(workingDir) {
51
+ const configFiles = [
52
+ "storyblok.config.js",
53
+ "storyblok.config.cjs",
54
+ "storyblok.config.mjs",
55
+ ];
56
+ for (const configFile of configFiles) {
57
+ try {
58
+ const configPath = join(workingDir, configFile);
59
+ const configContent = await readFile(configPath, "utf-8");
60
+ const match = configContent.match(/componentsDirectories\s*:\s*\[([\s\S]*?)\]/);
61
+ if (match && match[1]) {
62
+ const dirsMatch = match[1].match(/['"]([^'"]+)['"]/g);
63
+ if (dirsMatch) {
64
+ return dirsMatch.map((d) => d.replace(/['"]/g, ""));
65
+ }
66
+ }
67
+ break;
68
+ }
69
+ catch {
70
+ // Config file doesn't exist, continue
71
+ }
72
+ }
73
+ return ["src", "components", "storyblok"];
74
+ }
75
+ /**
76
+ * Check if a path is within the project directory
77
+ * Resolves symlinks and ensures we don't escape the project bounds
78
+ */
79
+ async function isWithinProject(targetPath, projectRoot) {
80
+ try {
81
+ // Resolve both paths to handle symlinks
82
+ const resolvedTarget = await realpath(targetPath);
83
+ const resolvedRoot = await realpath(projectRoot);
84
+ // Check if target is within project root
85
+ return (resolvedTarget.startsWith(resolvedRoot + "/") ||
86
+ resolvedTarget === resolvedRoot);
87
+ }
88
+ catch {
89
+ // If we can't resolve the path, assume it's not safe
90
+ return false;
91
+ }
92
+ }
93
+ /**
94
+ * Discover components in the working directory
95
+ * Prefers .ts for local files and .cjs for external (node_modules) files
96
+ * to avoid duplicates when both ESM and CJS versions exist
97
+ *
98
+ * Security: Stays within project bounds and doesn't follow symlinks outside
99
+ */
100
+ export async function discoverComponents(workingDir, options) {
101
+ const components = [];
102
+ // Priority order: .ts first (local), then .cjs (for node_modules)
103
+ // Skip .js and .mjs to avoid duplicates
104
+ const extensions = options?.extensions ?? [".sb.ts", ".sb.cjs"];
105
+ const includeExternal = options?.includeExternal ?? true;
106
+ const maxDepth = options?.maxDepth ?? 20;
107
+ // Resolve the project root for security checks
108
+ const projectRoot = resolve(workingDir);
109
+ const componentDirs = await readComponentDirectories(workingDir);
110
+ const scanDir = async (dir, isExternal, depth) => {
111
+ // Prevent excessive depth
112
+ if (depth > maxDepth) {
113
+ return;
114
+ }
115
+ // Security: Ensure we're still within project bounds
116
+ if (!(await isWithinProject(dir, projectRoot))) {
117
+ return;
118
+ }
119
+ try {
120
+ const entries = await readdir(dir, { withFileTypes: true });
121
+ for (const entry of entries) {
122
+ const fullPath = join(dir, entry.name);
123
+ if (entry.isDirectory()) {
124
+ // Skip common non-source directories
125
+ if (entry.name === ".git" ||
126
+ entry.name === ".next" ||
127
+ entry.name === "dist" ||
128
+ entry.name === ".cache" ||
129
+ entry.name === "coverage") {
130
+ continue;
131
+ }
132
+ // Skip node_modules entirely if not including external
133
+ if (entry.name === "node_modules" && !includeExternal) {
134
+ continue;
135
+ }
136
+ const isNowExternal = isExternal || entry.name === "node_modules";
137
+ await scanDir(fullPath, isNowExternal, depth + 1);
138
+ }
139
+ else if (entry.isFile()) {
140
+ // Skip external files if not including them
141
+ if (isExternal && !includeExternal) {
142
+ continue;
143
+ }
144
+ for (const ext of extensions) {
145
+ if (entry.name.endsWith(ext) &&
146
+ !entry.name.startsWith("_")) {
147
+ const componentName = entry.name.replace(ext, "");
148
+ components.push({
149
+ name: componentName,
150
+ filePath: fullPath,
151
+ type: isExternal ? "external" : "local",
152
+ });
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }
159
+ catch {
160
+ // Directory doesn't exist or can't be read
161
+ }
162
+ };
163
+ for (const dir of componentDirs) {
164
+ const fullDir = join(workingDir, dir);
165
+ // Skip if the directory path includes node_modules and we're not including external
166
+ if (dir.includes("node_modules") && !includeExternal) {
167
+ continue;
168
+ }
169
+ try {
170
+ const dirStat = await stat(fullDir);
171
+ if (dirStat.isDirectory()) {
172
+ await scanDir(fullDir, dir.includes("node_modules"), 0);
173
+ }
174
+ }
175
+ catch {
176
+ // Directory doesn't exist
177
+ }
178
+ }
179
+ // Also scan root
180
+ try {
181
+ const rootEntries = await readdir(workingDir, { withFileTypes: true });
182
+ for (const entry of rootEntries) {
183
+ if (entry.isFile()) {
184
+ for (const ext of extensions) {
185
+ if (entry.name.endsWith(ext) &&
186
+ !entry.name.startsWith("_")) {
187
+ const componentName = entry.name.replace(ext, "");
188
+ if (!components.find((c) => c.name === componentName)) {
189
+ components.push({
190
+ name: componentName,
191
+ filePath: join(workingDir, entry.name),
192
+ type: "local",
193
+ });
194
+ }
195
+ break;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ catch {
202
+ // Ignore
203
+ }
204
+ // Deduplicate: prefer .ts over .cjs for same component name
205
+ const seen = new Map();
206
+ for (const component of components) {
207
+ const existing = seen.get(component.name);
208
+ if (!existing) {
209
+ seen.set(component.name, component);
210
+ }
211
+ else {
212
+ // Prefer .ts files over .cjs
213
+ if (component.filePath.endsWith(".ts") &&
214
+ !existing.filePath.endsWith(".ts")) {
215
+ seen.set(component.name, component);
216
+ }
217
+ // Prefer local over external
218
+ else if (component.type === "local" &&
219
+ existing.type === "external") {
220
+ seen.set(component.name, component);
221
+ }
222
+ }
223
+ }
224
+ const deduplicated = Array.from(seen.values());
225
+ // Sort: local first, then by name
226
+ deduplicated.sort((a, b) => {
227
+ if (a.type !== b.type) {
228
+ return a.type === "local" ? -1 : 1;
229
+ }
230
+ return a.name.localeCompare(b.name);
231
+ });
232
+ return deduplicated;
233
+ }
234
+ /**
235
+ * Discover datasources in the working directory
236
+ */
237
+ export async function discoverDatasources(workingDir) {
238
+ const datasources = [];
239
+ const extensions = [
240
+ ".datasource.js",
241
+ ".datasource.cjs",
242
+ ".sb.datasource.js",
243
+ ".sb.datasource.cjs",
244
+ ];
245
+ const scanDir = async (dir) => {
246
+ try {
247
+ const entries = await readdir(dir, { withFileTypes: true });
248
+ for (const entry of entries) {
249
+ const fullPath = join(dir, entry.name);
250
+ if (entry.isDirectory()) {
251
+ if (entry.name === ".git" ||
252
+ entry.name === ".next" ||
253
+ entry.name === "dist" ||
254
+ entry.name === "node_modules") {
255
+ continue;
256
+ }
257
+ await scanDir(fullPath);
258
+ }
259
+ else if (entry.isFile()) {
260
+ for (const ext of extensions) {
261
+ if (entry.name.endsWith(ext) &&
262
+ !entry.name.startsWith("_")) {
263
+ const name = entry.name
264
+ .replace(ext, "")
265
+ .replace(".sb", "");
266
+ datasources.push({
267
+ name,
268
+ filePath: fullPath,
269
+ type: "local",
270
+ });
271
+ break;
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+ catch {
278
+ // Skip
279
+ }
280
+ };
281
+ await scanDir(workingDir);
282
+ datasources.sort((a, b) => a.name.localeCompare(b.name));
283
+ return datasources;
284
+ }
285
+ /**
286
+ * Discover roles in the working directory
287
+ */
288
+ export async function discoverRoles(workingDir) {
289
+ const roles = [];
290
+ const extensions = [".sb.roles.js", ".sb.roles.cjs", ".sb.roles.ts"];
291
+ const scanDir = async (dir) => {
292
+ try {
293
+ const entries = await readdir(dir, { withFileTypes: true });
294
+ for (const entry of entries) {
295
+ const fullPath = join(dir, entry.name);
296
+ if (entry.isDirectory()) {
297
+ if (entry.name === ".git" ||
298
+ entry.name === ".next" ||
299
+ entry.name === "dist" ||
300
+ entry.name === "node_modules") {
301
+ continue;
302
+ }
303
+ await scanDir(fullPath);
304
+ }
305
+ else if (entry.isFile()) {
306
+ for (const ext of extensions) {
307
+ if (entry.name.endsWith(ext) &&
308
+ !entry.name.startsWith("_")) {
309
+ const name = entry.name.replace(ext, "");
310
+ roles.push({
311
+ name,
312
+ filePath: fullPath,
313
+ type: "local",
314
+ });
315
+ break;
316
+ }
317
+ }
318
+ }
319
+ }
320
+ }
321
+ catch {
322
+ // Skip
323
+ }
324
+ };
325
+ await scanDir(workingDir);
326
+ roles.sort((a, b) => a.name.localeCompare(b.name));
327
+ return roles;
328
+ }
@@ -0,0 +1,2 @@
1
+ export { discoverComponents, discoverDatasources, discoverRoles, loadResourceContent, loadResources, } from "./discover.js";
2
+ export type { DiscoverComponentsOptions, DiscoveredResource, LoadedResource, } from "./discover.js";
@@ -0,0 +1 @@
1
+ export { discoverComponents, discoverDatasources, discoverRoles, loadResourceContent, loadResources, } from "./discover.js";
@@ -0,0 +1,19 @@
1
+ export { testConnection, testAsyncConnection } from "./test.js";
2
+ export { createClient } from "./client.js";
3
+ export type { ClientConfig, ApiClient } from "./client.js";
4
+ export * as stories from "./stories/index.js";
5
+ export type { CopyProgress, CopyResult, StoryTreeNode, FetchStoriesResult, } from "./stories/types.js";
6
+ export * as assets from "./assets/index.js";
7
+ export * as auth from "./auth/index.js";
8
+ export * as components from "./components/index.js";
9
+ export * as datasources from "./datasources/index.js";
10
+ export * as plugins from "./plugins/index.js";
11
+ export * as presets from "./presets/index.js";
12
+ export * as roles from "./roles/index.js";
13
+ export * as spaces from "./spaces/index.js";
14
+ export * as sync from "./sync/index.js";
15
+ export type { SyncResult, SyncError, SyncProgressEvent, SyncProgressCallback, } from "./sync/types.js";
16
+ export * as discover from "./discover/index.js";
17
+ export type { DiscoveredResource } from "./discover/index.js";
18
+ export * as precompile from "./precompile/index.js";
19
+ export type { PrecompileOptions, PrecompileResult, } from "./precompile/index.js";
@@ -0,0 +1,21 @@
1
+ // Test functions for ESM/CJS interop testing
2
+ export { testConnection, testAsyncConnection } from "./test.js";
3
+ // Client
4
+ export { createClient } from "./client.js";
5
+ // Stories
6
+ export * as stories from "./stories/index.js";
7
+ // Resources (thin wrappers)
8
+ export * as assets from "./assets/index.js";
9
+ export * as auth from "./auth/index.js";
10
+ export * as components from "./components/index.js";
11
+ export * as datasources from "./datasources/index.js";
12
+ export * as plugins from "./plugins/index.js";
13
+ export * as presets from "./presets/index.js";
14
+ export * as roles from "./roles/index.js";
15
+ export * as spaces from "./spaces/index.js";
16
+ // Sync (data-only)
17
+ export * as sync from "./sync/index.js";
18
+ // Discovery
19
+ export * as discover from "./discover/index.js";
20
+ // Precompile (TypeScript to JS using Rollup + SWC)
21
+ export * as precompile from "./precompile/index.js";
@@ -0,0 +1,9 @@
1
+ import type { ApiClient } from "../client.js";
2
+ export declare function getAllPlugins(client: ApiClient): Promise<any>;
3
+ export declare function getPlugin(client: ApiClient, pluginName: string): Promise<any>;
4
+ export declare function getPluginDetails(client: ApiClient, plugin: any): Promise<any>;
5
+ export declare function updatePlugin(client: ApiClient, args: {
6
+ plugin: any;
7
+ body: string;
8
+ }): Promise<any>;
9
+ export declare function createPlugin(client: ApiClient, pluginName: string): Promise<any>;
@@ -0,0 +1,42 @@
1
+ import { getAllItemsWithPagination } from "../../api/utils/request.js";
2
+ export async function getAllPlugins(client) {
3
+ return getAllItemsWithPagination({
4
+ apiFn: ({ per_page, page }) => client.sbApi.get("field_types", { per_page, page }),
5
+ params: {},
6
+ itemsKey: "field_types",
7
+ });
8
+ }
9
+ export async function getPlugin(client, pluginName) {
10
+ const plugins = await getAllPlugins(client);
11
+ const plugin = plugins.find((p) => p.name === pluginName);
12
+ if (!plugin)
13
+ return false;
14
+ return await getPluginDetails(client, plugin);
15
+ }
16
+ export async function getPluginDetails(client, plugin) {
17
+ return client.sbApi
18
+ .get(`field_types/${plugin.id}`)
19
+ .then((res) => res.data);
20
+ }
21
+ export async function updatePlugin(client, args) {
22
+ const { plugin, body } = args;
23
+ return client.sbApi
24
+ .put(`field_types/${plugin.id}`, {
25
+ publish: true,
26
+ field_type: {
27
+ body,
28
+ compiled_body: "",
29
+ },
30
+ })
31
+ .then((res) => res.data);
32
+ }
33
+ export async function createPlugin(client, pluginName) {
34
+ return client.sbApi
35
+ .post("field_types", {
36
+ publish: true,
37
+ field_type: {
38
+ name: pluginName,
39
+ },
40
+ })
41
+ .then((res) => res.data);
42
+ }
@@ -0,0 +1,2 @@
1
+ export { precompile, extractComponentName, getCompiledPath, } from "./precompile.js";
2
+ export type { PrecompileOptions, PrecompileResult } from "./precompile.js";
@@ -0,0 +1 @@
1
+ export { precompile, extractComponentName, getCompiledPath, } from "./precompile.js";
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Options for precompiling TypeScript schema files
3
+ */
4
+ export interface PrecompileOptions {
5
+ /** Directory to store compiled files (defaults to .sb-mig-cache) */
6
+ cacheDir?: string;
7
+ /** Whether to clear cache before compiling (defaults to true) */
8
+ flushCache?: boolean;
9
+ /** Project directory (defaults to process.cwd()) */
10
+ projectDir?: string;
11
+ }
12
+ /**
13
+ * Result of precompiling files
14
+ */
15
+ export interface PrecompileResult {
16
+ /** Successfully compiled files with their output paths */
17
+ compiled: Array<{
18
+ input: string;
19
+ outputCjs: string;
20
+ outputEsm: string;
21
+ }>;
22
+ /** Files that failed to compile */
23
+ errors: Array<{
24
+ input: string;
25
+ error: string;
26
+ }>;
27
+ }
28
+ /**
29
+ * Extract the component name from a file path
30
+ * e.g., "/path/to/my-component.sb.ts" -> "my-component.sb"
31
+ */
32
+ export declare const extractComponentName: (filePath: string) => string;
33
+ /**
34
+ * Precompile TypeScript schema files to JavaScript
35
+ *
36
+ * This uses Rollup with SWC for fast transpilation, producing
37
+ * both CommonJS (.cjs) and ESM (.js) outputs.
38
+ *
39
+ * @param files - Array of TypeScript file paths to compile
40
+ * @param options - Precompile options
41
+ * @returns Result with compiled files and any errors
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const result = await precompile([
46
+ * '/path/to/hero.sb.ts',
47
+ * '/path/to/card.sb.ts',
48
+ * ], { cacheDir: '.cache/sb-mig' });
49
+ *
50
+ * // Use compiled CJS files
51
+ * for (const compiled of result.compiled) {
52
+ * const content = require(compiled.outputCjs);
53
+ * }
54
+ * ```
55
+ */
56
+ export declare function precompile(files: string[], options?: PrecompileOptions): Promise<PrecompileResult>;
57
+ /**
58
+ * Get the compiled file path for a TypeScript source file
59
+ *
60
+ * @param tsFilePath - Original .ts file path
61
+ * @param options - Options with cacheDir and projectDir
62
+ * @param format - Output format ('cjs' or 'esm')
63
+ * @returns Path to the compiled file
64
+ */
65
+ export declare function getCompiledPath(tsFilePath: string, options?: PrecompileOptions, format?: "cjs" | "esm"): string;