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,127 @@
1
+ import { mkdir, rm } from "fs/promises";
2
+ import path from "path";
3
+ import { rollup } from "rollup";
4
+ import ts from "rollup-plugin-ts";
5
+ /**
6
+ * Extract the component name from a file path
7
+ * e.g., "/path/to/my-component.sb.ts" -> "my-component.sb"
8
+ */
9
+ export const extractComponentName = (filePath) => {
10
+ const separator = "/";
11
+ const parts = filePath.split(separator);
12
+ const lastElement = parts[parts.length - 1];
13
+ return lastElement.replace(/\.ts$/, "");
14
+ };
15
+ /**
16
+ * Build a single file using Rollup
17
+ */
18
+ async function buildFile(inputPath, outputCjs, outputEsm) {
19
+ const inputOptions = {
20
+ input: inputPath,
21
+ plugins: [
22
+ ts({
23
+ transpileOnly: true,
24
+ transpiler: "swc",
25
+ }),
26
+ ],
27
+ };
28
+ const outputOptionsList = [
29
+ { file: outputCjs, format: "cjs" },
30
+ { file: outputEsm, format: "es" },
31
+ ];
32
+ let bundle;
33
+ try {
34
+ bundle = await rollup(inputOptions);
35
+ for (const outputOptions of outputOptionsList) {
36
+ await bundle.write(outputOptions);
37
+ }
38
+ }
39
+ finally {
40
+ if (bundle) {
41
+ await bundle.close();
42
+ }
43
+ }
44
+ }
45
+ /**
46
+ * Precompile TypeScript schema files to JavaScript
47
+ *
48
+ * This uses Rollup with SWC for fast transpilation, producing
49
+ * both CommonJS (.cjs) and ESM (.js) outputs.
50
+ *
51
+ * @param files - Array of TypeScript file paths to compile
52
+ * @param options - Precompile options
53
+ * @returns Result with compiled files and any errors
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const result = await precompile([
58
+ * '/path/to/hero.sb.ts',
59
+ * '/path/to/card.sb.ts',
60
+ * ], { cacheDir: '.cache/sb-mig' });
61
+ *
62
+ * // Use compiled CJS files
63
+ * for (const compiled of result.compiled) {
64
+ * const content = require(compiled.outputCjs);
65
+ * }
66
+ * ```
67
+ */
68
+ export async function precompile(files, options = {}) {
69
+ const { cacheDir = ".sb-mig-cache", flushCache = true, projectDir = process.cwd(), } = options;
70
+ const fullCacheDir = path.join(projectDir, cacheDir, "sb-mig");
71
+ // Optionally clear cache
72
+ if (flushCache) {
73
+ try {
74
+ await rm(fullCacheDir, { recursive: true, force: true });
75
+ }
76
+ catch {
77
+ // Ignore if doesn't exist
78
+ }
79
+ }
80
+ // Ensure cache directory exists
81
+ await mkdir(fullCacheDir, { recursive: true });
82
+ const result = {
83
+ compiled: [],
84
+ errors: [],
85
+ };
86
+ // Filter to only TypeScript files
87
+ const tsFiles = files.filter((f) => f.endsWith(".ts"));
88
+ if (tsFiles.length === 0) {
89
+ return result;
90
+ }
91
+ // Compile all files in parallel
92
+ await Promise.all(tsFiles.map(async (inputPath) => {
93
+ const componentName = extractComponentName(inputPath);
94
+ const outputCjs = path.join(fullCacheDir, `${componentName}.cjs`);
95
+ const outputEsm = path.join(fullCacheDir, `${componentName}.js`);
96
+ try {
97
+ await buildFile(inputPath, outputCjs, outputEsm);
98
+ result.compiled.push({
99
+ input: inputPath,
100
+ outputCjs,
101
+ outputEsm,
102
+ });
103
+ }
104
+ catch (error) {
105
+ result.errors.push({
106
+ input: inputPath,
107
+ error: error instanceof Error ? error.message : String(error),
108
+ });
109
+ }
110
+ }));
111
+ return result;
112
+ }
113
+ /**
114
+ * Get the compiled file path for a TypeScript source file
115
+ *
116
+ * @param tsFilePath - Original .ts file path
117
+ * @param options - Options with cacheDir and projectDir
118
+ * @param format - Output format ('cjs' or 'esm')
119
+ * @returns Path to the compiled file
120
+ */
121
+ export function getCompiledPath(tsFilePath, options = {}, format = "cjs") {
122
+ const { cacheDir = ".sb-mig-cache", projectDir = process.cwd() } = options;
123
+ const fullCacheDir = path.join(projectDir, cacheDir, "sb-mig");
124
+ const componentName = extractComponentName(tsFilePath);
125
+ const ext = format === "cjs" ? ".cjs" : ".js";
126
+ return path.join(fullCacheDir, `${componentName}${ext}`);
127
+ }
@@ -0,0 +1,13 @@
1
+ import type { ApiClient } from "../client.js";
2
+ export declare function getAllPresets(client: ApiClient): Promise<any>;
3
+ export declare function getPreset(client: ApiClient, presetId: string): Promise<any>;
4
+ export declare function createPreset(client: ApiClient, preset: any): Promise<any>;
5
+ export declare function updatePreset(client: ApiClient, preset: any): Promise<any>;
6
+ export declare function updatePresets(client: ApiClient, args: {
7
+ presets: any[];
8
+ spaceId: string;
9
+ options?: {
10
+ publish?: boolean;
11
+ };
12
+ }): Promise<any>;
13
+ export declare function getComponentPresets(client: ApiClient, componentName: string): Promise<any>;
@@ -0,0 +1,25 @@
1
+ import { getComponentPresets as apiGetComponentPresets } from "../../api/presets/componentPresets.js";
2
+ import { getAllPresets as apiGetAllPresets, getPreset as apiGetPreset, createPreset as apiCreatePreset, updatePreset as apiUpdatePreset, updatePresets as apiUpdatePresets, } from "../../api/presets/presets.js";
3
+ import { toRequestConfig } from "../requestConfig.js";
4
+ export async function getAllPresets(client) {
5
+ return await apiGetAllPresets(toRequestConfig(client));
6
+ }
7
+ export async function getPreset(client, presetId) {
8
+ return await apiGetPreset({ presetId }, toRequestConfig(client));
9
+ }
10
+ export async function createPreset(client, preset) {
11
+ return await apiCreatePreset(preset, toRequestConfig(client));
12
+ }
13
+ export async function updatePreset(client, preset) {
14
+ return await apiUpdatePreset({ p: preset }, toRequestConfig(client));
15
+ }
16
+ export async function updatePresets(client, args) {
17
+ return await apiUpdatePresets({
18
+ presets: args.presets,
19
+ spaceId: args.spaceId,
20
+ options: args.options ?? {},
21
+ }, toRequestConfig(client));
22
+ }
23
+ export async function getComponentPresets(client, componentName) {
24
+ return await apiGetComponentPresets(componentName, toRequestConfig(client));
25
+ }
@@ -0,0 +1,5 @@
1
+ import type { ApiClient } from "./client.js";
2
+ import type { RequestBaseConfig } from "../api/utils/request.js";
3
+ export declare function toRequestConfig(client: ApiClient, overrides?: Partial<Omit<RequestBaseConfig, "sbApi">> & {
4
+ spaceId?: string;
5
+ }): RequestBaseConfig;
@@ -0,0 +1,34 @@
1
+ export function toRequestConfig(client, overrides) {
2
+ return {
3
+ spaceId: overrides?.spaceId ?? client.spaceId,
4
+ sbApi: client.sbApi,
5
+ oauthToken: overrides?.oauthToken ?? client.config.oauthToken,
6
+ accessToken: overrides?.accessToken ?? client.config.accessToken,
7
+ storyblokApiUrl: overrides?.storyblokApiUrl,
8
+ storyblokDeliveryApiUrl: overrides?.storyblokDeliveryApiUrl,
9
+ storyblokGraphqlApiUrl: overrides?.storyblokGraphqlApiUrl,
10
+ schemaFileExt: overrides?.schemaFileExt,
11
+ datasourceExt: overrides?.datasourceExt,
12
+ rolesExt: overrides?.rolesExt,
13
+ storiesExt: overrides?.storiesExt,
14
+ migrationConfigExt: overrides?.migrationConfigExt,
15
+ sbmigWorkingDirectory: overrides?.sbmigWorkingDirectory,
16
+ presetsBackupDirectory: overrides?.presetsBackupDirectory,
17
+ storiesBackupDirectory: overrides?.storiesBackupDirectory,
18
+ componentsDirectories: overrides?.componentsDirectories,
19
+ flushCache: overrides?.flushCache,
20
+ cacheDir: overrides?.cacheDir,
21
+ debug: overrides?.debug,
22
+ rateLimit: overrides?.rateLimit,
23
+ openaiToken: overrides?.openaiToken,
24
+ boilerplateSpaceId: overrides?.boilerplateSpaceId,
25
+ schemaType: overrides?.schemaType,
26
+ awsBucketData: overrides?.awsBucketData,
27
+ metadataSelection: overrides?.metadataSelection,
28
+ contentHubOriginUrl: overrides?.contentHubOriginUrl,
29
+ contentHubAuthorizationToken: overrides?.contentHubAuthorizationToken,
30
+ resolvers: overrides?.resolvers,
31
+ advancedResolvers: overrides?.advancedResolvers,
32
+ storyblokComponentsLocalDirectory: overrides?.storyblokComponentsLocalDirectory,
33
+ };
34
+ }
@@ -0,0 +1,5 @@
1
+ import type { ApiClient } from "../client.js";
2
+ export declare function getAllRoles(client: ApiClient): Promise<any>;
3
+ export declare function getRole(client: ApiClient, roleName: string): Promise<any>;
4
+ export declare function createRole(client: ApiClient, role: any): Promise<any>;
5
+ export declare function updateRole(client: ApiClient, role: any): Promise<any>;
@@ -0,0 +1,35 @@
1
+ import { getAllItemsWithPagination } from "../../api/utils/request.js";
2
+ export async function getAllRoles(client) {
3
+ const spaceId = client.spaceId;
4
+ return getAllItemsWithPagination({
5
+ apiFn: ({ per_page, page }) => client.sbApi.get(`spaces/${spaceId}/space_roles/`, {
6
+ per_page,
7
+ page,
8
+ }),
9
+ params: {
10
+ spaceId,
11
+ },
12
+ itemsKey: "space_roles",
13
+ });
14
+ }
15
+ export async function getRole(client, roleName) {
16
+ const roles = await getAllRoles(client);
17
+ const match = roles.filter((r) => r.role === roleName);
18
+ if (Array.isArray(match) && match.length === 0)
19
+ return false;
20
+ return match;
21
+ }
22
+ export async function createRole(client, role) {
23
+ const spaceId = client.spaceId;
24
+ return client.sbApi
25
+ .post(`spaces/${spaceId}/space_roles/`, { space_role: role })
26
+ .then((res) => res.data);
27
+ }
28
+ export async function updateRole(client, role) {
29
+ const spaceId = client.spaceId;
30
+ return client.sbApi
31
+ .put(`spaces/${spaceId}/space_roles/${role.id}`, {
32
+ space_role: role,
33
+ })
34
+ .then((res) => res.data);
35
+ }
@@ -0,0 +1,7 @@
1
+ import type { ApiClient } from "../client.js";
2
+ export declare function getAllSpaces(client: ApiClient): Promise<any>;
3
+ export declare function getSpace(client: ApiClient, spaceId: string): Promise<any>;
4
+ export declare function updateSpace(client: ApiClient, args: {
5
+ spaceId: string;
6
+ params: Record<string, any>;
7
+ }): Promise<any>;
@@ -0,0 +1,11 @@
1
+ import { getAllSpaces as apiGetAllSpaces, getSpace as apiGetSpace, updateSpace as apiUpdateSpace, } from "../../api/spaces/spaces.js";
2
+ import { toRequestConfig } from "../requestConfig.js";
3
+ export async function getAllSpaces(client) {
4
+ return await apiGetAllSpaces(toRequestConfig(client));
5
+ }
6
+ export async function getSpace(client, spaceId) {
7
+ return await apiGetSpace({ spaceId }, toRequestConfig(client));
8
+ }
9
+ export async function updateSpace(client, args) {
10
+ return await apiUpdateSpace(args, toRequestConfig(client));
11
+ }
@@ -0,0 +1,34 @@
1
+ import type { ApiClient } from "../client.js";
2
+ import type { CopyProgress, CopyResult, StoryTreeNode } from "./types.js";
3
+ import type { ExtendedISbStoriesParams } from "../../api/stories/stories.types.js";
4
+ /**
5
+ * Get all stories from a space
6
+ */
7
+ export declare function getAllStories(client: ApiClient, options?: ExtendedISbStoriesParams): Promise<any[]>;
8
+ /**
9
+ * Get a single story by ID
10
+ */
11
+ export declare function getStoryById(client: ApiClient, storyId: number | string): Promise<any>;
12
+ /**
13
+ * Get a story by slug
14
+ */
15
+ export declare function getStoryBySlug(client: ApiClient, slug: string): Promise<any>;
16
+ /**
17
+ * Create a story in a space
18
+ */
19
+ export declare function createStory(client: ApiClient, content: any): Promise<any>;
20
+ /**
21
+ * Fetch all stories and build a tree structure
22
+ */
23
+ export declare function fetchStories(client: ApiClient, options?: ExtendedISbStoriesParams): Promise<{
24
+ stories: any[];
25
+ tree: StoryTreeNode[];
26
+ total: number;
27
+ }>;
28
+ /**
29
+ * Copy stories from source space to target space
30
+ */
31
+ export declare function copyStories(sourceClient: ApiClient, targetClient: ApiClient, options: {
32
+ storyIds: number[];
33
+ destinationParentId?: number | null;
34
+ }, onProgress?: (progress: CopyProgress) => void): Promise<CopyResult>;
@@ -0,0 +1,172 @@
1
+ import { getAllStories as apiGetAllStories, getStoryById as apiGetStoryById, getStoryBySlug as apiGetStoryBySlug, createStory as apiCreateStory, } from "../../api/stories/stories.js";
2
+ import { toRequestConfig } from "../requestConfig.js";
3
+ /**
4
+ * Build a tree structure from flat story list
5
+ */
6
+ function buildTree(stories) {
7
+ const storyMap = new Map();
8
+ // First pass: create all nodes
9
+ for (const storyData of stories) {
10
+ const story = storyData.story || storyData;
11
+ storyMap.set(story.id, {
12
+ id: story.id,
13
+ name: story.name,
14
+ slug: story.slug,
15
+ full_slug: story.full_slug,
16
+ is_folder: story.is_folder,
17
+ is_startpage: story.is_startpage,
18
+ parent_id: story.parent_id,
19
+ children: [],
20
+ story,
21
+ });
22
+ }
23
+ // Second pass: build tree structure
24
+ const rootNodes = [];
25
+ for (const storyData of stories) {
26
+ const story = storyData.story || storyData;
27
+ const node = storyMap.get(story.id);
28
+ if (story.parent_id === null || story.parent_id === 0) {
29
+ rootNodes.push(node);
30
+ }
31
+ else {
32
+ const parent = storyMap.get(story.parent_id);
33
+ if (parent) {
34
+ parent.children.push(node);
35
+ }
36
+ else {
37
+ rootNodes.push(node);
38
+ }
39
+ }
40
+ }
41
+ // Sort children
42
+ const sortNodes = (nodes) => {
43
+ nodes.sort((a, b) => {
44
+ if (a.is_folder && !b.is_folder)
45
+ return -1;
46
+ if (!a.is_folder && b.is_folder)
47
+ return 1;
48
+ if (a.story.position !== b.story.position) {
49
+ return a.story.position - b.story.position;
50
+ }
51
+ return a.name.localeCompare(b.name);
52
+ });
53
+ for (const node of nodes) {
54
+ if (node.children.length > 0) {
55
+ sortNodes(node.children);
56
+ }
57
+ }
58
+ };
59
+ sortNodes(rootNodes);
60
+ return rootNodes;
61
+ }
62
+ /**
63
+ * Get all stories from a space
64
+ */
65
+ export async function getAllStories(client, options) {
66
+ const config = toRequestConfig(client);
67
+ return await apiGetAllStories({ options }, config);
68
+ }
69
+ /**
70
+ * Get a single story by ID
71
+ */
72
+ export async function getStoryById(client, storyId) {
73
+ const config = toRequestConfig(client);
74
+ return await apiGetStoryById(String(storyId), config);
75
+ }
76
+ /**
77
+ * Get a story by slug
78
+ */
79
+ export async function getStoryBySlug(client, slug) {
80
+ const config = toRequestConfig(client);
81
+ return await apiGetStoryBySlug(slug, config);
82
+ }
83
+ /**
84
+ * Create a story in a space
85
+ */
86
+ export async function createStory(client, content) {
87
+ const config = toRequestConfig(client);
88
+ return await apiCreateStory(content, config);
89
+ }
90
+ /**
91
+ * Fetch all stories and build a tree structure
92
+ */
93
+ export async function fetchStories(client, options) {
94
+ const stories = await getAllStories(client, options);
95
+ const tree = buildTree(stories);
96
+ return {
97
+ stories,
98
+ tree,
99
+ total: stories.length,
100
+ };
101
+ }
102
+ /**
103
+ * Copy stories from source space to target space
104
+ */
105
+ export async function copyStories(sourceClient, targetClient, options, onProgress) {
106
+ const errors = [];
107
+ let copiedCount = 0;
108
+ // Fetch all stories with their full content
109
+ const storiesToCopy = [];
110
+ for (let i = 0; i < options.storyIds.length; i++) {
111
+ const storyId = options.storyIds[i];
112
+ if (storyId === undefined)
113
+ continue;
114
+ onProgress?.({
115
+ current: i + 1,
116
+ total: options.storyIds.length,
117
+ currentStory: `Fetching story ${storyId}...`,
118
+ status: "copying",
119
+ });
120
+ try {
121
+ const storyData = await getStoryById(sourceClient, storyId);
122
+ storiesToCopy.push(storyData);
123
+ }
124
+ catch (error) {
125
+ const errorMsg = error instanceof Error ? error.message : String(error);
126
+ errors.push(`Failed to fetch story ${storyId}: ${errorMsg}`);
127
+ }
128
+ }
129
+ // Build tree from selected stories
130
+ const tree = buildTree(storiesToCopy);
131
+ // Recursive function to create stories maintaining hierarchy
132
+ const createInOrder = async (nodes, newParentId) => {
133
+ for (const node of nodes) {
134
+ onProgress?.({
135
+ current: copiedCount + 1,
136
+ total: storiesToCopy.length,
137
+ currentStory: node.name,
138
+ status: "copying",
139
+ });
140
+ try {
141
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
142
+ const { id, uuid, created_at, updated_at, ...storyData } = node.story;
143
+ const newStory = await createStory(targetClient, {
144
+ ...storyData,
145
+ parent_id: newParentId,
146
+ });
147
+ copiedCount++;
148
+ // Recursively create children
149
+ if (node.children.length > 0) {
150
+ await createInOrder(node.children, newStory.story.id);
151
+ }
152
+ }
153
+ catch (error) {
154
+ const errorMsg = error instanceof Error ? error.message : String(error);
155
+ errors.push(`Failed to create "${node.name}": ${errorMsg}`);
156
+ }
157
+ }
158
+ };
159
+ // Start creating from root nodes
160
+ await createInOrder(tree, options.destinationParentId ?? null);
161
+ onProgress?.({
162
+ current: copiedCount,
163
+ total: storiesToCopy.length,
164
+ currentStory: "Complete",
165
+ status: errors.length > 0 ? "error" : "done",
166
+ });
167
+ return {
168
+ success: errors.length === 0,
169
+ copiedCount,
170
+ errors,
171
+ };
172
+ }
@@ -0,0 +1,28 @@
1
+ export interface CopyProgress {
2
+ current: number;
3
+ total: number;
4
+ currentStory: string;
5
+ status: "pending" | "copying" | "done" | "error";
6
+ error?: string;
7
+ }
8
+ export interface CopyResult {
9
+ success: boolean;
10
+ copiedCount: number;
11
+ errors: string[];
12
+ }
13
+ export interface StoryTreeNode {
14
+ id: number;
15
+ name: string;
16
+ slug: string;
17
+ full_slug: string;
18
+ is_folder: boolean;
19
+ is_startpage: boolean;
20
+ parent_id: number | null;
21
+ children: StoryTreeNode[];
22
+ story: any;
23
+ }
24
+ export interface FetchStoriesResult {
25
+ stories: any[];
26
+ tree: StoryTreeNode[];
27
+ total: number;
28
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { ApiClient } from "../client.js";
2
+ import type { SyncProgressCallback, SyncResult } from "./types.js";
3
+ export declare function syncComponents(client: ApiClient, args: {
4
+ components: any[];
5
+ presets?: boolean;
6
+ ssot?: boolean;
7
+ dryRun?: boolean;
8
+ onProgress?: SyncProgressCallback;
9
+ }): Promise<SyncResult>;
10
+ export declare function syncDatasources(client: ApiClient, args: {
11
+ datasources: any[];
12
+ dryRun?: boolean;
13
+ }): Promise<SyncResult>;
14
+ export declare function syncRoles(client: ApiClient, args: {
15
+ roles: any[];
16
+ dryRun?: boolean;
17
+ }): Promise<SyncResult>;
18
+ export declare function syncPlugins(client: ApiClient, args: {
19
+ plugins: {
20
+ name: string;
21
+ body: string;
22
+ }[];
23
+ dryRun?: boolean;
24
+ }): Promise<SyncResult>;
@@ -0,0 +1,109 @@
1
+ import { syncComponentsData } from "../../api/components/components.sync.js";
2
+ import { syncDatasourcesData } from "../../api/datasources/datasources.js";
3
+ import { syncPluginsData } from "../../api/plugins/plugins.js";
4
+ import { syncRolesData } from "../../api/roles/roles.js";
5
+ import { toRequestConfig } from "../requestConfig.js";
6
+ export async function syncComponents(client, args) {
7
+ const presets = args.presets ?? false;
8
+ if (args.dryRun) {
9
+ // minimal dry-run: compare names against remote
10
+ const remote = await client.sbApi.get(`spaces/${client.spaceId}/components/`, {
11
+ per_page: 100,
12
+ page: 1,
13
+ });
14
+ const remoteNames = new Set(remote.data?.components?.map((c) => c.name) ?? []);
15
+ const created = [];
16
+ const updated = [];
17
+ const skipped = [];
18
+ for (const c of args.components) {
19
+ const name = String(c?.name ?? "unknown");
20
+ if (!c?.name) {
21
+ skipped.push(name);
22
+ continue;
23
+ }
24
+ if (remoteNames.has(c.name))
25
+ updated.push(name);
26
+ else
27
+ created.push(name);
28
+ }
29
+ return { created, updated, skipped, errors: [] };
30
+ }
31
+ return (await syncComponentsData({
32
+ components: args.components,
33
+ presets,
34
+ ssot: args.ssot,
35
+ onProgress: args.onProgress,
36
+ }, toRequestConfig(client)));
37
+ }
38
+ export async function syncDatasources(client, args) {
39
+ if (args.dryRun) {
40
+ const remote = await client.sbApi.get(`spaces/${client.spaceId}/datasources/`);
41
+ const remoteNames = new Set(remote.data?.datasources?.map((d) => d.name) ?? []);
42
+ const created = [];
43
+ const updated = [];
44
+ const skipped = [];
45
+ for (const d of args.datasources) {
46
+ const name = String(d?.name ?? "unknown");
47
+ if (!d?.name) {
48
+ skipped.push(name);
49
+ continue;
50
+ }
51
+ if (remoteNames.has(d.name))
52
+ updated.push(name);
53
+ else
54
+ created.push(name);
55
+ }
56
+ return { created, updated, skipped, errors: [] };
57
+ }
58
+ return (await syncDatasourcesData({ datasources: args.datasources }, toRequestConfig(client)));
59
+ }
60
+ export async function syncRoles(client, args) {
61
+ if (args.dryRun) {
62
+ const remote = await client.sbApi.get(`spaces/${client.spaceId}/space_roles/`, {
63
+ per_page: 100,
64
+ page: 1,
65
+ });
66
+ const remoteNames = new Set(remote.data?.space_roles?.map((r) => r.role) ?? []);
67
+ const created = [];
68
+ const updated = [];
69
+ const skipped = [];
70
+ for (const r of args.roles) {
71
+ const name = String(r?.role ?? "unknown");
72
+ if (!r?.role) {
73
+ skipped.push(name);
74
+ continue;
75
+ }
76
+ if (remoteNames.has(r.role))
77
+ updated.push(name);
78
+ else
79
+ created.push(name);
80
+ }
81
+ return { created, updated, skipped, errors: [] };
82
+ }
83
+ return (await syncRolesData({ roles: args.roles }, toRequestConfig(client)));
84
+ }
85
+ export async function syncPlugins(client, args) {
86
+ if (args.dryRun) {
87
+ const remote = await client.sbApi.get("field_types", {
88
+ per_page: 100,
89
+ page: 1,
90
+ });
91
+ const remoteNames = new Set(remote.data?.field_types?.map((p) => p.name) ?? []);
92
+ const created = [];
93
+ const updated = [];
94
+ const skipped = [];
95
+ for (const p of args.plugins) {
96
+ const name = String(p?.name ?? "unknown");
97
+ if (!p?.name) {
98
+ skipped.push(name);
99
+ continue;
100
+ }
101
+ if (remoteNames.has(p.name))
102
+ updated.push(name);
103
+ else
104
+ created.push(name);
105
+ }
106
+ return { created, updated, skipped, errors: [] };
107
+ }
108
+ return (await syncPluginsData({ plugins: args.plugins }, toRequestConfig(client)));
109
+ }
@@ -0,0 +1 @@
1
+ export type { SyncError, SyncResult, SyncProgressEvent, SyncProgressCallback, } from "../../api/sync/sync.types.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Simple test function with no dependencies to verify ESM/CJS interop
3
+ */
4
+ export declare function testConnection(): {
5
+ success: boolean;
6
+ message: string;
7
+ timestamp: string;
8
+ };
9
+ /**
10
+ * Async test function to verify async imports work
11
+ */
12
+ export declare function testAsyncConnection(): Promise<{
13
+ success: boolean;
14
+ message: string;
15
+ }>;