@quenty/nevermore-cli 4.42.0 → 4.42.1-canary.783.30683606415.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.
- package/CHANGELOG.md +22 -0
- package/dist/args/global-args.d.ts +13 -0
- package/dist/args/global-args.d.ts.map +1 -1
- package/dist/commands/batch-command/batch-deploy-command.d.ts +3 -0
- package/dist/commands/batch-command/batch-deploy-command.d.ts.map +1 -1
- package/dist/commands/batch-command/batch-deploy-command.js +90 -1
- package/dist/commands/batch-command/batch-deploy-command.js.map +1 -1
- package/dist/commands/batch-command/batch-test-command.d.ts.map +1 -1
- package/dist/commands/batch-command/batch-test-command.js +7 -2
- package/dist/commands/batch-command/batch-test-command.js.map +1 -1
- package/dist/commands/deploy-command/deploy-init.js +1 -1
- package/dist/commands/deploy-command/deploy-init.js.map +1 -1
- package/dist/commands/deploy-command/index.d.ts +3 -0
- package/dist/commands/deploy-command/index.d.ts.map +1 -1
- package/dist/commands/deploy-command/index.js +301 -60
- package/dist/commands/deploy-command/index.js.map +1 -1
- package/dist/commands/deploy-command/select-target.js +1 -1
- package/dist/commands/deploy-command/select-target.js.map +1 -1
- package/dist/commands/deploy-command/version-command.d.ts.map +1 -1
- package/dist/commands/deploy-command/version-command.js +138 -12
- package/dist/commands/deploy-command/version-command.js.map +1 -1
- package/dist/commands/test-command/test-command.d.ts.map +1 -1
- package/dist/commands/test-command/test-command.js +17 -7
- package/dist/commands/test-command/test-command.js.map +1 -1
- package/dist/nevermore.js +17 -0
- package/dist/nevermore.js.map +1 -1
- package/dist/utils/batch/changed-packages-utils.d.ts +1 -1
- package/dist/utils/batch/changed-packages-utils.d.ts.map +1 -1
- package/dist/utils/batch/changed-packages-utils.js +1 -1
- package/dist/utils/batch/changed-packages-utils.js.map +1 -1
- package/dist/utils/build/base-place-resolver-factory.d.ts +25 -0
- package/dist/utils/build/base-place-resolver-factory.d.ts.map +1 -0
- package/dist/utils/build/base-place-resolver-factory.js +40 -0
- package/dist/utils/build/base-place-resolver-factory.js.map +1 -0
- package/dist/utils/build/build.d.ts +13 -2
- package/dist/utils/build/build.d.ts.map +1 -1
- package/dist/utils/build/build.js.map +1 -1
- package/dist/utils/build/upload.d.ts +1 -1
- package/dist/utils/build/upload.d.ts.map +1 -1
- package/dist/utils/deploy/deploy-metadata.d.ts +1 -1
- package/dist/utils/deploy/deploy-metadata.d.ts.map +1 -1
- package/dist/utils/job-context/base-job-context.d.ts +3 -1
- package/dist/utils/job-context/base-job-context.d.ts.map +1 -1
- package/dist/utils/job-context/base-job-context.js +45 -6
- package/dist/utils/job-context/base-job-context.js.map +1 -1
- package/dist/utils/job-context/batch-script-job-context.d.ts +6 -0
- package/dist/utils/job-context/batch-script-job-context.d.ts.map +1 -1
- package/dist/utils/job-context/batch-script-job-context.js +13 -0
- package/dist/utils/job-context/batch-script-job-context.js.map +1 -1
- package/dist/utils/job-context/cloud-job-context.d.ts +2 -1
- package/dist/utils/job-context/cloud-job-context.d.ts.map +1 -1
- package/dist/utils/job-context/cloud-job-context.js +2 -2
- package/dist/utils/job-context/cloud-job-context.js.map +1 -1
- package/dist/utils/job-context/local-job-context.d.ts +2 -1
- package/dist/utils/job-context/local-job-context.d.ts.map +1 -1
- package/dist/utils/job-context/local-job-context.js +2 -2
- package/dist/utils/job-context/local-job-context.js.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.d.ts +20 -2
- package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.js +74 -20
- package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.test.js +89 -12
- package/dist/utils/open-cloud/open-cloud-client.test.js.map +1 -1
- package/dist/utils/testing/runner/combined-project-generator.d.ts +1 -1
- package/dist/utils/testing/runner/combined-project-generator.d.ts.map +1 -1
- package/dist/utils/testing/runner/test-runner.d.ts +1 -1
- package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
- package/dist/utils/watch/github-context.d.ts +50 -0
- package/dist/utils/watch/github-context.d.ts.map +1 -0
- package/dist/utils/watch/github-context.js +125 -0
- package/dist/utils/watch/github-context.js.map +1 -0
- package/dist/utils/watch/github-context.test.d.ts +2 -0
- package/dist/utils/watch/github-context.test.d.ts.map +1 -0
- package/dist/utils/watch/github-context.test.js +112 -0
- package/dist/utils/watch/github-context.test.js.map +1 -0
- package/dist/utils/watch/http-watch-registry.d.ts +40 -0
- package/dist/utils/watch/http-watch-registry.d.ts.map +1 -0
- package/dist/utils/watch/http-watch-registry.js +262 -0
- package/dist/utils/watch/http-watch-registry.js.map +1 -0
- package/dist/utils/watch/http-watch-registry.test.d.ts +2 -0
- package/dist/utils/watch/http-watch-registry.test.d.ts.map +1 -0
- package/dist/utils/watch/http-watch-registry.test.js +211 -0
- package/dist/utils/watch/http-watch-registry.test.js.map +1 -0
- package/dist/utils/watch/local-watch-loop.d.ts +50 -0
- package/dist/utils/watch/local-watch-loop.d.ts.map +1 -0
- package/dist/utils/watch/local-watch-loop.js +103 -0
- package/dist/utils/watch/local-watch-loop.js.map +1 -0
- package/dist/utils/watch/local-watch-loop.test.d.ts +2 -0
- package/dist/utils/watch/local-watch-loop.test.d.ts.map +1 -0
- package/dist/utils/watch/local-watch-loop.test.js +170 -0
- package/dist/utils/watch/local-watch-loop.test.js.map +1 -0
- package/dist/utils/watch/register-notify-watches.d.ts +41 -0
- package/dist/utils/watch/register-notify-watches.d.ts.map +1 -0
- package/dist/utils/watch/register-notify-watches.js +159 -0
- package/dist/utils/watch/register-notify-watches.js.map +1 -0
- package/dist/utils/watch/register-notify-watches.test.d.ts +2 -0
- package/dist/utils/watch/register-notify-watches.test.d.ts.map +1 -0
- package/dist/utils/watch/register-notify-watches.test.js +225 -0
- package/dist/utils/watch/register-notify-watches.test.js.map +1 -0
- package/dist/utils/watch/register-watches.d.ts +68 -0
- package/dist/utils/watch/register-watches.d.ts.map +1 -0
- package/dist/utils/watch/register-watches.js +221 -0
- package/dist/utils/watch/register-watches.js.map +1 -0
- package/dist/utils/watch/register-watches.test.d.ts +2 -0
- package/dist/utils/watch/register-watches.test.d.ts.map +1 -0
- package/dist/utils/watch/register-watches.test.js +576 -0
- package/dist/utils/watch/register-watches.test.js.map +1 -0
- package/dist/utils/watch/stream-watch-loop.d.ts +54 -0
- package/dist/utils/watch/stream-watch-loop.d.ts.map +1 -0
- package/dist/utils/watch/stream-watch-loop.js +282 -0
- package/dist/utils/watch/stream-watch-loop.js.map +1 -0
- package/dist/utils/watch/stream-watch-loop.test.d.ts +2 -0
- package/dist/utils/watch/stream-watch-loop.test.d.ts.map +1 -0
- package/dist/utils/watch/stream-watch-loop.test.js +392 -0
- package/dist/utils/watch/stream-watch-loop.test.js.map +1 -0
- package/dist/utils/watch/websocket-watch-stream.d.ts +25 -0
- package/dist/utils/watch/websocket-watch-stream.d.ts.map +1 -0
- package/dist/utils/watch/websocket-watch-stream.js +306 -0
- package/dist/utils/watch/websocket-watch-stream.js.map +1 -0
- package/dist/utils/watch/websocket-watch-stream.test.d.ts +2 -0
- package/dist/utils/watch/websocket-watch-stream.test.d.ts.map +1 -0
- package/dist/utils/watch/websocket-watch-stream.test.js +475 -0
- package/dist/utils/watch/websocket-watch-stream.test.js.map +1 -0
- package/package.json +7 -4
- package/src/args/global-args.ts +13 -0
- package/src/commands/batch-command/batch-deploy-command.ts +105 -1
- package/src/commands/batch-command/batch-test-command.ts +8 -2
- package/src/commands/deploy-command/deploy-init.ts +1 -1
- package/src/commands/deploy-command/index.ts +331 -32
- package/src/commands/deploy-command/select-target.ts +1 -1
- package/src/commands/deploy-command/version-command.ts +215 -21
- package/src/commands/test-command/test-command.ts +24 -18
- package/src/nevermore.ts +19 -0
- package/src/utils/batch/changed-packages-utils.ts +1 -1
- package/src/utils/build/base-place-resolver-factory.ts +49 -0
- package/src/utils/build/build.ts +13 -2
- package/src/utils/build/upload.ts +1 -1
- package/src/utils/deploy/deploy-metadata.ts +1 -1
- package/src/utils/job-context/base-job-context.ts +68 -6
- package/src/utils/job-context/batch-script-job-context.ts +18 -0
- package/src/utils/job-context/cloud-job-context.ts +7 -2
- package/src/utils/job-context/local-job-context.ts +7 -2
- package/src/utils/open-cloud/open-cloud-client.test.ts +133 -14
- package/src/utils/open-cloud/open-cloud-client.ts +127 -34
- package/src/utils/testing/runner/combined-project-generator.ts +1 -1
- package/src/utils/testing/runner/test-runner.ts +1 -1
- package/src/utils/watch/github-context.test.ts +154 -0
- package/src/utils/watch/github-context.ts +184 -0
- package/src/utils/watch/http-watch-registry.test.ts +330 -0
- package/src/utils/watch/http-watch-registry.ts +341 -0
- package/src/utils/watch/local-watch-loop.test.ts +197 -0
- package/src/utils/watch/local-watch-loop.ts +190 -0
- package/src/utils/watch/register-notify-watches.test.ts +282 -0
- package/src/utils/watch/register-notify-watches.ts +226 -0
- package/src/utils/watch/register-watches.test.ts +696 -0
- package/src/utils/watch/register-watches.ts +369 -0
- package/src/utils/watch/stream-watch-loop.test.ts +625 -0
- package/src/utils/watch/stream-watch-loop.ts +411 -0
- package/src/utils/watch/websocket-watch-stream.test.ts +581 -0
- package/src/utils/watch/websocket-watch-stream.ts +403 -0
- package/tsconfig.json +19 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/build/deploy-config.d.ts +0 -71
- package/dist/utils/build/deploy-config.d.ts.map +0 -1
- package/dist/utils/build/deploy-config.js +0 -164
- package/dist/utils/build/deploy-config.js.map +0 -1
- package/dist/utils/build/deploy-config.test.d.ts +0 -2
- package/dist/utils/build/deploy-config.test.d.ts.map +0 -1
- package/dist/utils/build/deploy-config.test.js +0 -126
- package/dist/utils/build/deploy-config.test.js.map +0 -1
- package/src/utils/build/deploy-config.test.ts +0 -149
- package/src/utils/build/deploy-config.ts +0 -259
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
2
|
+
/** How often to ask Open Cloud whether a base place moved. */
|
|
3
|
+
const DEFAULT_POLL_INTERVAL_MS = 15_000;
|
|
4
|
+
/**
|
|
5
|
+
* Poll base places and redeploy in-process when one moves.
|
|
6
|
+
*
|
|
7
|
+
* This is what `--watch` does outside CI. Registering with the watch service
|
|
8
|
+
* would be pointless on a laptop: the service's only action is dispatching a
|
|
9
|
+
* GitHub workflow, which would rebuild on a runner rather than here — so a
|
|
10
|
+
* local run keeps the loop in the terminal, where the developer can see it.
|
|
11
|
+
*
|
|
12
|
+
* Poll failures never end the loop. A watch is meant to be left running for
|
|
13
|
+
* hours, and a dropped connection is not a reason to stop watching.
|
|
14
|
+
*/
|
|
15
|
+
export async function runLocalWatchLoopAsync(options) {
|
|
16
|
+
const { entries, source, durationMs, redeployAsync, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, now = () => Date.now(), sleepAsync = _sleepAsync, } = options;
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const signal = options.signal ?? controller.signal;
|
|
19
|
+
const onSigint = () => controller.abort();
|
|
20
|
+
if (!options.signal) {
|
|
21
|
+
process.on('SIGINT', onSigint);
|
|
22
|
+
}
|
|
23
|
+
const seen = new Map(entries.map((e) => [_key(e), e.baseline]));
|
|
24
|
+
const deadline = now() + durationMs;
|
|
25
|
+
let redeploys = 0;
|
|
26
|
+
let failures = 0;
|
|
27
|
+
OutputHelper.info(`Watching ${entries.length} base place${entries.length === 1 ? '' : 's'} locally. Ctrl-C to stop.`);
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
OutputHelper.info(` ${entry.label} — base place ${entry.placeId} (${entry.versionType}${entry.baseline == null ? '' : ` v${entry.baseline}`})`);
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
while (!signal.aborted && now() < deadline) {
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
if (signal.aborted) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
let latest;
|
|
38
|
+
try {
|
|
39
|
+
latest = await source.resolveLatestPlaceVersionAsync(entry.universeId, entry.placeId, entry.versionType);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
OutputHelper.warn(`Could not check ${entry.label}: ` +
|
|
43
|
+
(err instanceof Error ? err.message : String(err)));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const key = _key(entry);
|
|
47
|
+
const previous = seen.get(key);
|
|
48
|
+
if (previous === undefined) {
|
|
49
|
+
// First sighting of a place with no recorded baseline: adopt it
|
|
50
|
+
// rather than treating "unknown -> something" as a change.
|
|
51
|
+
seen.set(key, latest);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (latest === previous) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
OutputHelper.info(`${entry.label}: base place moved v${previous} → v${latest}, rebuilding...`);
|
|
58
|
+
try {
|
|
59
|
+
await redeployAsync(entry, latest);
|
|
60
|
+
redeploys++;
|
|
61
|
+
// Recorded only on success, so a failed rebuild is retried on the
|
|
62
|
+
// next poll instead of being silently skipped forever.
|
|
63
|
+
seen.set(key, latest);
|
|
64
|
+
OutputHelper.info(`${entry.label}: rebuilt from v${latest}.`);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
failures++;
|
|
68
|
+
OutputHelper.error(`${entry.label}: rebuild failed — ` +
|
|
69
|
+
(err instanceof Error ? err.message : String(err)));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (signal.aborted || now() >= deadline) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
await sleepAsync(pollIntervalMs, signal);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
if (!options.signal) {
|
|
80
|
+
process.off('SIGINT', onSigint);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const expired = !signal.aborted;
|
|
84
|
+
OutputHelper.info(expired
|
|
85
|
+
? `Watch lease elapsed. ${redeploys} rebuild${redeploys === 1 ? '' : 's'}.`
|
|
86
|
+
: `Stopped watching. ${redeploys} rebuild${redeploys === 1 ? '' : 's'}.`);
|
|
87
|
+
return { redeploys, failures, expired };
|
|
88
|
+
}
|
|
89
|
+
function _key(entry) {
|
|
90
|
+
return `${entry.placeId}:${entry.versionType}`;
|
|
91
|
+
}
|
|
92
|
+
function _sleepAsync(ms, signal) {
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
const timer = setTimeout(finish, ms);
|
|
95
|
+
function finish() {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
signal.removeEventListener('abort', finish);
|
|
98
|
+
resolve();
|
|
99
|
+
}
|
|
100
|
+
signal.addEventListener('abort', finish, { once: true });
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=local-watch-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-watch-loop.js","sourceRoot":"","sources":["../../../src/utils/watch/local-watch-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-watch-loop.test.d.ts","sourceRoot":"","sources":["../../../src/utils/watch/local-watch-loop.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { runLocalWatchLoopAsync, } from './local-watch-loop.js';
|
|
3
|
+
function makeEntry(overrides = {}) {
|
|
4
|
+
return {
|
|
5
|
+
label: 'integration.places.hub',
|
|
6
|
+
universeId: 10,
|
|
7
|
+
placeId: 20,
|
|
8
|
+
versionType: 'published',
|
|
9
|
+
baseline: 158,
|
|
10
|
+
...overrides,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Drives the loop deterministically: time only advances when the loop sleeps,
|
|
15
|
+
* so a test controls exactly how many poll rounds happen.
|
|
16
|
+
*/
|
|
17
|
+
function makeClock(pollIntervalMs) {
|
|
18
|
+
let current = 0;
|
|
19
|
+
return {
|
|
20
|
+
now: () => current,
|
|
21
|
+
sleepAsync: async () => {
|
|
22
|
+
current += pollIntervalMs;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
describe('runLocalWatchLoopAsync', () => {
|
|
27
|
+
it('redeploys when the base place moves', async () => {
|
|
28
|
+
const versions = [158, 158, 159];
|
|
29
|
+
let i = 0;
|
|
30
|
+
const redeployed = [];
|
|
31
|
+
const clock = makeClock(1000);
|
|
32
|
+
const result = await runLocalWatchLoopAsync({
|
|
33
|
+
entries: [makeEntry()],
|
|
34
|
+
source: {
|
|
35
|
+
resolveLatestPlaceVersionAsync: async () => versions[Math.min(i++, versions.length - 1)],
|
|
36
|
+
},
|
|
37
|
+
durationMs: 3000,
|
|
38
|
+
pollIntervalMs: 1000,
|
|
39
|
+
redeployAsync: async (_entry, version) => {
|
|
40
|
+
redeployed.push(version);
|
|
41
|
+
},
|
|
42
|
+
...clock,
|
|
43
|
+
});
|
|
44
|
+
expect(redeployed).toEqual([159]);
|
|
45
|
+
expect(result.redeploys).toBe(1);
|
|
46
|
+
expect(result.failures).toBe(0);
|
|
47
|
+
expect(result.expired).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it('does not redeploy while the version holds still', async () => {
|
|
50
|
+
const redeployed = [];
|
|
51
|
+
const clock = makeClock(1000);
|
|
52
|
+
const result = await runLocalWatchLoopAsync({
|
|
53
|
+
entries: [makeEntry()],
|
|
54
|
+
source: { resolveLatestPlaceVersionAsync: async () => 158 },
|
|
55
|
+
durationMs: 5000,
|
|
56
|
+
pollIntervalMs: 1000,
|
|
57
|
+
redeployAsync: async (_e, v) => {
|
|
58
|
+
redeployed.push(v);
|
|
59
|
+
},
|
|
60
|
+
...clock,
|
|
61
|
+
});
|
|
62
|
+
expect(redeployed).toEqual([]);
|
|
63
|
+
expect(result.redeploys).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
// An entry with no lock entry has no baseline. Treating "unknown -> 158" as a
|
|
66
|
+
// change would rebuild immediately on startup for no reason.
|
|
67
|
+
it('adopts the first observed version when there is no baseline', async () => {
|
|
68
|
+
const redeployed = [];
|
|
69
|
+
const clock = makeClock(1000);
|
|
70
|
+
await runLocalWatchLoopAsync({
|
|
71
|
+
entries: [makeEntry({ baseline: undefined })],
|
|
72
|
+
source: { resolveLatestPlaceVersionAsync: async () => 158 },
|
|
73
|
+
durationMs: 3000,
|
|
74
|
+
pollIntervalMs: 1000,
|
|
75
|
+
redeployAsync: async (_e, v) => {
|
|
76
|
+
redeployed.push(v);
|
|
77
|
+
},
|
|
78
|
+
...clock,
|
|
79
|
+
});
|
|
80
|
+
expect(redeployed).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
it('keeps watching after a poll failure', async () => {
|
|
83
|
+
let call = 0;
|
|
84
|
+
const redeployed = [];
|
|
85
|
+
const clock = makeClock(1000);
|
|
86
|
+
const result = await runLocalWatchLoopAsync({
|
|
87
|
+
entries: [makeEntry()],
|
|
88
|
+
source: {
|
|
89
|
+
resolveLatestPlaceVersionAsync: async () => {
|
|
90
|
+
call++;
|
|
91
|
+
if (call === 1) {
|
|
92
|
+
throw new Error('ECONNRESET');
|
|
93
|
+
}
|
|
94
|
+
return 159;
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
durationMs: 3000,
|
|
98
|
+
pollIntervalMs: 1000,
|
|
99
|
+
redeployAsync: async (_e, v) => {
|
|
100
|
+
redeployed.push(v);
|
|
101
|
+
},
|
|
102
|
+
...clock,
|
|
103
|
+
});
|
|
104
|
+
expect(redeployed).toEqual([159]);
|
|
105
|
+
expect(result.redeploys).toBe(1);
|
|
106
|
+
});
|
|
107
|
+
// The new version is recorded only on a successful rebuild, so a transient
|
|
108
|
+
// build failure is retried rather than silently skipped forever.
|
|
109
|
+
it('retries a version whose rebuild failed', async () => {
|
|
110
|
+
let attempts = 0;
|
|
111
|
+
const clock = makeClock(1000);
|
|
112
|
+
const result = await runLocalWatchLoopAsync({
|
|
113
|
+
entries: [makeEntry()],
|
|
114
|
+
source: { resolveLatestPlaceVersionAsync: async () => 159 },
|
|
115
|
+
durationMs: 3000,
|
|
116
|
+
pollIntervalMs: 1000,
|
|
117
|
+
redeployAsync: async () => {
|
|
118
|
+
attempts++;
|
|
119
|
+
if (attempts === 1) {
|
|
120
|
+
throw new Error('rojo exploded');
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
...clock,
|
|
124
|
+
});
|
|
125
|
+
expect(attempts).toBeGreaterThan(1);
|
|
126
|
+
expect(result.failures).toBe(1);
|
|
127
|
+
expect(result.redeploys).toBe(1);
|
|
128
|
+
});
|
|
129
|
+
it('stops when the caller aborts', async () => {
|
|
130
|
+
const controller = new AbortController();
|
|
131
|
+
const clock = makeClock(1000);
|
|
132
|
+
const poll = vi.fn(async () => {
|
|
133
|
+
controller.abort();
|
|
134
|
+
return 158;
|
|
135
|
+
});
|
|
136
|
+
const result = await runLocalWatchLoopAsync({
|
|
137
|
+
entries: [makeEntry()],
|
|
138
|
+
source: { resolveLatestPlaceVersionAsync: poll },
|
|
139
|
+
durationMs: 60_000,
|
|
140
|
+
pollIntervalMs: 1000,
|
|
141
|
+
redeployAsync: async () => { },
|
|
142
|
+
signal: controller.signal,
|
|
143
|
+
...clock,
|
|
144
|
+
});
|
|
145
|
+
expect(poll).toHaveBeenCalledTimes(1);
|
|
146
|
+
expect(result.expired).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
it('watches every entry independently', async () => {
|
|
149
|
+
const seen = [];
|
|
150
|
+
const clock = makeClock(1000);
|
|
151
|
+
await runLocalWatchLoopAsync({
|
|
152
|
+
entries: [
|
|
153
|
+
makeEntry({ label: 'hub', placeId: 20, baseline: 1 }),
|
|
154
|
+
makeEntry({ label: 'lobby', placeId: 21, baseline: 1 }),
|
|
155
|
+
],
|
|
156
|
+
source: {
|
|
157
|
+
resolveLatestPlaceVersionAsync: async (_u, placeId) => placeId === 21 ? 2 : 1,
|
|
158
|
+
},
|
|
159
|
+
durationMs: 2000,
|
|
160
|
+
pollIntervalMs: 1000,
|
|
161
|
+
redeployAsync: async (entry) => {
|
|
162
|
+
seen.push(entry.label);
|
|
163
|
+
},
|
|
164
|
+
...clock,
|
|
165
|
+
});
|
|
166
|
+
expect(seen).toContain('lobby');
|
|
167
|
+
expect(seen).not.toContain('hub');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=local-watch-loop.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-watch-loop.test.js","sourceRoot":"","sources":["../../../src/utils/watch/local-watch-loop.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type WatchOption, type WatchRegistry } from '@quenty/nevermore-deploy';
|
|
2
|
+
import { type LocalWatchEntry } from './local-watch-loop.js';
|
|
3
|
+
import { type StreamWatchEntry } from './stream-watch-loop.js';
|
|
4
|
+
export interface RegisterNotifyWatchesOptions {
|
|
5
|
+
option: WatchOption;
|
|
6
|
+
/** Lease key within the repository, as for a dispatching monitor. */
|
|
7
|
+
monitorName: string;
|
|
8
|
+
entries: LocalWatchEntry[];
|
|
9
|
+
/** Open Cloud key to share, so the service can poll a private base place. */
|
|
10
|
+
robloxApiKey?: string;
|
|
11
|
+
/** Let the GitHub CLI supply the token when no env var does. */
|
|
12
|
+
useGhAuth?: boolean;
|
|
13
|
+
/** Injected in tests; defaults to the HTTP registry. */
|
|
14
|
+
createRegistry?: (registerUrl: string) => WatchRegistry;
|
|
15
|
+
}
|
|
16
|
+
export type RegisterNotifyWatchesResult = {
|
|
17
|
+
success: true;
|
|
18
|
+
monitorId: string;
|
|
19
|
+
/** Bearer token for the stream; the same one registration used. */
|
|
20
|
+
credential: string;
|
|
21
|
+
entries: StreamWatchEntry[];
|
|
22
|
+
} | {
|
|
23
|
+
success: false;
|
|
24
|
+
reason: 'no_github_context' | 'no_token' | 'unwatchable_version_type' | 'no_entries' | 'register_failed' | 'no_monitor_id';
|
|
25
|
+
detail?: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Register a monitor that notifies this process instead of dispatching CI.
|
|
29
|
+
*
|
|
30
|
+
* Best-effort on purpose. Every way this can fail — no GitHub identity to
|
|
31
|
+
* register under, no token, a `"saved"` base place the service cannot poll, a
|
|
32
|
+
* service that is unreachable — has a working answer already: poll Open Cloud
|
|
33
|
+
* from here. So a failure downgrades the watch rather than the run, and the
|
|
34
|
+
* caller falls back.
|
|
35
|
+
*/
|
|
36
|
+
export declare function tryRegisterNotifyWatchesAsync(options: RegisterNotifyWatchesOptions): Promise<RegisterNotifyWatchesResult>;
|
|
37
|
+
/** Why the run is polling instead, in words a user can act on. */
|
|
38
|
+
export declare function describeNotifyWatchFallback(result: RegisterNotifyWatchesResult & {
|
|
39
|
+
success: false;
|
|
40
|
+
}): string;
|
|
41
|
+
//# sourceMappingURL=register-notify-watches.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-notify-watches.d.ts","sourceRoot":"","sources":["../../../src/utils/watch/register-notify-watches.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,WAAW,CAAC;IACpB,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,aAAa,CAAC;CACzD;AAED,MAAM,MAAM,2BAA2B,GACnC;IACE,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EACF,mBAAmB,GACnB,UAAU,GACV,0BAA0B,GAC1B,YAAY,GACZ,iBAAiB,GACjB,eAAe,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,2BAA2B,CAAC,CA2GtC;AAED,kEAAkE;AAClE,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,2BAA2B,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GACvD,MAAM,CAqBR"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
2
|
+
import { WATCH_BASELINE_KIND, WATCH_INPUT_NAME, sanitizeWatchName, } from '@quenty/nevermore-deploy';
|
|
3
|
+
import { HttpWatchRegistry } from './http-watch-registry.js';
|
|
4
|
+
import { tryResolveGithubDispatchContext } from './github-context.js';
|
|
5
|
+
/**
|
|
6
|
+
* Register a monitor that notifies this process instead of dispatching CI.
|
|
7
|
+
*
|
|
8
|
+
* Best-effort on purpose. Every way this can fail — no GitHub identity to
|
|
9
|
+
* register under, no token, a `"saved"` base place the service cannot poll, a
|
|
10
|
+
* service that is unreachable — has a working answer already: poll Open Cloud
|
|
11
|
+
* from here. So a failure downgrades the watch rather than the run, and the
|
|
12
|
+
* caller falls back.
|
|
13
|
+
*/
|
|
14
|
+
export async function tryRegisterNotifyWatchesAsync(options) {
|
|
15
|
+
const { option, entries } = options;
|
|
16
|
+
if (entries.length === 0) {
|
|
17
|
+
return { success: false, reason: 'no_entries' };
|
|
18
|
+
}
|
|
19
|
+
// Without a shared key the service reads asset delivery, which reports
|
|
20
|
+
// published content only — it refuses `"saved"` at registration, and one
|
|
21
|
+
// refusal fails the whole request. Rather than watch some places one way and
|
|
22
|
+
// some the other, the whole run falls back to polling, which handles every
|
|
23
|
+
// version type this machine has credentials for.
|
|
24
|
+
const credentialed = options.robloxApiKey != null;
|
|
25
|
+
const unwatchable = credentialed
|
|
26
|
+
? []
|
|
27
|
+
: entries.filter((e) => e.versionType !== 'published');
|
|
28
|
+
if (unwatchable.length > 0) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
reason: 'unwatchable_version_type',
|
|
32
|
+
detail: unwatchable.map((e) => e.label).join(', '),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const contextResult = tryResolveGithubDispatchContext({
|
|
36
|
+
useGhAuth: options.useGhAuth,
|
|
37
|
+
});
|
|
38
|
+
if (!contextResult.success) {
|
|
39
|
+
return { success: false, reason: 'no_github_context' };
|
|
40
|
+
}
|
|
41
|
+
const context = contextResult.context;
|
|
42
|
+
// Registration needs a write-scoped PAT even though a notify never spends it:
|
|
43
|
+
// the repository is the only identity this service has, and it is what a
|
|
44
|
+
// monitor's leases and caps are counted against.
|
|
45
|
+
if (!context.token) {
|
|
46
|
+
return { success: false, reason: 'no_token' };
|
|
47
|
+
}
|
|
48
|
+
const streamEntries = entries.map((entry) => ({
|
|
49
|
+
...entry,
|
|
50
|
+
watchName: sanitizeWatchName(entry.label),
|
|
51
|
+
}));
|
|
52
|
+
_disambiguateWatchNames(streamEntries);
|
|
53
|
+
const watches = streamEntries.map((entry) => ({
|
|
54
|
+
name: entry.watchName,
|
|
55
|
+
source: {
|
|
56
|
+
type: 'roblox-place',
|
|
57
|
+
universeId: entry.universeId,
|
|
58
|
+
placeId: entry.placeId,
|
|
59
|
+
versionType: entry.versionType,
|
|
60
|
+
},
|
|
61
|
+
// Only when a key is shared do the two sides speak the same language; the
|
|
62
|
+
// `ready` reconcile covers this either way, by re-checking every watch
|
|
63
|
+
// against Open Cloud on connect.
|
|
64
|
+
...(credentialed && entry.baseline != null
|
|
65
|
+
? {
|
|
66
|
+
baselineVersion: String(entry.baseline),
|
|
67
|
+
baselineVersionKind: WATCH_BASELINE_KIND,
|
|
68
|
+
}
|
|
69
|
+
: {}),
|
|
70
|
+
action: {
|
|
71
|
+
type: 'notify',
|
|
72
|
+
// Same key a dispatching watch puts the selector under, so the two modes
|
|
73
|
+
// describe a change the same way even though only one crosses into CI.
|
|
74
|
+
payload: { [WATCH_INPUT_NAME]: entry.label },
|
|
75
|
+
},
|
|
76
|
+
}));
|
|
77
|
+
const registry = (options.createRegistry ?? _defaultRegistry)(option.registerUrl);
|
|
78
|
+
let result;
|
|
79
|
+
try {
|
|
80
|
+
result = await registry.registerAsync({
|
|
81
|
+
// Distinct from the dispatching monitor's name. They hold different
|
|
82
|
+
// actions, and re-registering replaces a monitor's whole watch list — so
|
|
83
|
+
// sharing a name would mean a local watch silently disarming CI's.
|
|
84
|
+
monitorName: sanitizeWatchName(`${options.monitorName}/local`),
|
|
85
|
+
repository: context.repository,
|
|
86
|
+
githubToken: context.token,
|
|
87
|
+
robloxApiKey: options.robloxApiKey,
|
|
88
|
+
watches,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
reason: 'register_failed',
|
|
95
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (!result.monitorId) {
|
|
99
|
+
return { success: false, reason: 'no_monitor_id' };
|
|
100
|
+
}
|
|
101
|
+
OutputHelper.verbose(`Registered a notify monitor (${result.monitorId}), lease ${option.lease}.`);
|
|
102
|
+
return {
|
|
103
|
+
success: true,
|
|
104
|
+
monitorId: result.monitorId,
|
|
105
|
+
credential: context.token,
|
|
106
|
+
entries: streamEntries,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Why the run is polling instead, in words a user can act on. */
|
|
110
|
+
export function describeNotifyWatchFallback(result) {
|
|
111
|
+
switch (result.reason) {
|
|
112
|
+
case 'no_entries':
|
|
113
|
+
return 'nothing to watch';
|
|
114
|
+
case 'unwatchable_version_type':
|
|
115
|
+
return (`${result.detail} tracks "saved", which the service can only see ` +
|
|
116
|
+
'with a shared Open Cloud key (--watch-share-api-key)');
|
|
117
|
+
case 'no_github_context':
|
|
118
|
+
return 'this checkout has no GitHub repository to register under';
|
|
119
|
+
case 'no_token':
|
|
120
|
+
return ('no GitHub token — set NEVERMORE_WATCH_TOKEN, or pass ' +
|
|
121
|
+
'--watch-use-gh-auth to use the one `gh` already holds');
|
|
122
|
+
case 'no_monitor_id':
|
|
123
|
+
return 'the service registered the monitor but returned no id';
|
|
124
|
+
case 'register_failed':
|
|
125
|
+
return `the watch service refused the registration — ${result.detail}`;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function _defaultRegistry(registerUrl) {
|
|
129
|
+
return new HttpWatchRegistry({ registerUrl });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Make every watch name unique within the monitor.
|
|
133
|
+
*
|
|
134
|
+
* Names come from selectors, which are unique per target — except that an
|
|
135
|
+
* unnamed place in a multi-place target has no name to contribute, so two of
|
|
136
|
+
* them produce the same selector. Appending the place id separates them without
|
|
137
|
+
* failing a deploy that already shipped.
|
|
138
|
+
*/
|
|
139
|
+
function _disambiguateWatchNames(entries) {
|
|
140
|
+
const byName = new Map();
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
const group = byName.get(entry.watchName);
|
|
143
|
+
if (group) {
|
|
144
|
+
group.push(entry);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
byName.set(entry.watchName, [entry]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const group of byName.values()) {
|
|
151
|
+
if (group.length === 1) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
for (const entry of group) {
|
|
155
|
+
entry.watchName = sanitizeWatchName(`${entry.watchName}/${entry.placeId}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=register-notify-watches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-notify-watches.js","sourceRoot":"","sources":["../../../src/utils/watch/register-notify-watches.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAIlB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AAqCtE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,OAAqC;IAErC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAEpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAClD,CAAC;IAED,uEAAuE;IACvE,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,iDAAiD;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC;IAClD,MAAM,WAAW,GAAG,YAAY;QAC9B,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC;IACzD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,0BAA0B;YAClC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SACnD,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,+BAA+B,CAAC;QACpD,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IACH,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACzD,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC;IACtC,8EAA8E;IAC9E,yEAAyE;IACzE,iDAAiD;IACjD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,aAAa,GAAuB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAChE,GAAG,KAAK;QACR,SAAS,EAAE,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC;KAC1C,CAAC,CAAC,CAAC;IACJ,uBAAuB,CAAC,aAAa,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAiB,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,EAAE,KAAK,CAAC,SAAS;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B;QACD,0EAA0E;QAC1E,uEAAuE;QACvE,iCAAiC;QACjC,GAAG,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI;YACxC,CAAC,CAAC;gBACE,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACvC,mBAAmB,EAAE,mBAAmB;aACzC;YACH,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,yEAAyE;YACzE,uEAAuE;YACvE,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE;SAC7C;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,gBAAgB,CAAC,CAC3D,MAAM,CAAC,WAAW,CACnB,CAAC;IAEF,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC;YACpC,oEAAoE;YACpE,yEAAyE;YACzE,mEAAmE;YACnE,WAAW,EAAE,iBAAiB,CAAC,GAAG,OAAO,CAAC,WAAW,QAAQ,CAAC;YAC9D,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW,EAAE,OAAO,CAAC,KAAK;YAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,iBAAiB;YACzB,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACzD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACrD,CAAC;IAED,YAAY,CAAC,OAAO,CAClB,gCAAgC,MAAM,CAAC,SAAS,YAAY,MAAM,CAAC,KAAK,GAAG,CAC5E,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,OAAO,CAAC,KAAK;QACzB,OAAO,EAAE,aAAa;KACvB,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,2BAA2B,CACzC,MAAwD;IAExD,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;QACtB,KAAK,YAAY;YACf,OAAO,kBAAkB,CAAC;QAC5B,KAAK,0BAA0B;YAC7B,OAAO,CACL,GAAG,MAAM,CAAC,MAAM,kDAAkD;gBAClE,sDAAsD,CACvD,CAAC;QACJ,KAAK,mBAAmB;YACtB,OAAO,0DAA0D,CAAC;QACpE,KAAK,UAAU;YACb,OAAO,CACL,uDAAuD;gBACvD,uDAAuD,CACxD,CAAC;QACJ,KAAK,eAAe;YAClB,OAAO,uDAAuD,CAAC;QACjE,KAAK,iBAAiB;YACpB,OAAO,gDAAgD,MAAM,CAAC,MAAM,EAAE,CAAC;IAC3E,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,WAAmB;IAC3C,OAAO,IAAI,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,uBAAuB,CAAC,OAA2B;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAC;IACrD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,SAAS;QACX,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,KAAK,CAAC,SAAS,GAAG,iBAAiB,CACjC,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,EAAE,CACtC,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-notify-watches.test.d.ts","sourceRoot":"","sources":["../../../src/utils/watch/register-notify-watches.test.ts"],"names":[],"mappings":""}
|