revisium 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.github/workflows/ci.yml +32 -0
  2. package/README.md +23 -3
  3. package/dist/e2e/setup/global-setup.js +2 -3
  4. package/dist/e2e/setup/global-setup.js.map +1 -1
  5. package/dist/e2e/setup/global-teardown.js +0 -2
  6. package/dist/e2e/setup/global-teardown.js.map +1 -1
  7. package/dist/e2e/utils/constants.d.ts +0 -2
  8. package/dist/e2e/utils/constants.js +0 -2
  9. package/dist/e2e/utils/constants.js.map +1 -1
  10. package/dist/e2e/utils/docker-helper.d.ts +0 -2
  11. package/dist/e2e/utils/docker-helper.js +0 -13
  12. package/dist/e2e/utils/docker-helper.js.map +1 -1
  13. package/dist/package.json +27 -14
  14. package/dist/src/commands/migration/apply-migrations.command.d.ts +1 -1
  15. package/dist/src/commands/migration/apply-migrations.command.js +4 -5
  16. package/dist/src/commands/migration/apply-migrations.command.js.map +1 -1
  17. package/dist/src/commands/migration/save-migrations.command.d.ts +1 -1
  18. package/dist/src/commands/migration/save-migrations.command.js +6 -6
  19. package/dist/src/commands/migration/save-migrations.command.js.map +1 -1
  20. package/dist/src/commands/rows/save-rows.command.d.ts +1 -1
  21. package/dist/src/commands/rows/save-rows.command.js +12 -10
  22. package/dist/src/commands/rows/save-rows.command.js.map +1 -1
  23. package/dist/src/commands/rows/upload-rows.command.d.ts +1 -1
  24. package/dist/src/commands/rows/upload-rows.command.js +12 -15
  25. package/dist/src/commands/rows/upload-rows.command.js.map +1 -1
  26. package/dist/src/commands/schema/create-migrations.command.js.map +1 -1
  27. package/dist/src/commands/schema/save-schema.command.d.ts +1 -1
  28. package/dist/src/commands/schema/save-schema.command.js +7 -7
  29. package/dist/src/commands/schema/save-schema.command.js.map +1 -1
  30. package/dist/src/config/meta-schema.d.ts +3 -0
  31. package/dist/src/config/meta-schema.js +43 -1
  32. package/dist/src/config/meta-schema.js.map +1 -1
  33. package/dist/src/services/connection/api-client-adapter.d.ts +2 -4
  34. package/dist/src/services/connection/api-client-adapter.js +40 -36
  35. package/dist/src/services/connection/api-client-adapter.js.map +1 -1
  36. package/dist/src/services/connection/api-client.d.ts +3 -4
  37. package/dist/src/services/connection/api-client.js +11 -33
  38. package/dist/src/services/connection/api-client.js.map +1 -1
  39. package/dist/src/services/connection/connection-factory.service.d.ts +4 -6
  40. package/dist/src/services/connection/connection-factory.service.js +18 -39
  41. package/dist/src/services/connection/connection-factory.service.js.map +1 -1
  42. package/dist/src/services/connection/connection.service.d.ts +2 -73
  43. package/dist/src/services/connection/connection.service.js +2 -11
  44. package/dist/src/services/connection/connection.service.js.map +1 -1
  45. package/dist/src/services/sync/commit-revision.service.js +6 -28
  46. package/dist/src/services/sync/commit-revision.service.js.map +1 -1
  47. package/dist/src/services/sync/row-sync.service.d.ts +5 -5
  48. package/dist/src/services/sync/row-sync.service.js +10 -10
  49. package/dist/src/services/sync/row-sync.service.js.map +1 -1
  50. package/dist/src/services/sync/sync-data.service.d.ts +1 -0
  51. package/dist/src/services/sync/sync-data.service.js +21 -21
  52. package/dist/src/services/sync/sync-data.service.js.map +1 -1
  53. package/dist/src/services/sync/sync-schema.service.d.ts +1 -0
  54. package/dist/src/services/sync/sync-schema.service.js +11 -10
  55. package/dist/src/services/sync/sync-schema.service.js.map +1 -1
  56. package/dist/src/services/url/auth-prompt.service.js +1 -1
  57. package/dist/src/services/url/auth-prompt.service.js.map +1 -1
  58. package/dist/src/types/migration.types.d.ts +1 -1
  59. package/dist/tsconfig.build.tsbuildinfo +1 -1
  60. package/docs/authentication.md +3 -3
  61. package/docs/configuration.md +58 -9
  62. package/docs/docker-deployment.md +48 -13
  63. package/docs/migrate-commands.md +35 -10
  64. package/docs/rows-commands.md +30 -7
  65. package/docs/schema-commands.md +21 -5
  66. package/docs/sync-commands.md +44 -12
  67. package/docs/url-format.md +2 -2
  68. package/e2e/setup/global-setup.ts +3 -9
  69. package/e2e/setup/global-teardown.ts +0 -6
  70. package/e2e/utils/constants.ts +0 -2
  71. package/e2e/utils/docker-helper.ts +0 -23
  72. package/package.json +27 -14
  73. package/src/commands/migration/apply-migrations.command.ts +5 -6
  74. package/src/commands/migration/save-migrations.command.ts +7 -6
  75. package/src/commands/rows/save-rows.command.ts +14 -28
  76. package/src/commands/rows/upload-rows.command.ts +7 -15
  77. package/src/commands/schema/create-migrations.command.ts +1 -1
  78. package/src/commands/schema/save-schema.command.ts +9 -14
  79. package/src/config/meta-schema.ts +47 -0
  80. package/src/services/connection/__tests__/connection-factory.service.spec.ts +117 -0
  81. package/src/services/connection/__tests__/connection.service.spec.ts +27 -117
  82. package/src/services/connection/api-client-adapter.ts +41 -45
  83. package/src/services/connection/api-client.ts +11 -50
  84. package/src/services/connection/connection-factory.service.ts +35 -65
  85. package/src/services/connection/connection.service.ts +3 -14
  86. package/src/services/sync/__tests__/row-sync.service.spec.ts +3 -6
  87. package/src/services/sync/commit-revision.service.ts +7 -51
  88. package/src/services/sync/row-sync.service.ts +4 -18
  89. package/src/services/sync/sync-data.service.ts +32 -45
  90. package/src/services/sync/sync-schema.service.ts +14 -22
  91. package/src/services/url/auth-prompt.service.ts +1 -1
  92. package/src/types/migration.types.ts +2 -2
  93. package/dist/src/__generated__/api.d.ts +0 -688
  94. package/dist/src/__generated__/api.js +0 -698
  95. package/dist/src/__generated__/api.js.map +0 -1
  96. package/e2e/docker-compose.e2e.yml +0 -31
  97. package/src/__generated__/api.ts +0 -2598
