retold-data-service 2.0.33 → 2.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/_cover.md CHANGED
@@ -1,4 +1,4 @@
1
- # Retold Data Service <small>v2.0.11</small>
1
+ # Retold Data Service
2
2
 
3
3
  > Schema-driven REST API generation for the Retold ecosystem
4
4
 
@@ -0,0 +1,7 @@
1
+ {
2
+ "Name": "retold-data-service",
3
+ "Version": "2.0.33",
4
+ "Description": "Serve up a whole model!",
5
+ "GeneratedAt": "2026-04-10T17:22:17.821Z",
6
+ "GitCommit": "bfd3f2c"
7
+ }
@@ -1,73 +1,327 @@
1
1
  /* ============================================================================
2
- Pict Docuserve - Base Styles
2
+ Pict Docuserve - Base Styles & Theme Variables
3
3
  ============================================================================ */
4
4
 
5
- /* Reset and base */
6
- *, *::before, *::after {
5
+ /* ----------------------------------------------------------------------------
6
+ Theme variables light defaults on :root.
7
+ Dark mode applies when either:
8
+ (a) the user explicitly selected dark via <html data-theme="dark">
9
+ (b) the user hasn't chosen anything AND the system prefers dark
10
+ An explicit <html data-theme="light"> pins the light palette regardless.
11
+ ---------------------------------------------------------------------------- */
12
+
13
+ :root
14
+ {
15
+ /* Surfaces */
16
+ --docuserve-bg: #FDFBF7;
17
+ --docuserve-bg-elevated: #FFFFFF;
18
+ --docuserve-border: #DDD6CA;
19
+ --docuserve-border-soft: #EAE3D8;
20
+
21
+ /* Text */
22
+ --docuserve-text: #2A241E;
23
+ --docuserve-text-strong: #3D3229;
24
+ --docuserve-text-muted: #5E5549;
25
+ --docuserve-text-dim: #8A7F72;
26
+
27
+ /* Accent / links */
28
+ --docuserve-accent: #2E7D74;
29
+ --docuserve-accent-hover: #236660;
30
+
31
+ /* Top bar */
32
+ --docuserve-topbar-bg: #3D3229;
33
+ --docuserve-topbar-text: #E8E0D4;
34
+ --docuserve-topbar-text-muted: #B5AA9A;
35
+ --docuserve-topbar-text-dim: #8A7F72;
36
+ --docuserve-topbar-hover-bg: #524438;
37
+ --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.06);
38
+ --docuserve-topbar-version-border: rgba(255, 255, 255, 0.08);
39
+ --docuserve-topbar-version-text: #B5AA9A;
40
+
41
+ /* Sidebar */
42
+ --docuserve-sidebar-bg: #FAF7F1;
43
+ --docuserve-sidebar-border: #DDD6CA;
44
+ --docuserve-sidebar-border-soft: #E5DED1;
45
+ --docuserve-sidebar-text: #423D37;
46
+ --docuserve-sidebar-group-title: #3D3229;
47
+ --docuserve-sidebar-module-text: #5E5549;
48
+ --docuserve-sidebar-hover-bg: #EAE3D8;
49
+ --docuserve-sidebar-hover-text: #2E7D74;
50
+ --docuserve-sidebar-active-bg: #E5DED1;
51
+ --docuserve-sidebar-active-text: #2E7D74;
52
+ --docuserve-sidebar-search-bg: #FFFFFF;
53
+ --docuserve-sidebar-search-border: #DDD6CA;
54
+
55
+ /* Inline code */
56
+ --docuserve-inline-code-bg: #F0ECE4;
57
+ --docuserve-inline-code-text: #9E3A50;
58
+
59
+ /* Code block panel */
60
+ --docuserve-code-bg: #F6F3EE;
61
+ --docuserve-code-border: #E5DED1;
62
+ --docuserve-code-gutter-bg: #EFEAE0;
63
+ --docuserve-code-gutter-border: #DDD6CA;
64
+ --docuserve-code-gutter-text: #A59986;
65
+ --docuserve-code-text: #2A241E;
66
+
67
+ /* Syntax tokens — low-chroma dark-on-light palette */
68
+ --docuserve-tok-keyword: #A03472;
69
+ --docuserve-tok-string: #1A6640;
70
+ --docuserve-tok-number: #B25A00;
71
+ --docuserve-tok-comment: #8A7F72;
72
+ --docuserve-tok-operator: #2E7D74;
73
+ --docuserve-tok-punctuation: #2A241E;
74
+ --docuserve-tok-function: #2A5DB0;
75
+ --docuserve-tok-property: #9E3A50;
76
+ --docuserve-tok-tag: #9E3A50;
77
+ --docuserve-tok-attr-name: #B25A00;
78
+ --docuserve-tok-attr-value: #1A6640;
79
+
80
+ /* Tables, blockquotes, mermaid */
81
+ --docuserve-table-header-bg: #F5F0E8;
82
+ --docuserve-table-row-alt-bg: #F9F6F0;
83
+ --docuserve-blockquote-bg: #F7F5F0;
84
+ --docuserve-blockquote-border: #2E7D74;
85
+ --docuserve-blockquote-text: #5E5549;
86
+ --docuserve-mermaid-bg: #FFFFFF;
87
+
88
+ /* Scrollbars */
89
+ --docuserve-scrollbar-track: #F5F0E8;
90
+ --docuserve-scrollbar-thumb: #D4CCBE;
91
+ --docuserve-scrollbar-thumb-hover: #B5AA9A;
92
+ }
93
+
94
+ @media (prefers-color-scheme: dark)
95
+ {
96
+ :root:not([data-theme="light"])
97
+ {
98
+ --docuserve-bg: #15120F;
99
+ --docuserve-bg-elevated: #1B1814;
100
+ --docuserve-border: #2F2823;
101
+ --docuserve-border-soft: #26211C;
102
+
103
+ --docuserve-text: #E8E0D4;
104
+ --docuserve-text-strong: #F2ECE0;
105
+ --docuserve-text-muted: #B5AA9A;
106
+ --docuserve-text-dim: #7A6F62;
107
+
108
+ --docuserve-accent: #5DB8A8;
109
+ --docuserve-accent-hover: #7FCCB8;
110
+
111
+ --docuserve-topbar-bg: #1A1612;
112
+ --docuserve-topbar-text: #E8E0D4;
113
+ --docuserve-topbar-text-muted: #B5AA9A;
114
+ --docuserve-topbar-text-dim: #7A6F62;
115
+ --docuserve-topbar-hover-bg: #2A241E;
116
+ --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
117
+ --docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
118
+ --docuserve-topbar-version-text: #B5AA9A;
119
+
120
+ --docuserve-sidebar-bg: #1B1814;
121
+ --docuserve-sidebar-border: #2F2823;
122
+ --docuserve-sidebar-border-soft: #26211C;
123
+ --docuserve-sidebar-text: #C9C0B3;
124
+ --docuserve-sidebar-group-title: #F2ECE0;
125
+ --docuserve-sidebar-module-text: #B5AA9A;
126
+ --docuserve-sidebar-hover-bg: #2A241E;
127
+ --docuserve-sidebar-hover-text: #7FCCB8;
128
+ --docuserve-sidebar-active-bg: #2F2823;
129
+ --docuserve-sidebar-active-text: #7FCCB8;
130
+ --docuserve-sidebar-search-bg: #26211C;
131
+ --docuserve-sidebar-search-border: #2F2823;
132
+
133
+ --docuserve-inline-code-bg: #2A241E;
134
+ --docuserve-inline-code-text: #E8B07A;
135
+
136
+ --docuserve-code-bg: #1E1A17;
137
+ --docuserve-code-border: #2F2823;
138
+ --docuserve-code-gutter-bg: #17130F;
139
+ --docuserve-code-gutter-border: #2F2823;
140
+ --docuserve-code-gutter-text: #6A6052;
141
+ --docuserve-code-text: #E8E0D4;
142
+
143
+ --docuserve-tok-keyword: #C678DD;
144
+ --docuserve-tok-string: #98C379;
145
+ --docuserve-tok-number: #D19A66;
146
+ --docuserve-tok-comment: #7F848E;
147
+ --docuserve-tok-operator: #56B6C2;
148
+ --docuserve-tok-punctuation: #E8E0D4;
149
+ --docuserve-tok-function: #61AFEF;
150
+ --docuserve-tok-property: #E06C75;
151
+ --docuserve-tok-tag: #E06C75;
152
+ --docuserve-tok-attr-name: #D19A66;
153
+ --docuserve-tok-attr-value: #98C379;
154
+
155
+ --docuserve-table-header-bg: #26211C;
156
+ --docuserve-table-row-alt-bg: #1F1B17;
157
+ --docuserve-blockquote-bg: #1F1B17;
158
+ --docuserve-blockquote-border: #5DB8A8;
159
+ --docuserve-blockquote-text: #C9C0B3;
160
+ --docuserve-mermaid-bg: #E8E0D4;
161
+
162
+ --docuserve-scrollbar-track: #1B1814;
163
+ --docuserve-scrollbar-thumb: #3A322B;
164
+ --docuserve-scrollbar-thumb-hover: #524438;
165
+ }
166
+ }
167
+
168
+ :root[data-theme="dark"]
169
+ {
170
+ --docuserve-bg: #15120F;
171
+ --docuserve-bg-elevated: #1B1814;
172
+ --docuserve-border: #2F2823;
173
+ --docuserve-border-soft: #26211C;
174
+
175
+ --docuserve-text: #E8E0D4;
176
+ --docuserve-text-strong: #F2ECE0;
177
+ --docuserve-text-muted: #B5AA9A;
178
+ --docuserve-text-dim: #7A6F62;
179
+
180
+ --docuserve-accent: #5DB8A8;
181
+ --docuserve-accent-hover: #7FCCB8;
182
+
183
+ --docuserve-topbar-bg: #1A1612;
184
+ --docuserve-topbar-text: #E8E0D4;
185
+ --docuserve-topbar-text-muted: #B5AA9A;
186
+ --docuserve-topbar-text-dim: #7A6F62;
187
+ --docuserve-topbar-hover-bg: #2A241E;
188
+ --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
189
+ --docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
190
+ --docuserve-topbar-version-text: #B5AA9A;
191
+
192
+ --docuserve-sidebar-bg: #1B1814;
193
+ --docuserve-sidebar-border: #2F2823;
194
+ --docuserve-sidebar-border-soft: #26211C;
195
+ --docuserve-sidebar-text: #C9C0B3;
196
+ --docuserve-sidebar-group-title: #F2ECE0;
197
+ --docuserve-sidebar-module-text: #B5AA9A;
198
+ --docuserve-sidebar-hover-bg: #2A241E;
199
+ --docuserve-sidebar-hover-text: #7FCCB8;
200
+ --docuserve-sidebar-active-bg: #2F2823;
201
+ --docuserve-sidebar-active-text: #7FCCB8;
202
+ --docuserve-sidebar-search-bg: #26211C;
203
+ --docuserve-sidebar-search-border: #2F2823;
204
+
205
+ --docuserve-inline-code-bg: #2A241E;
206
+ --docuserve-inline-code-text: #E8B07A;
207
+
208
+ --docuserve-code-bg: #1E1A17;
209
+ --docuserve-code-border: #2F2823;
210
+ --docuserve-code-gutter-bg: #17130F;
211
+ --docuserve-code-gutter-border: #2F2823;
212
+ --docuserve-code-gutter-text: #6A6052;
213
+ --docuserve-code-text: #E8E0D4;
214
+
215
+ --docuserve-tok-keyword: #C678DD;
216
+ --docuserve-tok-string: #98C379;
217
+ --docuserve-tok-number: #D19A66;
218
+ --docuserve-tok-comment: #7F848E;
219
+ --docuserve-tok-operator: #56B6C2;
220
+ --docuserve-tok-punctuation: #E8E0D4;
221
+ --docuserve-tok-function: #61AFEF;
222
+ --docuserve-tok-property: #E06C75;
223
+ --docuserve-tok-tag: #E06C75;
224
+ --docuserve-tok-attr-name: #D19A66;
225
+ --docuserve-tok-attr-value: #98C379;
226
+
227
+ --docuserve-table-header-bg: #26211C;
228
+ --docuserve-table-row-alt-bg: #1F1B17;
229
+ --docuserve-blockquote-bg: #1F1B17;
230
+ --docuserve-blockquote-border: #5DB8A8;
231
+ --docuserve-blockquote-text: #C9C0B3;
232
+ --docuserve-mermaid-bg: #E8E0D4;
233
+
234
+ --docuserve-scrollbar-track: #1B1814;
235
+ --docuserve-scrollbar-thumb: #3A322B;
236
+ --docuserve-scrollbar-thumb-hover: #524438;
237
+ }
238
+
239
+ /* ----------------------------------------------------------------------------
240
+ Reset and base
241
+ ---------------------------------------------------------------------------- */
242
+
243
+ *, *::before, *::after
244
+ {
7
245
  box-sizing: border-box;
8
246
  }
