@indigoai-us/hq-cloud 6.18.16-alpha.main2 → 6.18.17
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/dist/bin/sync-runner-company.d.ts.map +1 -1
- package/dist/bin/sync-runner-company.js +9 -1
- package/dist/bin/sync-runner-company.js.map +1 -1
- package/dist/bin/sync-runner-company.test.js +184 -3
- package/dist/bin/sync-runner-company.test.js.map +1 -1
- package/dist/bin/sync-runner.d.ts +8 -0
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +57 -2
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/rescue-core.d.ts.map +1 -1
- package/dist/cli/rescue-core.js +21 -6
- package/dist/cli/rescue-core.js.map +1 -1
- package/dist/cli/rescue-rsync-status.test.js +23 -0
- package/dist/cli/rescue-rsync-status.test.js.map +1 -1
- package/dist/cli/share-plan-limit-presign.test.d.ts +2 -0
- package/dist/cli/share-plan-limit-presign.test.d.ts.map +1 -0
- package/dist/cli/share-plan-limit-presign.test.js +271 -0
- package/dist/cli/share-plan-limit-presign.test.js.map +1 -0
- package/dist/cli/share.d.ts +22 -0
- package/dist/cli/share.d.ts.map +1 -1
- package/dist/cli/share.js +151 -25
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +262 -18
- package/dist/cli/share.test.js.map +1 -1
- package/dist/cli/sync.d.ts +38 -1
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +2 -1
- package/dist/cli/sync.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/object-io.d.ts +40 -0
- package/dist/object-io.d.ts.map +1 -1
- package/dist/object-io.js +122 -5
- package/dist/object-io.js.map +1 -1
- package/dist/object-io.test.js +144 -1
- package/dist/object-io.test.js.map +1 -1
- package/dist/plan-limit-pause.d.ts +61 -0
- package/dist/plan-limit-pause.d.ts.map +1 -0
- package/dist/plan-limit-pause.js +252 -0
- package/dist/plan-limit-pause.js.map +1 -0
- package/dist/plan-limit-pause.test.d.ts +2 -0
- package/dist/plan-limit-pause.test.d.ts.map +1 -0
- package/dist/plan-limit-pause.test.js +150 -0
- package/dist/plan-limit-pause.test.js.map +1 -0
- package/dist/plan-limit.d.ts +87 -0
- package/dist/plan-limit.d.ts.map +1 -0
- package/dist/plan-limit.fixtures.d.ts +34 -0
- package/dist/plan-limit.fixtures.d.ts.map +1 -0
- package/dist/plan-limit.fixtures.js +96 -0
- package/dist/plan-limit.fixtures.js.map +1 -0
- package/dist/plan-limit.js +157 -0
- package/dist/plan-limit.js.map +1 -0
- package/dist/plan-limit.test.d.ts +2 -0
- package/dist/plan-limit.test.d.ts.map +1 -0
- package/dist/plan-limit.test.js +132 -0
- package/dist/plan-limit.test.js.map +1 -0
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/mutation-client.d.ts +14 -2
- package/dist/sync/mutation-client.d.ts.map +1 -1
- package/dist/sync/mutation-client.js +34 -2
- package/dist/sync/mutation-client.js.map +1 -1
- package/dist/sync/mutation-client.test.js +49 -0
- package/dist/sync/mutation-client.test.js.map +1 -1
- package/dist/vault-client.d.ts +49 -6
- package/dist/vault-client.d.ts.map +1 -1
- package/dist/vault-client.js +115 -43
- package/dist/vault-client.js.map +1 -1
- package/dist/vault-client.test.js +86 -10
- package/dist/vault-client.test.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/share.test.js
CHANGED
|
@@ -103,7 +103,9 @@ vi.mock("readline", () => ({
|
|
|
103
103
|
import * as readline from "readline";
|
|
104
104
|
import { share, ServerOwnedPushPathsError, UnreachablePushPathsError, UnregisteredCompanySkillError, currentUploadBytes, FULL_PUSH_COOPERATIVE_CHECKPOINT_BATCH_SIZE, parseRegisteredCompanySkillUid, setPushCollectCooperativeYieldMsForTesting, _testing as shareTesting, } from "./share.js";
|
|
105
105
|
import { deleteRemoteFile, downloadFile, headRemoteFile, primeObjectTransport, primeUploads, setUploadContentHash, uploadFile, uploadSymlink, WindowsSymlinkPrivilegeError, } from "../s3.js";
|
|
106
|
-
import { VaultAuthError, VaultClientError, VaultConflictError, VaultPermissionDeniedError, } from "../vault-client.js";
|
|
106
|
+
import { VaultAuthError, VaultClientError, VaultConflictError, VaultPermissionDeniedError, vaultErrorFromResponse, } from "../vault-client.js";
|
|
107
|
+
import { PLAN_LIMIT_UPGRADE_URL, canonicalPlanLimitBody, legacyMembershipPlanLimitBody, } from "../plan-limit.fixtures.js";
|
|
108
|
+
import { PLAN_LIMIT_PAUSE_RETRY_MS, PlanLimitPauseStore, setPlanLimitPauseClockForTesting, } from "../plan-limit-pause.js";
|
|
107
109
|
import { CognitoRefreshError } from "../cognito-auth.js";
|
|
108
110
|
import { RateLimitedError } from "../object-io.js";
|
|
109
111
|
import { resolveSkillRegisterLandedBytes } from "../lib/skill-register-landed-bytes.js";
|
|
@@ -2132,36 +2134,278 @@ describe("share", () => {
|
|
|
2132
2134
|
});
|
|
2133
2135
|
expect(journalAt(journalPath).files[secretKey]?.removedAt).toBeUndefined();
|
|
2134
2136
|
});
|
|
2135
|
-
|
|
2136
|
-
const
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
return file;
|
|
2137
|
+
describe("plan-limit refusals", () => {
|
|
2138
|
+
const T0 = Date.parse("2026-09-28T12:00:00.000Z");
|
|
2139
|
+
let clock = T0;
|
|
2140
|
+
beforeEach(() => {
|
|
2141
|
+
clock = T0;
|
|
2142
|
+
setPlanLimitPauseClockForTesting(() => clock);
|
|
2142
2143
|
});
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2144
|
+
afterEach(() => {
|
|
2145
|
+
setPlanLimitPauseClockForTesting(null);
|
|
2146
|
+
vi.mocked(uploadFile).mockReset();
|
|
2147
|
+
vi.mocked(uploadFile).mockResolvedValue({ etag: '"upload-etag"' });
|
|
2148
|
+
});
|
|
2149
|
+
function writeCompanyFiles(names) {
|
|
2150
|
+
const companyRoot = path.join(tmpDir, "companies", "acme");
|
|
2151
|
+
return names.map((name) => {
|
|
2152
|
+
const file = path.join(companyRoot, name);
|
|
2153
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
2154
|
+
fs.writeFileSync(file, `# ${name} paused by plan limit`);
|
|
2155
|
+
return file;
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
/** The error the vault client throws for the server's canonical 402 body. */
|
|
2159
|
+
function canonical402() {
|
|
2160
|
+
return vaultErrorFromResponse(402, JSON.stringify(canonicalPlanLimitBody()));
|
|
2161
|
+
}
|
|
2162
|
+
function collect() {
|
|
2163
|
+
const events = [];
|
|
2164
|
+
return { events, onEvent: (event) => events.push(event) };
|
|
2165
|
+
}
|
|
2166
|
+
it("reports one notice with the refused files, the server message and the upgrade link", async () => {
|
|
2167
|
+
const paths = writeCompanyFiles(["first.md", "second.md"]);
|
|
2168
|
+
vi.mocked(uploadFile).mockReset();
|
|
2169
|
+
vi.mocked(uploadFile).mockRejectedValue(canonical402());
|
|
2170
|
+
const { events, onEvent } = collect();
|
|
2148
2171
|
const result = await share({
|
|
2149
2172
|
paths,
|
|
2150
2173
|
company: "acme",
|
|
2151
2174
|
vaultConfig: mockConfig,
|
|
2152
2175
|
hqRoot: tmpDir,
|
|
2153
|
-
onEvent
|
|
2176
|
+
onEvent,
|
|
2154
2177
|
});
|
|
2155
2178
|
const notices = events.filter((event) => event.type === "plan-limit");
|
|
2156
|
-
expect(notices).toEqual([
|
|
2179
|
+
expect(notices).toEqual([
|
|
2180
|
+
{
|
|
2181
|
+
type: "plan-limit",
|
|
2182
|
+
upgradeUrl: PLAN_LIMIT_UPGRADE_URL,
|
|
2183
|
+
message: "New files are paused while Acme is over its Starter limits.",
|
|
2184
|
+
code: "PLAN_LIMIT_EXCEEDED",
|
|
2185
|
+
error: "plan_limit_reached",
|
|
2186
|
+
blocked: "files.create",
|
|
2187
|
+
resources: [
|
|
2188
|
+
{ resource: "storageBytes", used: 11_811_160_064, limit: 10_737_418_240 },
|
|
2189
|
+
],
|
|
2190
|
+
fixOptions: { storageBytes: 10_737_418_240 },
|
|
2191
|
+
freeMonth: {
|
|
2192
|
+
eligible: true,
|
|
2193
|
+
trialDays: 30,
|
|
2194
|
+
url: "https://billing.example.test/companies/acme/billing?offer=free-month",
|
|
2195
|
+
},
|
|
2196
|
+
count: 2,
|
|
2197
|
+
paths: expect.arrayContaining(["first.md", "second.md"]),
|
|
2198
|
+
pausedUntil: new Date(T0 + PLAN_LIMIT_PAUSE_RETRY_MS).toISOString(),
|
|
2199
|
+
fromPause: false,
|
|
2200
|
+
},
|
|
2201
|
+
]);
|
|
2157
2202
|
expect(events.some((event) => event.type === "error")).toBe(false);
|
|
2158
2203
|
expect(result.filesUploaded).toBe(0);
|
|
2159
2204
|
expect(result.filesSkipped).toBe(2);
|
|
2160
|
-
|
|
2161
|
-
|
|
2205
|
+
expect(result.filesPlanLimited).toBe(2);
|
|
2206
|
+
expect(result.planLimitedPaths?.sort()).toEqual(["first.md", "second.md"]);
|
|
2207
|
+
expect(result.planLimit?.upgradeUrl).toBe(PLAN_LIMIT_UPGRADE_URL);
|
|
2208
|
+
// The refusal is recorded so the runner does not presign these again.
|
|
2209
|
+
const pauses = PlanLimitPauseStore.open("cmp_01ABCDEF");
|
|
2210
|
+
expect(pauses.isPaused("first.md", T0)).toBe(true);
|
|
2211
|
+
expect(pauses.isPaused("second.md", T0)).toBe(true);
|
|
2212
|
+
});
|
|
2213
|
+
it("recognises the legacy membership 402 shape the same way", async () => {
|
|
2214
|
+
const paths = writeCompanyFiles(["legacy.md"]);
|
|
2215
|
+
vi.mocked(uploadFile).mockReset();
|
|
2216
|
+
vi.mocked(uploadFile).mockRejectedValue(vaultErrorFromResponse(402, JSON.stringify(legacyMembershipPlanLimitBody())));
|
|
2217
|
+
const { events, onEvent } = collect();
|
|
2218
|
+
const result = await share({ paths, company: "acme", vaultConfig: mockConfig, hqRoot: tmpDir, onEvent });
|
|
2219
|
+
expect(events.filter((e) => e.type === "plan-limit")).toEqual([
|
|
2220
|
+
expect.objectContaining({ upgradeUrl: PLAN_LIMIT_UPGRADE_URL, count: 1, paths: ["legacy.md"] }),
|
|
2221
|
+
]);
|
|
2222
|
+
expect(events.some((event) => event.type === "error")).toBe(false);
|
|
2223
|
+
expect(result.filesPlanLimited).toBe(1);
|
|
2224
|
+
});
|
|
2225
|
+
it("with planLimitPause, skips paused files without uploading until the hour lapses", async () => {
|
|
2226
|
+
const paths = writeCompanyFiles(["a.md", "b.md", "c.md"]);
|
|
2227
|
+
vi.mocked(uploadFile).mockReset();
|
|
2228
|
+
vi.mocked(uploadFile).mockRejectedValue(canonical402());
|
|
2229
|
+
const pass = async () => {
|
|
2230
|
+
const { events, onEvent } = collect();
|
|
2231
|
+
const result = await share({
|
|
2232
|
+
paths,
|
|
2233
|
+
company: "acme",
|
|
2234
|
+
vaultConfig: mockConfig,
|
|
2235
|
+
hqRoot: tmpDir,
|
|
2236
|
+
skipUnchanged: true,
|
|
2237
|
+
planLimitPause: true,
|
|
2238
|
+
onEvent,
|
|
2239
|
+
});
|
|
2240
|
+
return { events, result };
|
|
2241
|
+
};
|
|
2242
|
+
const first = await pass();
|
|
2243
|
+
expect(vi.mocked(uploadFile)).toHaveBeenCalledTimes(3);
|
|
2244
|
+
expect(first.events.filter((e) => e.type === "plan-limit")).toHaveLength(1);
|
|
2245
|
+
for (let i = 0; i < 4; i++) {
|
|
2246
|
+
clock += 10 * 60 * 1000;
|
|
2247
|
+
const next = await pass();
|
|
2248
|
+
// Still announced every pass, from the stored refusal.
|
|
2249
|
+
expect(next.events.filter((e) => e.type === "plan-limit")).toEqual([
|
|
2250
|
+
expect.objectContaining({
|
|
2251
|
+
fromPause: true,
|
|
2252
|
+
count: 3,
|
|
2253
|
+
upgradeUrl: PLAN_LIMIT_UPGRADE_URL,
|
|
2254
|
+
message: "New files are paused while Acme is over its Starter limits.",
|
|
2255
|
+
pausedUntil: new Date(T0 + PLAN_LIMIT_PAUSE_RETRY_MS).toISOString(),
|
|
2256
|
+
}),
|
|
2257
|
+
]);
|
|
2258
|
+
expect(next.events.some((e) => e.type === "error")).toBe(false);
|
|
2259
|
+
expect(next.result.filesUploaded).toBe(0);
|
|
2260
|
+
expect(next.result.filesPlanLimited).toBe(3);
|
|
2261
|
+
expect(next.result.planLimit?.upgradeUrl).toBe(PLAN_LIMIT_UPGRADE_URL);
|
|
2262
|
+
}
|
|
2263
|
+
// Four more passes inside the hour: no further upload attempts.
|
|
2264
|
+
expect(vi.mocked(uploadFile)).toHaveBeenCalledTimes(3);
|
|
2265
|
+
clock = T0 + PLAN_LIMIT_PAUSE_RETRY_MS;
|
|
2266
|
+
const retry = await pass();
|
|
2267
|
+
expect(vi.mocked(uploadFile)).toHaveBeenCalledTimes(6);
|
|
2268
|
+
expect(retry.events.filter((e) => e.type === "plan-limit")).toEqual([
|
|
2269
|
+
expect.objectContaining({ count: 3, fromPause: false }),
|
|
2270
|
+
]);
|
|
2271
|
+
});
|
|
2272
|
+
it("announces files a direct push paused when the runner then skips them (fromPause)", async () => {
|
|
2273
|
+
const paths = writeCompanyFiles(["a.md", "b.md"]);
|
|
2274
|
+
vi.mocked(uploadFile).mockReset();
|
|
2275
|
+
vi.mocked(uploadFile).mockRejectedValue(canonical402());
|
|
2276
|
+
// `hq sync push` (no planLimitPause) refuses a.md and b.md and records
|
|
2277
|
+
// the pauses, but does not obey them itself.
|
|
2278
|
+
await share({ paths, company: "acme", vaultConfig: mockConfig, hqRoot: tmpDir, onEvent: () => { } });
|
|
2279
|
+
expect(vi.mocked(uploadFile)).toHaveBeenCalledTimes(2);
|
|
2280
|
+
// Twenty minutes later the runner (or a restarted desktop) skips them.
|
|
2281
|
+
// It must say so: one plan-limit event built from the stored refusal.
|
|
2282
|
+
clock = T0 + 20 * 60 * 1000;
|
|
2283
|
+
const { events, onEvent } = collect();
|
|
2284
|
+
const result = await share({
|
|
2285
|
+
paths,
|
|
2286
|
+
company: "acme",
|
|
2287
|
+
vaultConfig: mockConfig,
|
|
2288
|
+
hqRoot: tmpDir,
|
|
2289
|
+
skipUnchanged: true,
|
|
2290
|
+
planLimitPause: true,
|
|
2291
|
+
onEvent,
|
|
2292
|
+
});
|
|
2293
|
+
expect(vi.mocked(uploadFile)).toHaveBeenCalledTimes(2);
|
|
2294
|
+
expect(result.filesPlanLimited).toBe(2);
|
|
2295
|
+
expect(events.filter((e) => e.type === "plan-limit")).toEqual([
|
|
2296
|
+
{
|
|
2297
|
+
type: "plan-limit",
|
|
2298
|
+
upgradeUrl: PLAN_LIMIT_UPGRADE_URL,
|
|
2299
|
+
message: "New files are paused while Acme is over its Starter limits.",
|
|
2300
|
+
code: "PLAN_LIMIT_EXCEEDED",
|
|
2301
|
+
error: "plan_limit_reached",
|
|
2302
|
+
blocked: "files.create",
|
|
2303
|
+
resources: [
|
|
2304
|
+
{ resource: "storageBytes", used: 11_811_160_064, limit: 10_737_418_240 },
|
|
2305
|
+
],
|
|
2306
|
+
fixOptions: { storageBytes: 10_737_418_240 },
|
|
2307
|
+
freeMonth: {
|
|
2308
|
+
eligible: true,
|
|
2309
|
+
trialDays: 30,
|
|
2310
|
+
url: "https://billing.example.test/companies/acme/billing?offer=free-month",
|
|
2311
|
+
},
|
|
2312
|
+
count: 2,
|
|
2313
|
+
paths: expect.arrayContaining(["a.md", "b.md"]),
|
|
2314
|
+
pausedUntil: new Date(T0 + PLAN_LIMIT_PAUSE_RETRY_MS).toISOString(),
|
|
2315
|
+
fromPause: true,
|
|
2316
|
+
},
|
|
2317
|
+
]);
|
|
2318
|
+
expect(events.some((e) => e.type === "error")).toBe(false);
|
|
2319
|
+
});
|
|
2320
|
+
it("reports fresh refusals and paused skips together in one event", async () => {
|
|
2321
|
+
const [first] = writeCompanyFiles(["first.md"]);
|
|
2322
|
+
vi.mocked(uploadFile).mockReset();
|
|
2323
|
+
vi.mocked(uploadFile).mockRejectedValue(canonical402());
|
|
2324
|
+
await share({
|
|
2325
|
+
paths: [first],
|
|
2326
|
+
company: "acme",
|
|
2327
|
+
vaultConfig: mockConfig,
|
|
2328
|
+
hqRoot: tmpDir,
|
|
2329
|
+
skipUnchanged: true,
|
|
2330
|
+
planLimitPause: true,
|
|
2331
|
+
onEvent: () => { },
|
|
2332
|
+
});
|
|
2333
|
+
clock = T0 + 30 * 60 * 1000;
|
|
2334
|
+
const [second] = writeCompanyFiles(["second.md"]);
|
|
2335
|
+
const { events, onEvent } = collect();
|
|
2336
|
+
await share({
|
|
2337
|
+
paths: [first, second],
|
|
2338
|
+
company: "acme",
|
|
2339
|
+
vaultConfig: mockConfig,
|
|
2340
|
+
hqRoot: tmpDir,
|
|
2341
|
+
skipUnchanged: true,
|
|
2342
|
+
planLimitPause: true,
|
|
2343
|
+
onEvent,
|
|
2344
|
+
});
|
|
2345
|
+
expect(events.filter((e) => e.type === "plan-limit")).toEqual([
|
|
2346
|
+
expect.objectContaining({
|
|
2347
|
+
fromPause: false,
|
|
2348
|
+
count: 2,
|
|
2349
|
+
paths: ["second.md", "first.md"],
|
|
2350
|
+
// The earliest retry: first.md's pause from T0.
|
|
2351
|
+
pausedUntil: new Date(T0 + PLAN_LIMIT_PAUSE_RETRY_MS).toISOString(),
|
|
2352
|
+
}),
|
|
2353
|
+
]);
|
|
2354
|
+
});
|
|
2355
|
+
it("without planLimitPause (a direct push), retries and reports refused files every time", async () => {
|
|
2356
|
+
const paths = writeCompanyFiles(["a.md"]);
|
|
2357
|
+
vi.mocked(uploadFile).mockReset();
|
|
2358
|
+
vi.mocked(uploadFile).mockRejectedValue(canonical402());
|
|
2359
|
+
for (let i = 0; i < 2; i++) {
|
|
2360
|
+
const { events, onEvent } = collect();
|
|
2361
|
+
await share({ paths, company: "acme", vaultConfig: mockConfig, hqRoot: tmpDir, skipUnchanged: true, onEvent });
|
|
2362
|
+
expect(events.filter((e) => e.type === "plan-limit")).toHaveLength(1);
|
|
2363
|
+
}
|
|
2364
|
+
expect(vi.mocked(uploadFile)).toHaveBeenCalledTimes(2);
|
|
2365
|
+
});
|
|
2366
|
+
it("drops every pause once an upload to the same vault succeeds", async () => {
|
|
2367
|
+
const [paused] = writeCompanyFiles(["paused.md"]);
|
|
2368
|
+
vi.mocked(uploadFile).mockReset();
|
|
2369
|
+
vi.mocked(uploadFile).mockRejectedValue(canonical402());
|
|
2370
|
+
await share({
|
|
2371
|
+
paths: [paused],
|
|
2372
|
+
company: "acme",
|
|
2373
|
+
vaultConfig: mockConfig,
|
|
2374
|
+
hqRoot: tmpDir,
|
|
2375
|
+
skipUnchanged: true,
|
|
2376
|
+
planLimitPause: true,
|
|
2377
|
+
onEvent: () => { },
|
|
2378
|
+
});
|
|
2379
|
+
expect(PlanLimitPauseStore.open("cmp_01ABCDEF").isPaused("paused.md", clock)).toBe(true);
|
|
2380
|
+
// The plan changed: the server accepts writes again. A new file uploads,
|
|
2381
|
+
// which clears the record so the paused file is retried next pass.
|
|
2162
2382
|
vi.mocked(uploadFile).mockReset();
|
|
2163
2383
|
vi.mocked(uploadFile).mockResolvedValue({ etag: '"upload-etag"' });
|
|
2164
|
-
|
|
2384
|
+
const [fresh] = writeCompanyFiles(["fresh.md"]);
|
|
2385
|
+
const accepted = await share({
|
|
2386
|
+
paths: [paused, fresh],
|
|
2387
|
+
company: "acme",
|
|
2388
|
+
vaultConfig: mockConfig,
|
|
2389
|
+
hqRoot: tmpDir,
|
|
2390
|
+
skipUnchanged: true,
|
|
2391
|
+
planLimitPause: true,
|
|
2392
|
+
onEvent: () => { },
|
|
2393
|
+
});
|
|
2394
|
+
expect(accepted.filesUploaded).toBe(1);
|
|
2395
|
+
expect(accepted.filesPlanLimited).toBe(1);
|
|
2396
|
+
expect(PlanLimitPauseStore.open("cmp_01ABCDEF").size).toBe(0);
|
|
2397
|
+
const next = await share({
|
|
2398
|
+
paths: [paused, fresh],
|
|
2399
|
+
company: "acme",
|
|
2400
|
+
vaultConfig: mockConfig,
|
|
2401
|
+
hqRoot: tmpDir,
|
|
2402
|
+
skipUnchanged: true,
|
|
2403
|
+
planLimitPause: true,
|
|
2404
|
+
onEvent: () => { },
|
|
2405
|
+
});
|
|
2406
|
+
expect(next.filesUploaded).toBe(1);
|
|
2407
|
+
expect(next.filesPlanLimited).toBe(0);
|
|
2408
|
+
});
|
|
2165
2409
|
});
|
|
2166
2410
|
it("hands queued realtime work a settled full-push boundary without losing journal rows", async () => {
|
|
2167
2411
|
const companyRoot = path.join(tmpDir, "companies", "acme");
|