@@ -61,26 +61,8 @@ describe('ConnectionService', () => {
61
61
  );
62
62
  });
63
63
 
64
- it('throws error when accessing api before connect', () => {
65
- expect(() => service.api).toThrow(
66
- 'Connection not established. Call connect() first.',
67
- );
68
- });
69
-
70
- it('throws error when accessing revisionId before connect', () => {
71
- expect(() => service.revisionId).toThrow(
72
- 'Connection not established. Call connect() first.',
73
- );
74
- });
75
-
76
- it('throws error when accessing draftRevisionId before connect', () => {
77
- expect(() => service.draftRevisionId).toThrow(
78
- 'Connection not established. Call connect() first.',
79
- );
80
- });
81
-
82
- it('throws error when accessing headRevisionId before connect', () => {
83
- expect(() => service.headRevisionId).toThrow(
64
+ it('throws error when accessing revisionScope before connect', () => {
65
+ expect(() => service.revisionScope).toThrow(
84
66
  'Connection not established. Call connect() first.',
85
67
  );
86
68
  });
@@ -179,114 +161,42 @@ describe('ConnectionService', () => {
179
161
  });
180
162
  });
181
163
 
182
- describe('revision resolution', () => {
183
- it('uses draft revision when revision is draft', async () => {
184
- const url = { ...mockUrl, revision: 'draft' };
185
- setupSuccessfulConnection(url, {
186
- headId: 'head-123',
187
- draftId: 'draft-456',
188
- });
189
-
190
- await service.connect();
191
-
192
- expect(service.revisionId).toBe('draft-456');
193
- });
194
-
195
- it('uses head revision when revision is head', async () => {
196
- const url = { ...mockUrl, revision: 'head' };
197
- setupSuccessfulConnection(url, {
198
- headId: 'head-123',
199
- draftId: 'draft-456',
200
- });
201
-
202
- await service.connect();
203
-
204
- expect(service.revisionId).toBe('head-123');
205
- });
206
-
207
- it('uses specific revision ID when provided', async () => {
208
- const url = { ...mockUrl, revision: 'specific-rev-id' };
209
- setupSuccessfulConnection(url, {
210
- headId: 'head-123',
211
- draftId: 'draft-456',
212
- });
213
-
214
- await service.connect();
215
-
216
- expect(service.revisionId).toBe('specific-rev-id');
217
- });
218
- });
219
-
220
- describe('connection properties after connect', () => {
221
- it('provides access to headRevisionId', async () => {
222
- setupSuccessfulConnection(mockUrl, {
223
- headId: 'test-head-id',
224
- draftId: 'test-draft-id',
225
- });
226
-
227
- await service.connect();
228
-
229
- expect(service.headRevisionId).toBe('test-head-id');
230
- });
231
-
232
- it('provides access to draftRevisionId', async () => {
233
- setupSuccessfulConnection(mockUrl, {
234
- headId: 'test-head-id',
235
- draftId: 'test-draft-id',
236
- });
237
-
238
- await service.connect();
239
-
240
- expect(service.draftRevisionId).toBe('test-draft-id');
241
- });
242
- });
243
-
244
- function setupSuccessfulConnection(
245
- url: RevisiumUrlComplete,
246
- revisions: { headId: string; draftId: string },
247
- ) {
248
- urlBuilderServiceFake.parseAndComplete.mockResolvedValue(url);
249
-
250
- const resolveRevisionId = (): string => {
251
- if (url.revision === 'head') {
252
- return revisions.headId;
253
- }
254
- if (url.revision === 'draft') {
255
- return revisions.draftId;
256
- }
257
- return url.revision;
258
- };
259
-
260
- connectionFactoryFake.createConnection.mockResolvedValue({
261
- url,
262
- client: createMockApiClient(),
263
- revisionId: resolveRevisionId(),
264
- headRevisionId: revisions.headId,
265
- draftRevisionId: revisions.draftId,
266
- });
267
- }
268
-
269
164
  function createMockConnectionInfo(url: RevisiumUrlComplete) {
270
165
  return {
271
166
  url,
272
167
  client: createMockApiClient(),
273
- revisionId: 'draft-id',
274
- headRevisionId: 'head-id',
275
- draftRevisionId: 'draft-id',
168
+ branchScope: createMockBranchScope(),
169
+ revisionScope: createMockRevisionScope(),
276
170
  };
277
171
  }
278
172
 
279
173
  function createMockApiClient() {
280
174
  return {
281
- api: {
282
- me: jest.fn().mockResolvedValue({ data: { username: 'test-user' } }),
283
- project: jest.fn().mockResolvedValue({ data: { id: 'project-id' } }),
284
- headRevision: jest.fn().mockResolvedValue({ data: { id: 'head-id' } }),
285
- draftRevision: jest
286
- .fn()
287
- .mockResolvedValue({ data: { id: 'draft-id' } }),
175
+ client: {
176
+ me: jest.fn().mockResolvedValue({ username: 'test-user' }),
177
+ branch: jest.fn(),
288
178
  },
289
179
  authenticate: jest.fn().mockResolvedValue('test-user'),
290
180
  };
291
181
  }
182
+
183
+ function createMockBranchScope() {
184
+ return {
185
+ draft: jest.fn(),
186
+ head: jest.fn(),
187
+ headRevisionId: 'head-id',
188
+ draftRevisionId: 'draft-id',
189
+ };
190
+ }
191
+
192
+ function createMockRevisionScope() {
193
+ return {
194
+ getTables: jest.fn(),
195
+ getRows: jest.fn(),
196
+ getMigrations: jest.fn(),
197
+ commit: jest.fn(),
198
+ revisionId: 'draft-id',
199
+ isDraft: true,
200
+ };
201
+ }
292
202
  });