9
247
 
10
- html, body {
248
+ html, body
249
+ {
11
250
  margin: 0;
12
251
  padding: 0;
13
252
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14
253
  font-size: 16px;
15
254
  line-height: 1.5;
16
- color: #423D37;
17
- background-color: #fff;
255
+ color: var(--docuserve-text);
256
+ background-color: var(--docuserve-bg);
18
257
  -webkit-font-smoothing: antialiased;
19
258
  -moz-osx-font-smoothing: grayscale;
259
+ transition: background-color 0.15s ease, color 0.15s ease;
20
260
  }
21
261
 
22
262
  /* Typography */
23
- h1, h2, h3, h4, h5, h6 {
263
+ h1, h2, h3, h4, h5, h6
264
+ {
24
265
  margin-top: 0;
25
266
  line-height: 1.3;
267
+ color: var(--docuserve-text-strong);
26
268
  }
27
269
 
28
- a {
29
- color: #2E7D74;
270
+ a
271
+ {
272
+ color: var(--docuserve-accent);
30
273
  text-decoration: none;
31
274
  }
32
275
 
33
- a:hover {
34
- color: #256861;
276
+ a:hover
277
+ {
278
+ color: var(--docuserve-accent-hover);
35
279
  }
36
280
 
37
281
  /* Application container */
38
- #Docuserve-Application-Container {
282
+ #Docuserve-Application-Container
283
+ {
39
284
  min-height: 100vh;
40
285
  }
41
286
 
42
287
  /* Utility: scrollbar styling */
43
- ::-webkit-scrollbar {
288
+ ::-webkit-scrollbar
289
+ {
44
290
  width: 8px;
291
+ height: 8px;
45
292
  }
46
293
 
47
- ::-webkit-scrollbar-track {
48
- background: #F5F0E8;
294
+ ::-webkit-scrollbar-track
295
+ {
296
+ background: var(--docuserve-scrollbar-track);
49
297
  }
50
298
 
51
- ::-webkit-scrollbar-thumb {
52
- background: #D4CCBE;
299
+ ::-webkit-scrollbar-thumb
300
+ {
301
+ background: var(--docuserve-scrollbar-thumb);
53
302
  border-radius: 4px;
54
303
  }
55
304
 
56
- ::-webkit-scrollbar-thumb:hover {
57
- background: #B5AA9A;
305
+ ::-webkit-scrollbar-thumb:hover
306
+ {
307
+ background: var(--docuserve-scrollbar-thumb-hover);
58
308
  }
59
309
 
60
310
  /* Responsive adjustments */
61
- @media (max-width: 768px) {
62
- html {
311
+ @media (max-width: 768px)
312
+ {
313
+ html
314
+ {
63
315
  font-size: 14px;
64
316
  }
65
317
 
66
- #Docuserve-Sidebar-Container {
318
+ #Docuserve-Sidebar-Container
319
+ {
67
320
  display: none;
68
321
  }
69
322
 
70
- .docuserve-body {
323
+ .docuserve-body
324
+ {
71
325
  flex-direction: column;
72
326
  }
73
327
  }
package/docs/endpoints.md CHANGED
@@ -7,8 +7,8 @@ Once initialized, Retold Data Service automatically creates RESTful endpoints fo
7
7
  All endpoints follow the Meadow Endpoints URL pattern:
8
8
 
9
9
  ```
10
- /{Version}/{Entity} singular entity operations (Read, Create, Update, Delete)
11
- /{Version}/{Entity}s plural entity operations (Reads, Count)
10
+ /{Version}/{Entity} -- singular entity operations (Read, Create, Update, Delete)
11
+ /{Version}/{Entity}s -- plural entity operations (Reads, Count)
12
12
  ```
13
13
 
14
14
  The version defaults to `1.0`.
package/docs/index.html CHANGED
@@ -4,9 +4,9 @@
4
4
  <meta charset="utf-8">
5
5
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
- <meta name="description" content="Documentation powered by pict-docuserve">
7
+ <meta name="description" content="Retold Data Service v2.0.33 Documentation Serve up a whole model!">
8
8
 
9
- <title>Documentation</title>
9
+ <title>Retold Data Service v2.0.33 Documentation</title>
10
10
 
11
11
  <!-- Application Stylesheet -->
12
12
  <link href="css/docuserve.css" rel="stylesheet">
@@ -30,12 +30,12 @@ _Fable.RetoldDataService.initializeService(
30
30
  When `initializeService()` is called, the following steps run in order:
31
31
 
32
32
  ```
33
- 1. onBeforeInitialize() your custom hook
34
- 2. Start Orator web server if AutoStartOrator is true
35
- 3. initializePersistenceEngine() loads the storage provider module
36
- 4. onInitialize() your custom hook
37
- 5. initializeDataEndpoints() loads model, creates DAL + endpoints
38
- 6. onAfterInitialize() your custom hook
33
+ 1. onBeforeInitialize() <- your custom hook
34
+ 2. Start Orator web server <- if AutoStartOrator is true
35
+ 3. initializePersistenceEngine() <- loads the storage provider module
36
+ 4. onInitialize() <- your custom hook
37
+ 5. initializeDataEndpoints() <- loads model, creates DAL + endpoints
38
+ 6. onAfterInitialize() <- your custom hook
39
39
  ```
40
40
 
41
41
  ### Step 5: initializeDataEndpoints()
@@ -1,5 +1,5 @@
1
1
  {
2
- "Generated": "2026-03-02T03:24:01.334Z",
2
+ "Generated": "2026-04-10T17:22:17.521Z",
3
3
  "GitHubOrg": "stevenvelozo",
4
4
  "DefaultBranch": "master",
5
5
  "Groups": [
@@ -50,23 +50,6 @@
50
50
  }
51
51
  ]
52
52
  },
53
- {
54
- "Name": "Debug",
55
- "Key": "debug",
56
- "Description": "",
57
- "Modules": [
58
- {
59
- "Name": "data",
60
- "Repo": "data",
61
- "Group": "debug",
62
- "Branch": "master",
63
- "HasDocs": false,
64
- "HasCover": false,
65
- "Sidebar": [],
66
- "DocFiles": []
67
- }
68
- ]
69
- },
70
53
  {
71
54
  "Name": "Dist",
72
55
  "Key": "dist",
@@ -123,6 +106,23 @@
123
106
  }
124
107
  ]
125
108
  },
109
+ {
110
+ "Name": "Source",
111
+ "Key": "source",
112
+ "Description": "",
113
+ "Modules": [
114
+ {
115
+ "Name": "services",
116
+ "Repo": "services",
117
+ "Group": "source",
118
+ "Branch": "master",
119
+ "HasDocs": false,
120
+ "HasCover": false,
121
+ "Sidebar": [],
122
+ "DocFiles": []
123
+ }
124
+ ]
125
+ },
126
126
  {
127
127
  "Name": "Test",
128
128
  "Key": "test",
@@ -1,5 +1,5 @@
1
1
  {
2
- "Generated": "2026-03-02T03:24:01.450Z",
2
+ "Generated": "2026-04-10T17:22:17.785Z",
3
3
  "DocumentCount": 9,
4
4
  "LunrIndex": {
5
5
  "version": "2.3.9",
@@ -43,7 +43,7 @@ $Name 200
43
43
 
44
44
  | Symbol | Meaning | Meadow Type |
45
45
  |--------|---------|-------------|
46
- | `!` | Table/entity name | |
46
+ | `!` | Table/entity name | -- |
47
47
  | `@` | Auto-increment ID | `AutoIdentity` |
48
48
  | `%` | Auto GUID | `AutoGUID` |
49
49
  | `&` | DateTime column | `CreateDate`, `UpdateDate`, `DeleteDate`, or `DateTime` |
@@ -121,8 +121,8 @@ This runs `cd test && npx stricture -i model/ddl/BookStore.ddl` to regenerate th
121
121
  | `Deleted` | Soft-delete flag | On Delete (set to 1) |
122
122
  | `DeleteDate` | Deletion timestamp | On Delete |
123
123
  | `DeleteIDUser` | Deleter user ID | On Delete |
124
- | `String` | Text data | |
125
- | `Integer` | Numeric data | |
126
- | `Decimal` | Decimal data | |
127
- | `Boolean` | Boolean data | |
128
- | `DateTime` | Date/time data | |
124
+ | `String` | Text data | -- |
125
+ | `Integer` | Numeric data | -- |
126
+ | `Decimal` | Decimal data | -- |
127
+ | `Boolean` | Boolean data | -- |
128
+ | `DateTime` | Date/time data | -- |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retold-data-service",
3
- "version": "2.0.33",
3
+ "version": "2.0.34",
4
4
  "description": "Serve up a whole model!",
5
5
  "main": "source/Retold-Data-Service.js",
6
6
  "bin": {
@@ -60,8 +60,9 @@
60
60
  "homepage": "https://github.com/stevenvelozo/retold-data-service",
61
61
  "devDependencies": {
62
62
  "meadow-connection-sqlite": "^1.0.18",
63
+ "pict-docuserve": "^0.1.5",
63
64
  "puppeteer": "^24.40.0",
64
- "quackage": "^1.0.65",
65
+ "quackage": "^1.1.0",
65
66
  "stricture": "^4.0.2",
66
67
  "supertest": "^7.2.2"
67
68
  },
@@ -251,7 +251,9 @@ module.exports = (pDataClonerService, pConfig, pCLIOptions, fCallback) =>
251
251
  PageSize: tmpSync.PageSize || 100,
252
252
  SyncDeletedRecords: !!tmpSync.SyncDeletedRecords,
253
253
  MaxRecordsPerEntity: tmpMaxRecords || tmpSync.MaxRecordsPerEntity || 0,
254
- DateTimePrecisionMS: tmpSync.DateTimePrecisionMS
254
+ DateTimePrecisionMS: tmpSync.DateTimePrecisionMS,
255
+ BackSyncTimeLimit: tmpSync.BackSyncTimeLimit,
256
+ TrueUpPageSize: tmpSync.TrueUpPageSize
255
257
  });
256
258
 
257
259
  tmpFable.log.info(`Headless: Starting ${tmpSyncBody.SyncMode} sync...`);
@@ -89,6 +89,36 @@ module.exports = (pDataClonerService, pOratorServiceServer) =>
89
89
  }
90
90
  }
91
91
 
92
+ // Update BackSyncTimeLimit on MeadowSync and all sync entities
93
+ if (tmpBody.hasOwnProperty('BackSyncTimeLimit'))
94
+ {
95
+ let tmpBackSyncTimeLimit = parseInt(tmpBody.BackSyncTimeLimit, 10);
96
+ if (!isNaN(tmpBackSyncTimeLimit) && tmpBackSyncTimeLimit > 0)
97
+ {
98
+ tmpFable.MeadowSync.BackSyncTimeLimit = tmpBackSyncTimeLimit;
99
+ let tmpEntityNames = Object.keys(tmpFable.MeadowSync.MeadowSyncEntities);
100
+ for (let i = 0; i < tmpEntityNames.length; i++)
101
+ {
102
+ tmpFable.MeadowSync.MeadowSyncEntities[tmpEntityNames[i]].BackSyncTimeLimit = tmpBackSyncTimeLimit;
103
+ }
104
+ }
105
+ }
106
+
107
+ // Update TrueUpPageSize on MeadowSync and all sync entities
108
+ if (tmpBody.hasOwnProperty('TrueUpPageSize'))
109
+ {
110
+ let tmpTrueUpPageSize = parseInt(tmpBody.TrueUpPageSize, 10);
111
+ if (!isNaN(tmpTrueUpPageSize) && tmpTrueUpPageSize > 0)
112
+ {
113
+ tmpFable.MeadowSync.TrueUpPageSize = tmpTrueUpPageSize;
114
+ let tmpEntityNames = Object.keys(tmpFable.MeadowSync.MeadowSyncEntities);
115
+ for (let i = 0; i < tmpEntityNames.length; i++)
116
+ {
117
+ tmpFable.MeadowSync.MeadowSyncEntities[tmpEntityNames[i]].TrueUpPageSize = tmpTrueUpPageSize;
118
+ }
119
+ }
120
+ }
121
+
92
122
  // If no tables specified, sync all entities
93
123
  if (tmpSelectedTables.length === 0)
94
124
  {
@@ -7,6 +7,25 @@ class DataClonerSyncView extends libPictView
7
7
  super(pFable, pOptions, pServiceHash);
8
8
  }
9
9
 
10
+ onSyncModeChanged()
11
+ {
12
+ let tmpMode = document.querySelector('input[name="syncMode"]:checked').value;
13
+
14
+ // Hide all mode-specific option panels
15
+ let tmpPanels = document.querySelectorAll('[id^="syncModeOptions-"]');
16
+ for (let i = 0; i < tmpPanels.length; i++)
17
+ {
18
+ tmpPanels[i].style.display = 'none';
19
+ }
20
+
21
+ // Show the panel for the selected mode (if one exists)
22
+ let tmpPanel = document.getElementById('syncModeOptions-' + tmpMode);
23
+ if (tmpPanel)
24
+ {
25
+ tmpPanel.style.display = 'block';
26
+ }
27
+ }
28
+
10
29
  startSync()
11
30
  {
12
31
  let tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();
@@ -34,6 +53,18 @@ class DataClonerSyncView extends libPictView
34
53
  if (tmpMaxRecords > 0) tmpPostBody.MaxRecordsPerEntity = tmpMaxRecords;
35
54
  if (tmpLogToFile) tmpPostBody.LogToFile = true;
36
55
  if (tmpAdvancedIDPagination) tmpPostBody.UseAdvancedIDPagination = true;
56
+
57
+ // Strategy-specific options
58
+ if (tmpSyncMode === 'OngoingEventualConsistency')
59
+ {
60
+ let tmpBackSyncTimeLimit = parseInt(document.getElementById('backSyncTimeLimit').value, 10);
61
+ if (tmpBackSyncTimeLimit > 0) tmpPostBody.BackSyncTimeLimit = tmpBackSyncTimeLimit;
62
+ }
63
+ if (tmpSyncMode === 'TrueUp')
64
+ {
65
+ let tmpTrueUpPageSize = parseInt(document.getElementById('trueUpPageSize').value, 10);
66
+ if (tmpTrueUpPageSize > 0) tmpPostBody.TrueUpPageSize = tmpTrueUpPageSize;
67
+ }
37
68
  this.pict.providers.DataCloner.api('POST', '/clone/sync/start', tmpPostBody)
38
69
  .then(function(pData)
39
70
  {
@@ -507,16 +538,48 @@ module.exports.default_configuration =
507
538
 
508
539
  <div style="margin-bottom:10px">
509
540
  <label style="margin-bottom:6px">Sync Mode</label>
510
- <div style="display:flex; gap:16px; align-items:center">
541
+ <div style="display:flex; gap:12px 20px; align-items:center; flex-wrap:wrap">
511
542
  <label style="font-weight:normal; margin:0; cursor:pointer">
512
- <input type="radio" name="syncMode" id="syncModeInitial" value="Initial" checked> Initial
513
- <span style="color:#888; font-size:0.85em">(full clone — download all records)</span>
543
+ <input type="radio" name="syncMode" id="syncModeInitial" value="Initial" checked onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Initial
544
+ <span style="color:#888; font-size:0.85em">(full clone)</span>
514
545
  </label>
515
546
  <label style="font-weight:normal; margin:0; cursor:pointer">
516
- <input type="radio" name="syncMode" id="syncModeOngoing" value="Ongoing"> Ongoing
517
- <span style="color:#888; font-size:0.85em">(delta — only new/updated records since last sync)</span>
547
+ <input type="radio" name="syncMode" id="syncModeOngoing" value="Ongoing" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Ongoing
548
+ <span style="color:#888; font-size:0.85em">(delta sync)</span>
518
549
  </label>
550
+ <label style="font-weight:normal; margin:0; cursor:pointer">
551
+ <input type="radio" name="syncMode" id="syncModeOngoingEventualConsistency" value="OngoingEventualConsistency" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Eventual
552
+ <span style="color:#888; font-size:0.85em">(time-budgeted back-sync)</span>
553
+ </label>
554
+ <label style="font-weight:normal; margin:0; cursor:pointer">
555
+ <input type="radio" name="syncMode" id="syncModeTrueUp" value="TrueUp" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> True-Up
556
+ <span style="color:#888; font-size:0.85em">(linear walk, one-time)</span>
557
+ </label>
558
+ <label style="font-weight:normal; margin:0; cursor:pointer">
559
+ <input type="radio" name="syncMode" id="syncModeComparisonOnly" value="ComparisonOnly" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Compare
560
+ <span style="color:#888; font-size:0.85em">(diff report, no sync)</span>
561
+ </label>
562
+ </div>
563
+ </div>
564
+
565
+ <div id="syncModeOptions-OngoingEventualConsistency" style="display:none; margin-bottom:10px">
566
+ <div style="display:flex; gap:8px; align-items:flex-end">
567
+ <div style="flex:0 0 220px">
568
+ <label for="backSyncTimeLimit">Back-Sync Time Budget (ms)</label>
569
+ <input type="number" id="backSyncTimeLimit" value="30000" min="1000" max="600000" style="margin-bottom:0">
570
+ </div>
571
+ </div>
572
+ <div style="font-size:0.8em; color:#888; padding-left:4px">Milliseconds devoted to backwards bisection per entity before pulling new records (default: 30000)</div>
573
+ </div>
574
+
575
+ <div id="syncModeOptions-TrueUp" style="display:none; margin-bottom:10px">
576
+ <div style="display:flex; gap:8px; align-items:flex-end">
577
+ <div style="flex:0 0 220px">
578
+ <label for="trueUpPageSize">True-Up Page Size</label>
579
+ <input type="number" id="trueUpPageSize" value="500" min="10" max="10000" style="margin-bottom:0">
580
+ </div>
519
581
  </div>
582
+ <div style="font-size:0.8em; color:#888; padding-left:4px">Records per page for the linear keyset walk (default: 500)</div>
520
583
  </div>
521
584
 
522
585
  <div class="checkbox-row">