@@ -1,58 +1,54 @@
1
- import { Api } from 'src/__generated__/api';
1
+ import { RevisionScope } from '@revisium/client';
2
2
  import { ApiClient } from '../sync/row-sync.service';
3
3
 
4
- type GeneratedApi = Api<unknown>['api'];
5
-
6
- export function createApiClientAdapter(api: GeneratedApi): ApiClient {
4
+ export function createApiClientAdapter(
5
+ revisionScope: RevisionScope,
6
+ ): ApiClient {
7
7
  return {
8
- async rows(revisionId, tableId, options) {
9
- const result = await api.rows(revisionId, tableId, {
10
- first: options.first,
11
- after: options.after,
12
- orderBy: options.orderBy,
13
- });
14
-
15
- if (result.error) {
16
- return { error: result.error };
17
- }
18
-
19
- return {
20
- data: {
21
- edges: result.data.edges.map((edge) => ({
22
- node: { id: edge.node.id, data: edge.node.data },
23
- })),
24
- pageInfo: {
25
- hasNextPage: result.data.pageInfo.hasNextPage,
26
- endCursor: result.data.pageInfo.endCursor ?? '',
8
+ async rows(tableId, options) {
9
+ try {
10
+ const data = await revisionScope.getRows(tableId, {
11
+ first: options.first,
12
+ after: options.after,
13
+ orderBy: options.orderBy,
14
+ });
15
+
16
+ return {
17
+ data: {
18
+ edges: data.edges.map((e) => ({
19
+ node: { id: e.node.id, data: e.node.data },
20
+ })),
21
+ pageInfo: {
22
+ hasNextPage: data.pageInfo.hasNextPage,
23
+ endCursor: data.pageInfo.endCursor ?? '',
24
+ },
27
25
  },
28
- },
29
- };
26
+ };
27
+ } catch (error) {
28
+ return { error };
29
+ }
30
30
  },
31
31
 
32
- async createRows(revisionId, tableId, data) {
33
- const result = await api.createRows(revisionId, tableId, {
34
- rows: data.rows,
35
- isRestore: data.isRestore,
36
- });
37
-
38
- if (result.error) {
39
- return { error: result.error };
32
+ async createRows(tableId, data) {
33
+ try {
34
+ await revisionScope.createRows(tableId, data.rows, {
35
+ isRestore: data.isRestore,
36
+ });
37
+ return { data: true };
38
+ } catch (error) {
39
+ return { error };
40
40
  }
41
-
42
- return { data: result.data };
43
41
  },
44
42
 
45
- async updateRows(revisionId, tableId, data) {
46
- const result = await api.updateRows(revisionId, tableId, {
47
- rows: data.rows,
48
- isRestore: data.isRestore,
49
- });
50
-
51
- if (result.error) {
52
- return { error: result.error };
43
+ async updateRows(tableId, data) {
44
+ try {
45
+ await revisionScope.updateRows(tableId, data.rows, {
46
+ isRestore: data.isRestore,
47
+ });
48
+ return { data: true };
49
+ } catch (error) {
50
+ return { error };
53
51
  }
54
-
55
- return { data: result.data };
56
52
  },
57
53
  };
58
54
  }
@@ -1,11 +1,11 @@
1
- import { Api, RequestParams } from 'src/__generated__/api';
1
+ import { RevisiumClient } from '@revisium/client';
2
2
  import { AuthCredentials } from '../url';
3
3
 
4
- export class RevisiumApiClient extends Api<unknown> {
5
- public authToken: string | undefined = undefined;
4
+ export class RevisiumApiClient {
5
+ public readonly client: RevisiumClient;
6
6
 
7
7
  constructor(baseUrl: string) {
8
- super({ baseUrl });
8
+ this.client = new RevisiumClient({ baseUrl });
9
9
  }
10
10
 
11
11
  public async authenticate(auth: AuthCredentials): Promise<string> {
@@ -32,61 +32,22 @@ export class RevisiumApiClient extends Api<unknown> {
32
32
  }
33
33
 
34
34
  private async authenticateWithToken(token: string): Promise<string> {
35
- this.authToken = token;
36
- const response = await this.api.me();
37
-
38
- if (response.error) {
39
- throw new Error(
40
- `Token validation failed: ${JSON.stringify(response.error)}`,
41
- );
42
- }
43
-
44
- return response.data.username || 'authenticated user';
35
+ this.client.loginWithToken(token);
36
+ const me = await this.client.me();
37
+ return me.username || 'authenticated user';
45
38
  }
46
39
 
47
40
  private async authenticateWithApiKey(apikey: string): Promise<string> {
48
- this.authToken = apikey;
49
- const response = await this.api.me();
50
-
51
- if (response.error) {
52
- throw new Error(
53
- `API key validation failed: ${JSON.stringify(response.error)}`,
54
- );
55
- }
56
-
57
- return response.data.username || 'authenticated user';
41
+ this.client.loginWithToken(apikey);
42
+ const me = await this.client.me();
43
+ return me.username || 'authenticated user';
58
44
  }
59
45
 
60
46
  private async authenticateWithPassword(
61
47
  username: string,
62
48
  password: string,
63
49
  ): Promise<string> {
64
- const response = await this.api.login({
65
- emailOrUsername: username,
66
- password: password,
67
- });
68
-
69
- if (response.error) {
70
- throw new Error(`Login failed: ${JSON.stringify(response.error)}`);
71
- }
72
-
73
- this.authToken = response.data.accessToken;
50
+ await this.client.login(username, password);
74
51
  return username;
75
52
  }
76
-
77
- protected mergeRequestParams(
78
- params1: RequestParams,
79
- params2?: RequestParams,
80
- ): RequestParams {
81
- const params = super.mergeRequestParams(params1, params2);
82
-
83
- params.headers ??= {};
84
-
85
- if (this.authToken) {
86
- (params.headers as Record<string, string>)['Authorization'] =
87
- `Bearer ${this.authToken}`;
88
- }
89
-
90
- return params;
91
- }
92
53
  }
@@ -1,4 +1,5 @@
1
1
  import { Injectable } from '@nestjs/common';
2
+ import { BranchScope, RevisionScope } from '@revisium/client';
2
3
  import { RevisiumApiClient } from './api-client';
3
4
  import { LoggerService } from '../common';
4
5
  import { RevisiumUrlComplete, UrlBuilderService } from '../url';
@@ -6,9 +7,8 @@ import { RevisiumUrlComplete, UrlBuilderService } from '../url';
6
7
  export interface ConnectionInfo {
7
8
  url: RevisiumUrlComplete;
8
9
  client: RevisiumApiClient;
9
- revisionId: string;
10
- headRevisionId: string;
11
- draftRevisionId: string;
10
+ branchScope: BranchScope;
11
+ revisionScope: RevisionScope;
12
12
  }
13
13
 
14
14
  export interface ConnectOptions {
@@ -32,11 +32,24 @@ export class ConnectionFactoryService {
32
32
  this.logger.connecting(label, formattedUrl);
33
33
 
34
34
  const client = await this.createAuthenticatedClient(url);
35
- await this.validateProject(client, url);
36
- const revisions = await this.fetchRevisions(client, url);
37
35
 
38
- const revisionId = this.resolveRevisionId(url.revision, revisions);
39
- const revisionLabel = this.formatRevisionLabel(url.revision, revisions);
36
+ const branchScope = await client.client.branch({
37
+ org: url.organization,
38
+ project: url.project,
39
+ branch: url.branch || 'master',
40
+ });
41
+
42
+ const revisionScope = await this.resolveRevisionScope(
43
+ url.revision,
44
+ branchScope,
45
+ );
46
+ const revisionId = revisionScope.revisionId;
47
+ const revisionLabel = this.formatRevisionLabel(
48
+ url.revision,
49
+ branchScope.headRevisionId,
50
+ branchScope.draftRevisionId,
51
+ revisionId,
52
+ );
40
53
 
41
54
  this.logger.connected(
42
55
  `Project: ${url.organization}/${url.project}, Branch: ${url.branch || 'master'}, Revision: ${revisionLabel}`,
@@ -45,9 +58,8 @@ export class ConnectionFactoryService {
45
58
  return {
46
59
  url,
47
60
  client,
48
- revisionId,
49
- headRevisionId: revisions.headRevisionId,
50
- draftRevisionId: revisions.draftRevisionId,
61
+ branchScope,
62
+ revisionScope,
51
63
  };
52
64
  }
53
65
 
@@ -62,64 +74,24 @@ export class ConnectionFactoryService {
62
74
  return client;
63
75
  }
64
76
 
65
- private async validateProject(
66
- client: RevisiumApiClient,
67
- url: RevisiumUrlComplete,
68
- ): Promise<void> {
69
- const response = await client.api.project(url.organization, url.project);
70
-
71
- if (response.error) {
72
- throw new Error(
73
- `Failed to get project: ${JSON.stringify(response.error)}`,
74
- );
75
- }
76
- }
77
-
78
- private async fetchRevisions(
79
- client: RevisiumApiClient,
80
- url: RevisiumUrlComplete,
81
- ): Promise<{ headRevisionId: string; draftRevisionId: string }> {
82
- const branchName = url.branch || 'master';
83
-
84
- const [headResponse, draftResponse] = await Promise.all([
85
- client.api.headRevision(url.organization, url.project, branchName),
86
- client.api.draftRevision(url.organization, url.project, branchName),
87
- ]);
88
-
89
- if (headResponse.error) {
90
- throw new Error(
91
- `Failed to get head revision: ${JSON.stringify(headResponse.error)}`,
92
- );
93
- }
94
-
95
- if (draftResponse.error) {
96
- throw new Error(
97
- `Failed to get draft revision: ${JSON.stringify(draftResponse.error)}`,
98
- );
99
- }
100
-
101
- return {
102
- headRevisionId: headResponse.data.id,
103
- draftRevisionId: draftResponse.data.id,
104
- };
105
- }
106
-
107
- private resolveRevisionId(
77
+ private async resolveRevisionScope(
108
78
  revision: string,
109
- revisions: { headRevisionId: string; draftRevisionId: string },
110
- ): string {
111
- if (revision === 'head') {
112
- return revisions.headRevisionId;
113
- }
79
+ branchScope: BranchScope,
80
+ ): Promise<RevisionScope> {
114
81
  if (revision === 'draft') {
115
- return revisions.draftRevisionId;
82
+ return branchScope.draft();
116
83
  }
117
- return revision;
84
+ if (revision === 'head') {
85
+ return branchScope.head();
86
+ }
87
+ return branchScope.revision(revision);
118
88
  }
119
89
 
120
90
  private formatRevisionLabel(
121
91
  revision: string,
122
- revisions: { headRevisionId: string; draftRevisionId: string },
92
+ headRevisionId: string,
93
+ draftRevisionId: string,
94
+ resolvedId: string,
123
95
  ): string {
124
96
  if (revision === 'head') {
125
97
  return 'head';
@@ -128,12 +100,10 @@ export class ConnectionFactoryService {
128
100
  return 'draft';
129
101
  }
130
102
 
131
- const resolvedId = this.resolveRevisionId(revision, revisions);
132
-
133
- if (resolvedId === revisions.headRevisionId) {
103
+ if (resolvedId === headRevisionId) {
134
104
  return `${resolvedId} (head)`;
135
105
  }
136
- if (resolvedId === revisions.draftRevisionId) {
106
+ if (resolvedId === draftRevisionId) {
137
107
  return `${resolvedId} (draft)`;
138
108
  }
139
109
 
@@ -1,5 +1,6 @@
1
1
  import { Injectable } from '@nestjs/common';
2
2
  import { ConfigService } from '@nestjs/config';
3
+ import { RevisionScope } from '@revisium/client';
3
4
  import {
4
5
  ConnectionFactoryService,
5
6
  ConnectionInfo,
@@ -29,20 +30,8 @@ export class ConnectionService {
29
30
  return this._connection;
30
31
  }
31
32
 
32
- public get api() {
33
- return this.connection.client.api;
34
- }
35
-
36
- public get revisionId(): string {
37
- return this.connection.revisionId;
38
- }
39
-
40
- public get draftRevisionId(): string {
41
- return this.connection.draftRevisionId;
42
- }
43
-
44
- public get headRevisionId(): string {
45
- return this.connection.headRevisionId;
33
+ public get revisionScope(): RevisionScope {
34
+ return this.connection.revisionScope;
46
35
  }
47
36
 
48
37
  public async connect(options: ConnectionOptions = {}): Promise<void> {
@@ -97,7 +97,7 @@ describe('RowSyncService', () => {
97
97
  updateRows: jest.fn(),
98
98
  };
99
99
 
100
- const result = await service.getExistingRows(mockApi, 'rev1', 'table1');
100
+ const result = await service.getExistingRows(mockApi, 'table1');
101
101
 
102
102
  expect(result.size).toBe(3);
103
103
  expect(result.get('row1')).toEqual({ name: 'A' });
@@ -113,7 +113,7 @@ describe('RowSyncService', () => {
113
113
  updateRows: jest.fn(),
114
114
  };
115
115
 
116
- const result = await service.getExistingRows(mockApi, 'rev1', 'table1');
116
+ const result = await service.getExistingRows(mockApi, 'table1');
117
117
 
118
118
  expect(result.size).toBe(0);
119
119
  });
@@ -131,7 +131,7 @@ describe('RowSyncService', () => {
131
131
  };
132
132
  const onProgress = jest.fn();
133
133
 
134
- await service.getExistingRows(mockApi, 'rev1', 'table1', onProgress);
134
+ await service.getExistingRows(mockApi, 'table1', onProgress);
135
135
 
136
136
  expect(onProgress).toHaveBeenCalledWith({
137
137
  operation: 'fetch',
@@ -160,7 +160,6 @@ describe('RowSyncService', () => {
160
160
 
161
161
  const stats = await service.syncTableRows(
162
162
  mockApi,
163
- 'rev1',
164
163
  'table1',
165
164
  sourceRows,
166
165
  100,
@@ -188,7 +187,6 @@ describe('RowSyncService', () => {
188
187
 
189
188
  const stats = await service.syncTableRows(
190
189
  mockApi,
191
- 'rev1',
192
190
  'table1',
193
191
  sourceRows,
194
192
  100,
@@ -217,7 +215,6 @@ describe('RowSyncService', () => {
217
215
 
218
216
  const stats = await service.syncTableRows(
219
217
  mockApi,
220
- 'rev1',
221
218
  'table1',
222
219
  sourceRows,
223
220
  100,
@@ -1,4 +1,5 @@
1
1
  import { Injectable } from '@nestjs/common';
2
+ import { RevisionScope } from '@revisium/client';
2
3
  import { ConnectionInfo as SyncConnectionInfo } from './sync-api.service';
3
4
  import { ConnectionService } from '../connection';
4
5
  import { LoggerService } from '../common';
@@ -7,20 +8,6 @@ export interface CommitResult {
7
8
  revisionId: string;
8
9
  }
9
10
 
10
- interface CommitParams {
11
- organization: string;
12
- project: string;
13
- branch: string;
14
- api: {
15
- createRevision: (
16
- org: string,
17
- proj: string,
18
- branch: string,
19
- data: { comment: string },
20
- ) => Promise<{ data?: { id: string }; error?: unknown }>;
21
- };
22
- }
23
-
24
11
  @Injectable()
25
12
  export class CommitRevisionService {
26
13
  constructor(
@@ -34,12 +21,7 @@ export class CommitRevisionService {
34
21
  ): Promise<CommitResult> {
35
22
  const connection = this.connectionService.connection;
36
23
  return this.doCommit(
37
- {
38
- organization: connection.url.organization,
39
- project: connection.url.project,
40
- branch: connection.url.branch,
41
- api: connection.client.api,
42
- },
24
+ connection.revisionScope,
43
25
  actionDescription,
44
26
  changeCount,
45
27
  );
@@ -69,19 +51,14 @@ export class CommitRevisionService {
69
51
  }
70
52
 
71
53
  await this.doCommit(
72
- {
73
- organization: connection.url.organization,
74
- project: connection.url.project,
75
- branch: connection.url.branch,
76
- api: connection.client.api,
77
- },
54
+ connection.revisionScope,
78
55
  actionDescription,
79
56
  changeCount,
80
57
  );
81
58
  }
82
59
 
83
60
  private async doCommit(
84
- params: CommitParams,
61
+ revisionScope: RevisionScope,
85
62
  actionDescription: string,
86
63
  changeCount: number,
87
64
  ): Promise<CommitResult> {
@@ -89,37 +66,16 @@ export class CommitRevisionService {
89
66
 
90
67
  const comment = this.generateCommitComment(actionDescription, changeCount);
91
68
 
92
- let result: { data?: { id: string }; error?: unknown };
93
69
  try {
94
- result = await params.api.createRevision(
95
- params.organization,
96
- params.project,
97
- params.branch,
98
- { comment },
99
- );
70
+ const revision = await revisionScope.commit(comment);
71
+ this.logger.commitSuccess(revision.id);
72
+ return { revisionId: revision.id };
100
73
  } catch (error) {
101
74
  const errorMessage =
102
75
  error instanceof Error ? error.message : String(error);
103
76
  this.logger.commitError(errorMessage);
104
77
  throw error;
105
78
  }
106
-
107
- if (result.error) {
108
- const errorMessage =
109
- typeof result.error === 'string'
110
- ? result.error
111
- : JSON.stringify(result.error);
112
- this.logger.commitError(errorMessage);
113
- throw new Error(errorMessage);
114
- }
115
-
116
- if (result.data) {
117
- this.logger.commitSuccess(result.data.id);
118
- return { revisionId: result.data.id };
119
- }
120
-
121
- this.logger.commitError('No data returned');
122
- throw new Error('Failed to create revision');
123
79
  }
124
80
 
125
81
  private generateCommitComment(