@hraness/peopleblade 0.2.1 → 0.2.2
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/README.md +21 -17
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/dist/cli.ts +19 -9
- package/dist/peopleblade.js +358 -339
- package/package.json +1 -1
package/dist/peopleblade.js
CHANGED
|
@@ -4312,13 +4312,13 @@ var peoplebladeCapabilities = Object.freeze({
|
|
|
4312
4312
|
sources: [
|
|
4313
4313
|
{ id: "apple-contacts", command: "contacts sync", status: "supported", transport: "local-database", requirement: "macOS Contacts access" },
|
|
4314
4314
|
{ id: "imessage", command: "imessage sync", status: "supported", transport: "local-metadata", requirement: "macOS Messages access; no message bodies" },
|
|
4315
|
-
{ id: "google-contacts", command: "google sync", status: "supported", transport: "
|
|
4316
|
-
{ id: "beeper", command: "beeper sync", status: "supported", transport: "
|
|
4317
|
-
{ id: "whatsapp", command: "whatsapp sync", status: "supported", transport: "
|
|
4315
|
+
{ id: "google-contacts", command: "google sync", status: "supported", transport: "ghostget", requirement: "Reviewed Gmail/People contacts.list and contact scopes" },
|
|
4316
|
+
{ id: "beeper", command: "beeper sync", status: "supported", transport: "ghostget", requirement: "Ghostget 0.17.1, Beeper adapter 2.4.0, CLI 0.6.2; body-free relationships require macOS arm64" },
|
|
4317
|
+
{ id: "whatsapp", command: "whatsapp sync", status: "supported", transport: "ghostget", requirement: "Reviewed linked-device contacts.list v2" },
|
|
4318
4318
|
{ id: "linkedin", command: "linkedin import", status: "supported", transport: "official-archive", requirement: "Owner-selected official ZIP; no authenticated browser collection" },
|
|
4319
4319
|
{ id: "instagram", command: "instagram import", status: "supported", transport: "official-archive", requirement: "Owner-selected JSON ZIP and exact owner username" },
|
|
4320
4320
|
{ id: "x-archive", command: "x import", status: "bounded", transport: "official-archive", requirement: "Owner-selected ZIP; unresolved IDs remain inert" },
|
|
4321
|
-
{ id: "x-live", command: "x mutuals sync", status: "blocked", transport: "unavailable", requirement: "A reviewed bounded
|
|
4321
|
+
{ id: "x-live", command: "x mutuals sync", status: "blocked", transport: "unavailable", requirement: "A reviewed bounded Ghostget mutuals capability is not yet available" },
|
|
4322
4322
|
{ id: "telegram", command: "telegram status", status: "planned", transport: "unavailable", requirement: "First real export and importer validation remain pending" }
|
|
4323
4323
|
],
|
|
4324
4324
|
enrichment: [
|
|
@@ -12341,7 +12341,7 @@ function importContactSourceSnapshot(database, value) {
|
|
|
12341
12341
|
}
|
|
12342
12342
|
}
|
|
12343
12343
|
|
|
12344
|
-
// node_modules/@hraness/
|
|
12344
|
+
// node_modules/@hraness/ghostget/dist/index-26yq8q16.js
|
|
12345
12345
|
var PROVIDER_PLUGIN_ID_MAX_LENGTH = 63;
|
|
12346
12346
|
var PROVIDER_PLUGIN_OPERATION_NAME_MAX_LENGTH = 163;
|
|
12347
12347
|
var strictKebabPattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
|
|
@@ -12360,7 +12360,7 @@ function isProviderPluginOperationName(value) {
|
|
|
12360
12360
|
return segments.length >= 2 && segments.length <= 4 && segments.every((segment) => segment.length <= 40 && strictKebabSegmentPattern.test(segment));
|
|
12361
12361
|
}
|
|
12362
12362
|
|
|
12363
|
-
// node_modules/@hraness/
|
|
12363
|
+
// node_modules/@hraness/ghostget/dist/index-gwk7rbyj.js
|
|
12364
12364
|
import { createHash as createHash4 } from "crypto";
|
|
12365
12365
|
function isRecord(value) {
|
|
12366
12366
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -12388,7 +12388,7 @@ function sha2563(value) {
|
|
|
12388
12388
|
return createHash4("sha256").update(value).digest("hex");
|
|
12389
12389
|
}
|
|
12390
12390
|
|
|
12391
|
-
// node_modules/@hraness/
|
|
12391
|
+
// node_modules/@hraness/ghostget/dist/client.js
|
|
12392
12392
|
import { spawn, spawnSync } from "child_process";
|
|
12393
12393
|
import { existsSync as existsSync3 } from "fs";
|
|
12394
12394
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -12485,7 +12485,7 @@ function publicWebSessionAuthority(request) {
|
|
|
12485
12485
|
function expectedRequestAuthId(request, authKind) {
|
|
12486
12486
|
if (authKind === PUBLIC_WEB_SESSION_AUTHORITY_KIND) {
|
|
12487
12487
|
if (request.authId !== undefined) {
|
|
12488
|
-
throw new Error("
|
|
12488
|
+
throw new Error("Ghostget public invocation unexpectedly accepted an auth locator");
|
|
12489
12489
|
}
|
|
12490
12490
|
return publicWebSessionAuthority(request).id;
|
|
12491
12491
|
}
|
|
@@ -12535,14 +12535,14 @@ var clientReadFailureRetryDisposition = Object.freeze({
|
|
|
12535
12535
|
"cleanup-required": "do-not-retry"
|
|
12536
12536
|
});
|
|
12537
12537
|
function parseClientReadFailure(value) {
|
|
12538
|
-
const failure = record(value, "
|
|
12539
|
-
assertExactKeys(failure, ["category", "retryDisposition"], [], "
|
|
12538
|
+
const failure = record(value, "Ghostget read failure");
|
|
12539
|
+
assertExactKeys(failure, ["category", "retryDisposition"], [], "Ghostget read failure");
|
|
12540
12540
|
const category = failure.category;
|
|
12541
12541
|
if (typeof category !== "string" || !Object.hasOwn(clientReadFailureRetryDisposition, category))
|
|
12542
|
-
throw new Error("
|
|
12542
|
+
throw new Error("Ghostget read failure category is malformed");
|
|
12543
12543
|
const retryDisposition = clientReadFailureRetryDisposition[category];
|
|
12544
12544
|
if (failure.retryDisposition !== retryDisposition) {
|
|
12545
|
-
throw new Error("
|
|
12545
|
+
throw new Error("Ghostget read failure retry disposition is inconsistent");
|
|
12546
12546
|
}
|
|
12547
12547
|
return Object.freeze({ category, retryDisposition });
|
|
12548
12548
|
}
|
|
@@ -12693,16 +12693,16 @@ function cliSourcePath() {
|
|
|
12693
12693
|
const packagedSource = fileURLToPath2(new URL("../src/cli.ts", import.meta.url));
|
|
12694
12694
|
if (existsSync3(packagedSource))
|
|
12695
12695
|
return packagedSource;
|
|
12696
|
-
throw new Error("the installed
|
|
12696
|
+
throw new Error("the installed Ghostget CLI source is unavailable");
|
|
12697
12697
|
}
|
|
12698
12698
|
function requireBunRuntime() {
|
|
12699
12699
|
if (typeof process.versions.bun !== "string") {
|
|
12700
|
-
throw new Error("@hraness/
|
|
12700
|
+
throw new Error("@hraness/ghostget/client requires Bun to run the installed Ghostget CLI");
|
|
12701
12701
|
}
|
|
12702
12702
|
}
|
|
12703
12703
|
function environmentName(value) {
|
|
12704
12704
|
if (value.length < 1 || value.includes("=") || value.includes("\x00")) {
|
|
12705
|
-
throw new Error("
|
|
12705
|
+
throw new Error("Ghostget client environment name is malformed");
|
|
12706
12706
|
}
|
|
12707
12707
|
return value;
|
|
12708
12708
|
}
|
|
@@ -12723,26 +12723,26 @@ function snapshotChildEnvironment(overrides) {
|
|
|
12723
12723
|
if (overrides === undefined)
|
|
12724
12724
|
return Object.freeze(environment);
|
|
12725
12725
|
if (!isRecord2(overrides) || nodeTypes.isProxy(overrides) || Object.getPrototypeOf(overrides) !== Object.prototype && Object.getPrototypeOf(overrides) !== null) {
|
|
12726
|
-
throw new Error("
|
|
12726
|
+
throw new Error("Ghostget client environment must use a plain, non-proxy object");
|
|
12727
12727
|
}
|
|
12728
12728
|
const descriptors = Object.getOwnPropertyDescriptors(overrides);
|
|
12729
12729
|
const keys = Reflect.ownKeys(descriptors);
|
|
12730
12730
|
if (keys.some((key) => typeof key !== "string")) {
|
|
12731
|
-
throw new Error("
|
|
12731
|
+
throw new Error("Ghostget client environment has unsupported symbol fields");
|
|
12732
12732
|
}
|
|
12733
12733
|
for (const key of keys.sort((left, right) => left.localeCompare(right))) {
|
|
12734
12734
|
const descriptor = descriptors[key];
|
|
12735
12735
|
if (descriptor === undefined || !("value" in descriptor)) {
|
|
12736
|
-
throw new Error("
|
|
12736
|
+
throw new Error("Ghostget client environment must contain only data properties");
|
|
12737
12737
|
}
|
|
12738
12738
|
if (!descriptor.enumerable) {
|
|
12739
|
-
throw new Error("
|
|
12739
|
+
throw new Error("Ghostget client environment properties must be enumerable");
|
|
12740
12740
|
}
|
|
12741
12741
|
const name = environmentName(key);
|
|
12742
12742
|
if (descriptor.value === undefined) {
|
|
12743
12743
|
delete environment[name];
|
|
12744
12744
|
} else if (typeof descriptor.value !== "string" || descriptor.value.includes("\x00")) {
|
|
12745
|
-
throw new Error("
|
|
12745
|
+
throw new Error("Ghostget client environment value is malformed");
|
|
12746
12746
|
} else {
|
|
12747
12747
|
defineEnvironmentValue(environment, name, descriptor.value);
|
|
12748
12748
|
}
|
|
@@ -12762,20 +12762,20 @@ function isBrandedAbortSignal(value) {
|
|
|
12762
12762
|
}
|
|
12763
12763
|
function snapshotClientOptions(optionsValue, mode) {
|
|
12764
12764
|
if (!isRecord2(optionsValue) || nodeTypes.isProxy(optionsValue) || Object.getPrototypeOf(optionsValue) !== Object.prototype && Object.getPrototypeOf(optionsValue) !== null)
|
|
12765
|
-
throw new Error("
|
|
12765
|
+
throw new Error("Ghostget client options must use a plain, non-proxy object");
|
|
12766
12766
|
const descriptors = Object.getOwnPropertyDescriptors(optionsValue);
|
|
12767
12767
|
const keys = Reflect.ownKeys(descriptors);
|
|
12768
12768
|
if (keys.some((key) => typeof key !== "string")) {
|
|
12769
|
-
throw new Error("
|
|
12769
|
+
throw new Error("Ghostget client options have unsupported symbol fields");
|
|
12770
12770
|
}
|
|
12771
12771
|
const allowed = new Set(mode === "read" ? ["environment", "freshForMs", "now"] : mode === "revalidation" ? ["environment", "freshForMs", "now", "headed", "signal"] : mode === "invoke-async" ? ["environment", "headed", "signal"] : ["environment", "headed"]);
|
|
12772
12772
|
for (const key of keys) {
|
|
12773
12773
|
const descriptor = descriptors[key];
|
|
12774
12774
|
if (descriptor === undefined || !allowed.has(key)) {
|
|
12775
|
-
throw new Error("
|
|
12775
|
+
throw new Error("Ghostget client options contain an unsupported field");
|
|
12776
12776
|
}
|
|
12777
12777
|
if (!("value" in descriptor)) {
|
|
12778
|
-
throw new Error("
|
|
12778
|
+
throw new Error("Ghostget client options must contain only data properties");
|
|
12779
12779
|
}
|
|
12780
12780
|
}
|
|
12781
12781
|
const option = (key) => descriptors[key]?.value;
|
|
@@ -12783,27 +12783,27 @@ function snapshotClientOptions(optionsValue, mode) {
|
|
|
12783
12783
|
const nowValue = option("now");
|
|
12784
12784
|
const headedValue = option("headed");
|
|
12785
12785
|
const signalValue = option("signal");
|
|
12786
|
-
const freshForMs = freshForMsValue === undefined ? undefined : safeInteger(freshForMsValue, "
|
|
12786
|
+
const freshForMs = freshForMsValue === undefined ? undefined : safeInteger(freshForMsValue, "Ghostget client freshness window", 0, MAX_FRESH_FOR_MS);
|
|
12787
12787
|
let now;
|
|
12788
12788
|
if (nowValue !== undefined) {
|
|
12789
12789
|
if (nodeTypes.isProxy(nowValue) || !(nowValue instanceof Date) || Object.getPrototypeOf(nowValue) !== Date.prototype)
|
|
12790
|
-
throw new Error("
|
|
12790
|
+
throw new Error("Ghostget client observation time is invalid");
|
|
12791
12791
|
let time;
|
|
12792
12792
|
try {
|
|
12793
12793
|
time = Date.prototype.getTime.call(nowValue);
|
|
12794
12794
|
} catch {
|
|
12795
|
-
throw new Error("
|
|
12795
|
+
throw new Error("Ghostget client observation time is invalid");
|
|
12796
12796
|
}
|
|
12797
12797
|
if (!Number.isFinite(time)) {
|
|
12798
|
-
throw new Error("
|
|
12798
|
+
throw new Error("Ghostget client observation time is invalid");
|
|
12799
12799
|
}
|
|
12800
12800
|
now = new Date(time);
|
|
12801
12801
|
}
|
|
12802
12802
|
if (headedValue !== undefined && typeof headedValue !== "boolean") {
|
|
12803
|
-
throw new Error("
|
|
12803
|
+
throw new Error("Ghostget client headed option is malformed");
|
|
12804
12804
|
}
|
|
12805
12805
|
if (signalValue !== undefined && !isBrandedAbortSignal(signalValue))
|
|
12806
|
-
throw new Error("
|
|
12806
|
+
throw new Error("Ghostget client abort signal is malformed");
|
|
12807
12807
|
return Object.freeze({
|
|
12808
12808
|
cwd: process.cwd(),
|
|
12809
12809
|
environment: snapshotChildEnvironment(option("environment")),
|
|
@@ -12814,18 +12814,18 @@ function snapshotClientOptions(optionsValue, mode) {
|
|
|
12814
12814
|
});
|
|
12815
12815
|
}
|
|
12816
12816
|
function prepareRequest(requestValue) {
|
|
12817
|
-
const snapshot = snapshotJson(requestValue, "
|
|
12818
|
-
const request = record(snapshot, "
|
|
12819
|
-
assertExactKeys(request, ["adapterId", "operationId"], ["authId", "input"], "
|
|
12820
|
-
const adapterId = safeString(request.adapterId, "
|
|
12821
|
-
const operationId = providerOperationName(request.operationId, "
|
|
12822
|
-
const authId = Object.hasOwn(request, "authId") ? safeString(request.authId, "
|
|
12817
|
+
const snapshot = snapshotJson(requestValue, "Ghostget client request");
|
|
12818
|
+
const request = record(snapshot, "Ghostget client request");
|
|
12819
|
+
assertExactKeys(request, ["adapterId", "operationId"], ["authId", "input"], "Ghostget client request");
|
|
12820
|
+
const adapterId = safeString(request.adapterId, "Ghostget client adapter ID", 64);
|
|
12821
|
+
const operationId = providerOperationName(request.operationId, "Ghostget client operation ID");
|
|
12822
|
+
const authId = Object.hasOwn(request, "authId") ? safeString(request.authId, "Ghostget client auth ID", 64) : undefined;
|
|
12823
12823
|
const rawInput = Object.hasOwn(request, "input") ? request.input : {};
|
|
12824
12824
|
if (!isRecord2(rawInput))
|
|
12825
12825
|
throw new Error("input must be a JSON object");
|
|
12826
12826
|
const input = canonicalJson2(rawInput);
|
|
12827
12827
|
if (Buffer.byteLength(input, "utf8") > MAX_INPUT_BYTES) {
|
|
12828
|
-
throw new Error("
|
|
12828
|
+
throw new Error("Ghostget client input exceeds its byte bound");
|
|
12829
12829
|
}
|
|
12830
12830
|
return Object.freeze({
|
|
12831
12831
|
adapterId,
|
|
@@ -12896,7 +12896,7 @@ function runIdentityCommand(command, options, label, responseLabel = `${label} r
|
|
|
12896
12896
|
return parseOutput(stdout, responseLabel);
|
|
12897
12897
|
}
|
|
12898
12898
|
function runProjectionIdentityCommand(command, options) {
|
|
12899
|
-
return runIdentityCommand(command, options, "
|
|
12899
|
+
return runIdentityCommand(command, options, "Ghostget projection identity preflight", "Ghostget projection identity response");
|
|
12900
12900
|
}
|
|
12901
12901
|
function observeProjectionIdentity(request, options) {
|
|
12902
12902
|
const value = runProjectionIdentityCommand(preparedCommand(request, {
|
|
@@ -12905,7 +12905,7 @@ function observeProjectionIdentity(request, options) {
|
|
|
12905
12905
|
headed: false
|
|
12906
12906
|
}), options);
|
|
12907
12907
|
if (value.ok !== true || value.source !== "projection-identity")
|
|
12908
|
-
throw new Error("
|
|
12908
|
+
throw new Error("Ghostget projection identity response is malformed");
|
|
12909
12909
|
if (value.status === "ready") {
|
|
12910
12910
|
assertExactKeys(value, [
|
|
12911
12911
|
"ok",
|
|
@@ -12915,15 +12915,15 @@ function observeProjectionIdentity(request, options) {
|
|
|
12915
12915
|
"authHash",
|
|
12916
12916
|
"inputHash",
|
|
12917
12917
|
"projection"
|
|
12918
|
-
], [], "
|
|
12919
|
-
const projection = record(value.projection, "
|
|
12920
|
-
assertExactKeys(projection, ["key"], [], "
|
|
12918
|
+
], [], "Ghostget projection identity response");
|
|
12919
|
+
const projection = record(value.projection, "Ghostget projection identity");
|
|
12920
|
+
assertExactKeys(projection, ["key"], [], "Ghostget projection identity");
|
|
12921
12921
|
return Object.freeze({
|
|
12922
12922
|
status: "ready",
|
|
12923
|
-
key: digest(projection.key, "
|
|
12924
|
-
authIdentity: digest(value.authIdentity, "
|
|
12925
|
-
authHash: digest(value.authHash, "
|
|
12926
|
-
inputHash: digest(value.inputHash, "
|
|
12923
|
+
key: digest(projection.key, "Ghostget projection identity key"),
|
|
12924
|
+
authIdentity: digest(value.authIdentity, "Ghostget projection auth identity"),
|
|
12925
|
+
authHash: digest(value.authHash, "Ghostget projection auth hash"),
|
|
12926
|
+
inputHash: digest(value.inputHash, "Ghostget projection validated input hash")
|
|
12927
12927
|
});
|
|
12928
12928
|
}
|
|
12929
12929
|
if (value.status === "unbound") {
|
|
@@ -12934,15 +12934,15 @@ function observeProjectionIdentity(request, options) {
|
|
|
12934
12934
|
"authIdentity",
|
|
12935
12935
|
"authHash",
|
|
12936
12936
|
"inputHash"
|
|
12937
|
-
], [], "
|
|
12937
|
+
], [], "Ghostget projection identity response");
|
|
12938
12938
|
return Object.freeze({
|
|
12939
12939
|
status: "unbound",
|
|
12940
|
-
authIdentity: digest(value.authIdentity, "
|
|
12941
|
-
authHash: digest(value.authHash, "
|
|
12942
|
-
inputHash: digest(value.inputHash, "
|
|
12940
|
+
authIdentity: digest(value.authIdentity, "Ghostget projection auth identity"),
|
|
12941
|
+
authHash: digest(value.authHash, "Ghostget projection auth hash"),
|
|
12942
|
+
inputHash: digest(value.inputHash, "Ghostget projection validated input hash")
|
|
12943
12943
|
});
|
|
12944
12944
|
}
|
|
12945
|
-
throw new Error("
|
|
12945
|
+
throw new Error("Ghostget projection identity response is malformed");
|
|
12946
12946
|
}
|
|
12947
12947
|
function projectionIdentitiesMatch(before, after) {
|
|
12948
12948
|
return before.status === "ready" ? after.status === "ready" && after.key === before.key && after.authIdentity === before.authIdentity && after.authHash === before.authHash && after.inputHash === before.inputHash : after.status === "unbound" && after.authIdentity === before.authIdentity && after.authHash === before.authHash && after.inputHash === before.inputHash;
|
|
@@ -12962,43 +12962,43 @@ function parseExecutionPreview(value, request) {
|
|
|
12962
12962
|
"identityBinding",
|
|
12963
12963
|
"transport",
|
|
12964
12964
|
...portable ? ["portablePluginContract"] : []
|
|
12965
|
-
], [], "
|
|
12965
|
+
], [], "Ghostget execution identity preview");
|
|
12966
12966
|
if (value.ok !== true || value.status !== "preview" || value.requiresConfirmation !== false || value.risk !== "R1")
|
|
12967
|
-
throw new Error("
|
|
12968
|
-
const adapterValue = record(value.adapter, "
|
|
12969
|
-
const auth = record(value.auth, "
|
|
12970
|
-
const binding2 = record(value.identityBinding, "
|
|
12971
|
-
assertExactKeys(adapterValue, ["id", "version", "hash"], [], "
|
|
12972
|
-
assertExactKeys(auth, ["id", "kind", "realmFingerprint"], [], "
|
|
12973
|
-
assertExactKeys(binding2, ["status", "subject", "accountActor", "requestedActor"], [], "
|
|
12967
|
+
throw new Error("Ghostget execution identity preview is malformed");
|
|
12968
|
+
const adapterValue = record(value.adapter, "Ghostget execution identity preview adapter");
|
|
12969
|
+
const auth = record(value.auth, "Ghostget execution identity preview auth");
|
|
12970
|
+
const binding2 = record(value.identityBinding, "Ghostget execution identity preview binding");
|
|
12971
|
+
assertExactKeys(adapterValue, ["id", "version", "hash"], [], "Ghostget execution identity preview adapter");
|
|
12972
|
+
assertExactKeys(auth, ["id", "kind", "realmFingerprint"], [], "Ghostget execution identity preview auth");
|
|
12973
|
+
assertExactKeys(binding2, ["status", "subject", "accountActor", "requestedActor"], [], "Ghostget execution identity preview binding");
|
|
12974
12974
|
const adapter = Object.freeze({
|
|
12975
|
-
id: safeString(adapterValue.id, "
|
|
12976
|
-
version: safeString(adapterValue.version, "
|
|
12977
|
-
hash: digest(adapterValue.hash, "
|
|
12975
|
+
id: safeString(adapterValue.id, "Ghostget execution identity preview adapter ID", 64),
|
|
12976
|
+
version: safeString(adapterValue.version, "Ghostget execution identity preview adapter version", 64),
|
|
12977
|
+
hash: digest(adapterValue.hash, "Ghostget execution identity preview adapter hash")
|
|
12978
12978
|
});
|
|
12979
|
-
const operation = providerOperationName(value.operation, "
|
|
12979
|
+
const operation = providerOperationName(value.operation, "Ghostget execution identity preview operation");
|
|
12980
12980
|
if (adapter.id !== request.adapterId || operation !== request.operationId) {
|
|
12981
|
-
throw new Error("
|
|
12981
|
+
throw new Error("Ghostget execution identity preview route is malformed");
|
|
12982
12982
|
}
|
|
12983
|
-
const authKind = safeString(auth.kind, "
|
|
12984
|
-
if (safeString(auth.id, "
|
|
12985
|
-
throw new Error("
|
|
12986
|
-
const realmFingerprint = safeString(auth.realmFingerprint, "
|
|
12983
|
+
const authKind = safeString(auth.kind, "Ghostget execution identity preview auth kind", 64);
|
|
12984
|
+
if (safeString(auth.id, "Ghostget execution identity preview auth ID", 64) !== expectedRequestAuthId(request, authKind))
|
|
12985
|
+
throw new Error("Ghostget execution identity preview auth is malformed");
|
|
12986
|
+
const realmFingerprint = safeString(auth.realmFingerprint, "Ghostget execution identity preview auth fingerprint", 16);
|
|
12987
12987
|
if (!/^[a-f0-9]{16}$/u.test(realmFingerprint)) {
|
|
12988
|
-
throw new Error("
|
|
12988
|
+
throw new Error("Ghostget execution identity preview auth fingerprint is malformed");
|
|
12989
12989
|
}
|
|
12990
12990
|
if (authKind === PUBLIC_WEB_SESSION_AUTHORITY_KIND) {
|
|
12991
12991
|
const authority = publicWebSessionAuthority(request);
|
|
12992
12992
|
if (value.transport !== "web-session-api" || realmFingerprint !== sha2563(canonicalJson2(authority)).slice(0, 16) || binding2.status !== "public" || binding2.subject !== authority.subject || binding2.accountActor !== null || binding2.requestedActor !== null) {
|
|
12993
|
-
throw new Error("
|
|
12993
|
+
throw new Error("Ghostget execution identity preview public authority is malformed");
|
|
12994
12994
|
}
|
|
12995
12995
|
}
|
|
12996
|
-
safeString(value.sideEffect, "
|
|
12996
|
+
safeString(value.sideEffect, "Ghostget execution identity preview side effect", 64);
|
|
12997
12997
|
const transport = value.transport;
|
|
12998
12998
|
if (transport === "portable-provider-plugin") {
|
|
12999
12999
|
const portablePluginContract = parsePortableOperationIdentity(value.portablePluginContract);
|
|
13000
13000
|
if (portablePluginContract.adapterId !== adapter.id || portablePluginContract.operation !== operation)
|
|
13001
|
-
throw new Error("
|
|
13001
|
+
throw new Error("Ghostget execution identity preview route is malformed");
|
|
13002
13002
|
return Object.freeze({
|
|
13003
13003
|
adapter,
|
|
13004
13004
|
operation,
|
|
@@ -13007,18 +13007,18 @@ function parseExecutionPreview(value, request) {
|
|
|
13007
13007
|
});
|
|
13008
13008
|
}
|
|
13009
13009
|
if (transport !== "browser" && transport !== "provider-api" && transport !== "web-session-api" && transport !== "reviewed-template-api" && transport !== "local-cli")
|
|
13010
|
-
throw new Error("
|
|
13010
|
+
throw new Error("Ghostget execution identity preview transport is malformed");
|
|
13011
13011
|
return Object.freeze({ adapter, operation, transport });
|
|
13012
13012
|
}
|
|
13013
13013
|
function parseCatalogExecutionIdentity(value, request, preview) {
|
|
13014
|
-
assertExactKeys(value, ["ok", "adapters"], [], "
|
|
13014
|
+
assertExactKeys(value, ["ok", "adapters"], [], "Ghostget execution identity catalog");
|
|
13015
13015
|
if (value.ok !== true || !isUnknownArray(value.adapters)) {
|
|
13016
|
-
throw new Error("
|
|
13016
|
+
throw new Error("Ghostget execution identity catalog is malformed");
|
|
13017
13017
|
}
|
|
13018
13018
|
if (value.adapters.length !== 1) {
|
|
13019
|
-
throw new Error("
|
|
13019
|
+
throw new Error("Ghostget execution identity catalog is ambiguous");
|
|
13020
13020
|
}
|
|
13021
|
-
const adapterValue = record(value.adapters[0], "
|
|
13021
|
+
const adapterValue = record(value.adapters[0], "Ghostget execution identity catalog adapter");
|
|
13022
13022
|
assertExactKeys(adapterValue, [
|
|
13023
13023
|
"id",
|
|
13024
13024
|
"version",
|
|
@@ -13027,17 +13027,17 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13027
13027
|
"origins",
|
|
13028
13028
|
"manifestHash",
|
|
13029
13029
|
"operations"
|
|
13030
|
-
], [], "
|
|
13030
|
+
], [], "Ghostget execution identity catalog adapter");
|
|
13031
13031
|
const adapter = Object.freeze({
|
|
13032
|
-
id: safeString(adapterValue.id, "
|
|
13033
|
-
version: safeString(adapterValue.version, "
|
|
13034
|
-
hash: digest(adapterValue.manifestHash, "
|
|
13032
|
+
id: safeString(adapterValue.id, "Ghostget execution identity catalog adapter ID", 64),
|
|
13033
|
+
version: safeString(adapterValue.version, "Ghostget execution identity catalog adapter version", 64),
|
|
13034
|
+
hash: digest(adapterValue.manifestHash, "Ghostget execution identity catalog adapter hash")
|
|
13035
13035
|
});
|
|
13036
13036
|
if (adapter.id !== request.adapterId || adapter.id !== preview.adapter.id || adapter.version !== preview.adapter.version || adapter.hash !== preview.adapter.hash || !isUnknownArray(adapterValue.operations))
|
|
13037
|
-
throw new Error("
|
|
13037
|
+
throw new Error("Ghostget execution identity preflights disagreed");
|
|
13038
13038
|
const operations = adapterValue.operations.filter((candidate) => isRecord2(candidate) && candidate.id === request.operationId);
|
|
13039
13039
|
if (operations.length !== 1) {
|
|
13040
|
-
throw new Error("
|
|
13040
|
+
throw new Error("Ghostget execution identity catalog operation is ambiguous");
|
|
13041
13041
|
}
|
|
13042
13042
|
const operation = operations[0];
|
|
13043
13043
|
const commonKeys = [
|
|
@@ -13051,7 +13051,7 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13051
13051
|
"input"
|
|
13052
13052
|
];
|
|
13053
13053
|
if (operation.risk !== "R1" || operation.transport !== preview.transport)
|
|
13054
|
-
throw new Error("
|
|
13054
|
+
throw new Error("Ghostget execution identity preflights disagreed");
|
|
13055
13055
|
const common = Object.freeze({
|
|
13056
13056
|
adapter,
|
|
13057
13057
|
operation: preview.operation
|
|
@@ -13066,18 +13066,18 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13066
13066
|
"requiredScopeSets",
|
|
13067
13067
|
"coverage",
|
|
13068
13068
|
"implementation"
|
|
13069
|
-
], [], "
|
|
13070
|
-
const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "
|
|
13071
|
-
const provider = providerSurfaceId(operation.provider, "
|
|
13072
|
-
const providerAction = providerOperationName(operation.providerAction, "
|
|
13073
|
-
safeInteger(operation.providerContractVersion, "
|
|
13069
|
+
], [], "Ghostget execution identity provider capability");
|
|
13070
|
+
const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Ghostget execution identity catalog surface");
|
|
13071
|
+
const provider = providerSurfaceId(operation.provider, "Ghostget execution identity provider surface");
|
|
13072
|
+
const providerAction = providerOperationName(operation.providerAction, "Ghostget execution identity provider action");
|
|
13073
|
+
safeInteger(operation.providerContractVersion, "Ghostget execution identity provider contract version", 1, 1e6);
|
|
13074
13074
|
if (provider !== catalogSurface || providerAction !== preview.operation)
|
|
13075
|
-
throw new Error("
|
|
13075
|
+
throw new Error("Ghostget execution identity provider route is malformed");
|
|
13076
13076
|
return Object.freeze({
|
|
13077
13077
|
...common,
|
|
13078
13078
|
schemaVersion: 3,
|
|
13079
13079
|
transport: "provider-api",
|
|
13080
|
-
providerContractHash: digest(operation.providerContractHash, "
|
|
13080
|
+
providerContractHash: digest(operation.providerContractHash, "Ghostget execution identity provider contract hash")
|
|
13081
13081
|
});
|
|
13082
13082
|
}
|
|
13083
13083
|
if (preview.transport === "web-session-api") {
|
|
@@ -13089,18 +13089,18 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13089
13089
|
"webSessionContractHash",
|
|
13090
13090
|
"state",
|
|
13091
13091
|
"implementation"
|
|
13092
|
-
], [], "
|
|
13093
|
-
const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "
|
|
13094
|
-
const site = providerSurfaceId(operation.site, "
|
|
13095
|
-
const webSessionAction = providerOperationName(operation.webSessionAction, "
|
|
13096
|
-
safeInteger(operation.webSessionContractVersion, "
|
|
13092
|
+
], [], "Ghostget execution identity web-session capability");
|
|
13093
|
+
const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Ghostget execution identity catalog surface");
|
|
13094
|
+
const site = providerSurfaceId(operation.site, "Ghostget execution identity web-session surface");
|
|
13095
|
+
const webSessionAction = providerOperationName(operation.webSessionAction, "Ghostget execution identity web-session action");
|
|
13096
|
+
safeInteger(operation.webSessionContractVersion, "Ghostget execution identity web-session contract version", 1, 1e6);
|
|
13097
13097
|
if (site !== catalogSurface || webSessionAction !== preview.operation)
|
|
13098
|
-
throw new Error("
|
|
13098
|
+
throw new Error("Ghostget execution identity web-session route is malformed");
|
|
13099
13099
|
return Object.freeze({
|
|
13100
13100
|
...common,
|
|
13101
13101
|
schemaVersion: 4,
|
|
13102
13102
|
transport: "web-session-api",
|
|
13103
|
-
webSessionContractHash: digest(operation.webSessionContractHash, "
|
|
13103
|
+
webSessionContractHash: digest(operation.webSessionContractHash, "Ghostget execution identity web-session contract hash")
|
|
13104
13104
|
});
|
|
13105
13105
|
}
|
|
13106
13106
|
if (preview.transport === "local-cli") {
|
|
@@ -13113,8 +13113,8 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13113
13113
|
"localCliTool",
|
|
13114
13114
|
"state",
|
|
13115
13115
|
"implementation"
|
|
13116
|
-
], [], "
|
|
13117
|
-
const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "
|
|
13116
|
+
], [], "Ghostget execution identity local CLI capability");
|
|
13117
|
+
const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Ghostget execution identity catalog surface");
|
|
13118
13118
|
const localCliContract = parseLocalCliContractIdentity({
|
|
13119
13119
|
surface: operation.surface,
|
|
13120
13120
|
action: operation.localCliAction,
|
|
@@ -13123,7 +13123,7 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13123
13123
|
tool: operation.localCliTool
|
|
13124
13124
|
});
|
|
13125
13125
|
if (localCliContract.surface !== catalogSurface || localCliContract.action !== preview.operation) {
|
|
13126
|
-
throw new Error("
|
|
13126
|
+
throw new Error("Ghostget execution identity local CLI route is malformed");
|
|
13127
13127
|
}
|
|
13128
13128
|
return Object.freeze({
|
|
13129
13129
|
...common,
|
|
@@ -13137,13 +13137,13 @@ function parseCatalogExecutionIdentity(value, request, preview) {
|
|
|
13137
13137
|
"state",
|
|
13138
13138
|
"reviewedTemplateContractVersion",
|
|
13139
13139
|
"reviewedTemplateContractHash"
|
|
13140
|
-
], ["instructions", "reviewedAt", "evidenceSha256", "origin"], "
|
|
13141
|
-
safeInteger(operation.reviewedTemplateContractVersion, "
|
|
13140
|
+
], ["instructions", "reviewedAt", "evidenceSha256", "origin"], "Ghostget execution identity reviewed-template capability");
|
|
13141
|
+
safeInteger(operation.reviewedTemplateContractVersion, "Ghostget execution identity reviewed-template contract version", 1, Number.MAX_SAFE_INTEGER);
|
|
13142
13142
|
return Object.freeze({
|
|
13143
13143
|
...common,
|
|
13144
13144
|
schemaVersion: 5,
|
|
13145
13145
|
transport: "reviewed-template-api",
|
|
13146
|
-
reviewedTemplateContractHash: digest(operation.reviewedTemplateContractHash, "
|
|
13146
|
+
reviewedTemplateContractHash: digest(operation.reviewedTemplateContractHash, "Ghostget execution identity reviewed-template contract hash")
|
|
13147
13147
|
});
|
|
13148
13148
|
}
|
|
13149
13149
|
function observeExecutionIdentity(request, options) {
|
|
@@ -13152,7 +13152,7 @@ function observeExecutionIdentity(request, options) {
|
|
|
13152
13152
|
projectionIdentityOnly: false,
|
|
13153
13153
|
preview: true,
|
|
13154
13154
|
headed: false
|
|
13155
|
-
}), options, "
|
|
13155
|
+
}), options, "Ghostget execution identity preview"), request);
|
|
13156
13156
|
if (preview.transport === "portable-provider-plugin") {
|
|
13157
13157
|
return Object.freeze({
|
|
13158
13158
|
adapter: preview.adapter,
|
|
@@ -13170,7 +13170,7 @@ function observeExecutionIdentity(request, options) {
|
|
|
13170
13170
|
transport: preview.transport
|
|
13171
13171
|
});
|
|
13172
13172
|
}
|
|
13173
|
-
return parseCatalogExecutionIdentity(runIdentityCommand(preparedCapabilitiesCommand(request), options, "
|
|
13173
|
+
return parseCatalogExecutionIdentity(runIdentityCommand(preparedCapabilitiesCommand(request), options, "Ghostget execution identity catalog preflight"), request, preview);
|
|
13174
13174
|
}
|
|
13175
13175
|
function receiptExecutionIdentity(receipt) {
|
|
13176
13176
|
const common = Object.freeze({
|
|
@@ -13240,59 +13240,59 @@ function runLiveCommandSync(command, options) {
|
|
|
13240
13240
|
const stdout = String(result.stdout ?? "");
|
|
13241
13241
|
const stderr = String(result.stderr ?? "");
|
|
13242
13242
|
if (stdout.trim().length === 0) {
|
|
13243
|
-
throw new Error(boundedMessage(stderr) || `
|
|
13243
|
+
throw new Error(boundedMessage(stderr) || `Ghostget live invocation exited ${String(code)}`);
|
|
13244
13244
|
}
|
|
13245
13245
|
if (code !== 0 && code !== 3 && code !== 5) {
|
|
13246
|
-
throw new Error(boundedMessage(stderr) || `
|
|
13246
|
+
throw new Error(boundedMessage(stderr) || `Ghostget live invocation exited ${String(code)}`);
|
|
13247
13247
|
}
|
|
13248
|
-
return parseOutput(stdout, "
|
|
13248
|
+
return parseOutput(stdout, "Ghostget live response");
|
|
13249
13249
|
}
|
|
13250
13250
|
function parsePublication(value) {
|
|
13251
|
-
const publication = record(value, "
|
|
13252
|
-
assertExactKeys(publication, ["key", "dataRevision", "validatedAt", "dataChangedAt", "disposition"], ["currentDataRevision"], "
|
|
13251
|
+
const publication = record(value, "Ghostget cache publication");
|
|
13252
|
+
assertExactKeys(publication, ["key", "dataRevision", "validatedAt", "dataChangedAt", "disposition"], ["currentDataRevision"], "Ghostget cache publication");
|
|
13253
13253
|
const disposition = publication.disposition;
|
|
13254
13254
|
if (disposition !== "created" && disposition !== "changed" && disposition !== "unchanged" && disposition !== "superseded")
|
|
13255
|
-
throw new Error("
|
|
13255
|
+
throw new Error("Ghostget cache publication disposition is malformed");
|
|
13256
13256
|
if (disposition === "superseded" !== Object.hasOwn(publication, "currentDataRevision"))
|
|
13257
|
-
throw new Error("
|
|
13257
|
+
throw new Error("Ghostget cache publication current revision is malformed");
|
|
13258
13258
|
return Object.freeze({
|
|
13259
|
-
key: digest(publication.key, "
|
|
13260
|
-
dataRevision: digest(publication.dataRevision, "
|
|
13261
|
-
validatedAt: timestamp2(publication.validatedAt, "
|
|
13262
|
-
dataChangedAt: timestamp2(publication.dataChangedAt, "
|
|
13259
|
+
key: digest(publication.key, "Ghostget cache publication key"),
|
|
13260
|
+
dataRevision: digest(publication.dataRevision, "Ghostget cache publication data revision"),
|
|
13261
|
+
validatedAt: timestamp2(publication.validatedAt, "Ghostget cache publication validation time"),
|
|
13262
|
+
dataChangedAt: timestamp2(publication.dataChangedAt, "Ghostget cache publication data-change time"),
|
|
13263
13263
|
disposition,
|
|
13264
13264
|
...publication.currentDataRevision === undefined ? {} : {
|
|
13265
|
-
currentDataRevision: digest(publication.currentDataRevision, "
|
|
13265
|
+
currentDataRevision: digest(publication.currentDataRevision, "Ghostget current cache data revision")
|
|
13266
13266
|
}
|
|
13267
13267
|
});
|
|
13268
13268
|
}
|
|
13269
13269
|
function parseCacheOutcome(value) {
|
|
13270
|
-
const outcome = record(value, "
|
|
13270
|
+
const outcome = record(value, "Ghostget cache outcome");
|
|
13271
13271
|
if (outcome.status === "stored") {
|
|
13272
|
-
assertExactKeys(outcome, ["status", "publication"], [], "
|
|
13272
|
+
assertExactKeys(outcome, ["status", "publication"], [], "Ghostget cache outcome");
|
|
13273
13273
|
return Object.freeze({ status: "stored", publication: parsePublication(outcome.publication) });
|
|
13274
13274
|
}
|
|
13275
13275
|
if (outcome.status === "retained" && outcome.reason === "live-read-failed") {
|
|
13276
|
-
assertExactKeys(outcome, ["status", "reason"], [], "
|
|
13276
|
+
assertExactKeys(outcome, ["status", "reason"], [], "Ghostget cache outcome");
|
|
13277
13277
|
return Object.freeze({ status: "retained", reason: "live-read-failed" });
|
|
13278
13278
|
}
|
|
13279
13279
|
if (outcome.status === "miss" && outcome.reason === "no-cached-snapshot") {
|
|
13280
|
-
assertExactKeys(outcome, ["status", "reason"], [], "
|
|
13280
|
+
assertExactKeys(outcome, ["status", "reason"], [], "Ghostget cache outcome");
|
|
13281
13281
|
return Object.freeze({ status: "miss", reason: "no-cached-snapshot" });
|
|
13282
13282
|
}
|
|
13283
13283
|
if (outcome.status === "skipped" && outcome.reason === "auth-subject-unbound") {
|
|
13284
|
-
assertExactKeys(outcome, ["status", "reason"], [], "
|
|
13284
|
+
assertExactKeys(outcome, ["status", "reason"], [], "Ghostget cache outcome");
|
|
13285
13285
|
return Object.freeze({ status: "skipped", reason: outcome.reason });
|
|
13286
13286
|
}
|
|
13287
13287
|
if (outcome.status === "error") {
|
|
13288
|
-
assertExactKeys(outcome, ["status", "message"], [], "
|
|
13289
|
-
return Object.freeze({ status: "error", message: safeString(outcome.message, "
|
|
13288
|
+
assertExactKeys(outcome, ["status", "message"], [], "Ghostget cache outcome");
|
|
13289
|
+
return Object.freeze({ status: "error", message: safeString(outcome.message, "Ghostget cache error", MAX_ERROR_BYTES) });
|
|
13290
13290
|
}
|
|
13291
|
-
throw new Error("
|
|
13291
|
+
throw new Error("Ghostget cache outcome is malformed");
|
|
13292
13292
|
}
|
|
13293
13293
|
function parseReceiptStatus(value) {
|
|
13294
13294
|
if (value !== "succeeded" && value !== "failed") {
|
|
13295
|
-
throw new Error("
|
|
13295
|
+
throw new Error("Ghostget live receipt status is malformed");
|
|
13296
13296
|
}
|
|
13297
13297
|
return value;
|
|
13298
13298
|
}
|
|
@@ -13367,7 +13367,7 @@ function parseLocalCliToolIdentity(value) {
|
|
|
13367
13367
|
}
|
|
13368
13368
|
return parsed;
|
|
13369
13369
|
};
|
|
13370
|
-
const tool = strictRecord(value, "
|
|
13370
|
+
const tool = strictRecord(value, "Ghostget local CLI tool identity");
|
|
13371
13371
|
assertExactKeys(tool, [
|
|
13372
13372
|
"schemaVersion",
|
|
13373
13373
|
"id",
|
|
@@ -13380,58 +13380,58 @@ function parseLocalCliToolIdentity(value) {
|
|
|
13380
13380
|
"releaseCommit",
|
|
13381
13381
|
"releaseManifestSha256",
|
|
13382
13382
|
"releaseManifestUrl"
|
|
13383
|
-
], "
|
|
13384
|
-
const artifactValues = strictArray(tool.artifacts, "
|
|
13383
|
+
], "Ghostget local CLI tool identity");
|
|
13384
|
+
const artifactValues = strictArray(tool.artifacts, "Ghostget local CLI tool artifact table");
|
|
13385
13385
|
if (tool.schemaVersion !== 1) {
|
|
13386
|
-
throw new Error("
|
|
13386
|
+
throw new Error("Ghostget local CLI tool identity is malformed");
|
|
13387
13387
|
}
|
|
13388
13388
|
if (artifactValues.length < 1) {
|
|
13389
|
-
throw new Error("
|
|
13389
|
+
throw new Error("Ghostget local CLI tool artifact table is malformed");
|
|
13390
13390
|
}
|
|
13391
13391
|
const artifacts = artifactValues.map((artifactValue, index) => {
|
|
13392
|
-
const artifact = strictRecord(artifactValue, `
|
|
13393
|
-
assertExactKeys(artifact, ["platform", "arch", "executableSha256"], ["archiveSha256", "downloadUrl"], `
|
|
13394
|
-
const archiveSha256 = artifact.archiveSha256 === undefined ? undefined : digest(artifact.archiveSha256, `
|
|
13395
|
-
const downloadUrl = artifact.downloadUrl === undefined ? undefined : exactHttpsUrl(artifact.downloadUrl, `
|
|
13392
|
+
const artifact = strictRecord(artifactValue, `Ghostget local CLI tool artifact ${index}`);
|
|
13393
|
+
assertExactKeys(artifact, ["platform", "arch", "executableSha256"], ["archiveSha256", "downloadUrl"], `Ghostget local CLI tool artifact ${index}`);
|
|
13394
|
+
const archiveSha256 = artifact.archiveSha256 === undefined ? undefined : digest(artifact.archiveSha256, `Ghostget local CLI tool artifact ${index} archive hash`);
|
|
13395
|
+
const downloadUrl = artifact.downloadUrl === undefined ? undefined : exactHttpsUrl(artifact.downloadUrl, `Ghostget local CLI tool artifact ${index} download URL`);
|
|
13396
13396
|
if (archiveSha256 === undefined !== (downloadUrl === undefined)) {
|
|
13397
|
-
throw new Error("
|
|
13397
|
+
throw new Error("Ghostget local CLI tool artifact archive provenance is malformed");
|
|
13398
13398
|
}
|
|
13399
13399
|
return Object.freeze({
|
|
13400
|
-
platform: token(artifact.platform, `
|
|
13401
|
-
arch: token(artifact.arch, `
|
|
13402
|
-
executableSha256: digest(artifact.executableSha256, `
|
|
13400
|
+
platform: token(artifact.platform, `Ghostget local CLI tool artifact ${index} platform`),
|
|
13401
|
+
arch: token(artifact.arch, `Ghostget local CLI tool artifact ${index} architecture`),
|
|
13402
|
+
executableSha256: digest(artifact.executableSha256, `Ghostget local CLI tool artifact ${index} executable hash`),
|
|
13403
13403
|
...archiveSha256 === undefined ? {} : { archiveSha256 },
|
|
13404
13404
|
...downloadUrl === undefined ? {} : { downloadUrl }
|
|
13405
13405
|
});
|
|
13406
13406
|
});
|
|
13407
13407
|
const coordinates = artifacts.map((artifact) => `${artifact.platform}\x00${artifact.arch}`);
|
|
13408
13408
|
if (new Set(coordinates).size !== coordinates.length || coordinates.some((coordinate, index) => index > 0 && coordinates[index - 1] >= coordinate))
|
|
13409
|
-
throw new Error("
|
|
13410
|
-
const sourceUrl = tool.sourceUrl === undefined ? undefined : exactHttpsUrl(tool.sourceUrl, "
|
|
13411
|
-
const releaseManifestSha256 = tool.releaseManifestSha256 === undefined ? undefined : digest(tool.releaseManifestSha256, "
|
|
13412
|
-
const releaseManifestUrl = tool.releaseManifestUrl === undefined ? undefined : exactHttpsUrl(tool.releaseManifestUrl, "
|
|
13409
|
+
throw new Error("Ghostget local CLI tool artifact table is not canonical");
|
|
13410
|
+
const sourceUrl = tool.sourceUrl === undefined ? undefined : exactHttpsUrl(tool.sourceUrl, "Ghostget local CLI tool source URL");
|
|
13411
|
+
const releaseManifestSha256 = tool.releaseManifestSha256 === undefined ? undefined : digest(tool.releaseManifestSha256, "Ghostget local CLI tool release manifest hash");
|
|
13412
|
+
const releaseManifestUrl = tool.releaseManifestUrl === undefined ? undefined : exactHttpsUrl(tool.releaseManifestUrl, "Ghostget local CLI tool release manifest URL");
|
|
13413
13413
|
if (releaseManifestSha256 === undefined !== (releaseManifestUrl === undefined))
|
|
13414
|
-
throw new Error("
|
|
13414
|
+
throw new Error("Ghostget local CLI tool release manifest provenance is malformed");
|
|
13415
13415
|
if (tool.versionScheme !== "semver" && tool.versionScheme !== "opaque") {
|
|
13416
|
-
throw new Error("
|
|
13416
|
+
throw new Error("Ghostget local CLI tool version scheme is malformed");
|
|
13417
13417
|
}
|
|
13418
13418
|
if (typeof tool.version !== "string" || tool.version.length < 1 || tool.version.length > 128)
|
|
13419
|
-
throw new Error("
|
|
13419
|
+
throw new Error("Ghostget local CLI tool version is malformed");
|
|
13420
13420
|
const version = tool.version;
|
|
13421
13421
|
if (!wellFormedVisible(version) || tool.versionScheme === "semver" && !/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:(?:0|[1-9]\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.test(version)) {
|
|
13422
|
-
throw new Error("
|
|
13422
|
+
throw new Error("Ghostget local CLI tool version is malformed");
|
|
13423
13423
|
}
|
|
13424
13424
|
const hasReleaseCommit = tool.releaseCommit !== undefined;
|
|
13425
|
-
const releaseCommit = hasReleaseCommit ? safeString(tool.releaseCommit, "
|
|
13425
|
+
const releaseCommit = hasReleaseCommit ? safeString(tool.releaseCommit, "Ghostget local CLI tool release commit", 40) : undefined;
|
|
13426
13426
|
if (releaseCommit !== undefined && !/^[a-f0-9]{40}$/u.test(releaseCommit))
|
|
13427
|
-
throw new Error("
|
|
13428
|
-
const implementation = safeString(tool.implementation, "
|
|
13427
|
+
throw new Error("Ghostget local CLI tool release commit is malformed");
|
|
13428
|
+
const implementation = safeString(tool.implementation, "Ghostget local CLI tool implementation", 256);
|
|
13429
13429
|
if (!/^[A-Za-z0-9](?:[A-Za-z0-9._/+:-]{0,254}[A-Za-z0-9])?$/u.test(implementation)) {
|
|
13430
|
-
throw new Error("
|
|
13430
|
+
throw new Error("Ghostget local CLI tool implementation is malformed");
|
|
13431
13431
|
}
|
|
13432
13432
|
return Object.freeze({
|
|
13433
13433
|
schemaVersion: 1,
|
|
13434
|
-
id: token(tool.id, "
|
|
13434
|
+
id: token(tool.id, "Ghostget local CLI tool ID"),
|
|
13435
13435
|
implementation,
|
|
13436
13436
|
versionScheme: tool.versionScheme,
|
|
13437
13437
|
version,
|
|
@@ -13442,20 +13442,20 @@ function parseLocalCliToolIdentity(value) {
|
|
|
13442
13442
|
});
|
|
13443
13443
|
}
|
|
13444
13444
|
function parseLocalCliContractIdentity(value) {
|
|
13445
|
-
const identity = record(value, "
|
|
13446
|
-
assertExactKeys(identity, ["surface", "action", "version", "hash", "tool"], [], "
|
|
13447
|
-
const surface = providerSurfaceId(identity.surface, "
|
|
13448
|
-
const action = providerOperationName(identity.action, "
|
|
13445
|
+
const identity = record(value, "Ghostget local CLI contract identity");
|
|
13446
|
+
assertExactKeys(identity, ["surface", "action", "version", "hash", "tool"], [], "Ghostget local CLI contract identity");
|
|
13447
|
+
const surface = providerSurfaceId(identity.surface, "Ghostget local CLI surface");
|
|
13448
|
+
const action = providerOperationName(identity.action, "Ghostget local CLI action");
|
|
13449
13449
|
return Object.freeze({
|
|
13450
13450
|
surface,
|
|
13451
13451
|
action,
|
|
13452
|
-
version: safeInteger(identity.version, "
|
|
13453
|
-
hash: digest(identity.hash, "
|
|
13452
|
+
version: safeInteger(identity.version, "Ghostget local CLI contract version", 1, 1e6),
|
|
13453
|
+
hash: digest(identity.hash, "Ghostget local CLI contract hash"),
|
|
13454
13454
|
tool: parseLocalCliToolIdentity(identity.tool)
|
|
13455
13455
|
});
|
|
13456
13456
|
}
|
|
13457
13457
|
function parseLiveReceipt(value, request, expectedInputHash) {
|
|
13458
|
-
const receipt = record(value, "
|
|
13458
|
+
const receipt = record(value, "Ghostget live receipt");
|
|
13459
13459
|
const commonKeys = [
|
|
13460
13460
|
"schemaVersion",
|
|
13461
13461
|
"runId",
|
|
@@ -13475,66 +13475,66 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13475
13475
|
"error"
|
|
13476
13476
|
];
|
|
13477
13477
|
if (receipt.schemaVersion === 2 && receipt.transport === "browser") {
|
|
13478
|
-
assertExactKeys(receipt, commonKeys, [], "
|
|
13478
|
+
assertExactKeys(receipt, commonKeys, [], "Ghostget live receipt");
|
|
13479
13479
|
} else if (receipt.schemaVersion === 3 && receipt.transport === "provider-api") {
|
|
13480
|
-
assertExactKeys(receipt, [...commonKeys, "providerContractHash"], [], "
|
|
13480
|
+
assertExactKeys(receipt, [...commonKeys, "providerContractHash"], [], "Ghostget live receipt");
|
|
13481
13481
|
} else if (receipt.schemaVersion === 4 && receipt.transport === "web-session-api") {
|
|
13482
|
-
assertExactKeys(receipt, [...commonKeys, "webSessionContractHash"], [], "
|
|
13482
|
+
assertExactKeys(receipt, [...commonKeys, "webSessionContractHash"], [], "Ghostget live receipt");
|
|
13483
13483
|
} else if (receipt.schemaVersion === 5 && receipt.transport === "reviewed-template-api") {
|
|
13484
|
-
assertExactKeys(receipt, [...commonKeys, "reviewedTemplateContractHash"], [], "
|
|
13484
|
+
assertExactKeys(receipt, [...commonKeys, "reviewedTemplateContractHash"], [], "Ghostget live receipt");
|
|
13485
13485
|
} else if (receipt.schemaVersion === 6 && receipt.transport === "portable-provider-plugin") {
|
|
13486
|
-
assertExactKeys(receipt, [...commonKeys, "portablePluginContract"], [], "
|
|
13486
|
+
assertExactKeys(receipt, [...commonKeys, "portablePluginContract"], [], "Ghostget live receipt");
|
|
13487
13487
|
} else if (receipt.schemaVersion === 7 && receipt.transport === "local-cli") {
|
|
13488
|
-
assertExactKeys(receipt, [...commonKeys, "localCliContract"], [], "
|
|
13488
|
+
assertExactKeys(receipt, [...commonKeys, "localCliContract"], [], "Ghostget live receipt");
|
|
13489
13489
|
} else {
|
|
13490
|
-
throw new Error("
|
|
13491
|
-
}
|
|
13492
|
-
const adapter = record(receipt.adapter, "
|
|
13493
|
-
const auth = record(receipt.auth, "
|
|
13494
|
-
const dispatch = record(receipt.dispatch, "
|
|
13495
|
-
assertExactKeys(adapter, ["id", "version", "hash"], [], "
|
|
13496
|
-
assertExactKeys(auth, ["id", "hash", "kind"], [], "
|
|
13497
|
-
assertExactKeys(dispatch, ["planned", "started", "verified"], [], "
|
|
13490
|
+
throw new Error("Ghostget live receipt schema and transport are malformed");
|
|
13491
|
+
}
|
|
13492
|
+
const adapter = record(receipt.adapter, "Ghostget live receipt adapter");
|
|
13493
|
+
const auth = record(receipt.auth, "Ghostget live receipt auth");
|
|
13494
|
+
const dispatch = record(receipt.dispatch, "Ghostget live receipt dispatch");
|
|
13495
|
+
assertExactKeys(adapter, ["id", "version", "hash"], [], "Ghostget live receipt adapter");
|
|
13496
|
+
assertExactKeys(auth, ["id", "hash", "kind"], [], "Ghostget live receipt auth");
|
|
13497
|
+
assertExactKeys(dispatch, ["planned", "started", "verified"], [], "Ghostget live receipt dispatch");
|
|
13498
13498
|
if (receipt.risk !== "R1") {
|
|
13499
|
-
throw new Error("
|
|
13499
|
+
throw new Error("Ghostget live receipt risk is malformed");
|
|
13500
13500
|
}
|
|
13501
13501
|
const authKind = auth.kind;
|
|
13502
13502
|
if (authKind !== "browser-profile" && authKind !== "cookie-source" && authKind !== "cookies-file" && authKind !== "linked-device-store" && authKind !== "oauth-token-file" && authKind !== PUBLIC_WEB_SESSION_AUTHORITY_KIND)
|
|
13503
|
-
throw new Error("
|
|
13503
|
+
throw new Error("Ghostget live receipt auth kind is malformed");
|
|
13504
13504
|
if (receipt.dispatchStarted !== false) {
|
|
13505
|
-
throw new Error("
|
|
13505
|
+
throw new Error("Ghostget live receipt dispatch state is malformed");
|
|
13506
13506
|
}
|
|
13507
|
-
const planned = safeInteger(dispatch.planned, "
|
|
13508
|
-
const started = safeInteger(dispatch.started, "
|
|
13509
|
-
const verified = safeInteger(dispatch.verified, "
|
|
13507
|
+
const planned = safeInteger(dispatch.planned, "Ghostget live receipt planned dispatch count", 0, Number.MAX_SAFE_INTEGER);
|
|
13508
|
+
const started = safeInteger(dispatch.started, "Ghostget live receipt started dispatch count", 0, Number.MAX_SAFE_INTEGER);
|
|
13509
|
+
const verified = safeInteger(dispatch.verified, "Ghostget live receipt verified dispatch count", 0, Number.MAX_SAFE_INTEGER);
|
|
13510
13510
|
if (planned !== 0 || started !== 0 || verified !== 0) {
|
|
13511
|
-
throw new Error("
|
|
13511
|
+
throw new Error("Ghostget live receipt dispatch counts are inconsistent");
|
|
13512
13512
|
}
|
|
13513
13513
|
const status = parseReceiptStatus(receipt.status);
|
|
13514
|
-
const finalOrigin = receipt.finalOrigin === null ? null : safeString(receipt.finalOrigin, "
|
|
13515
|
-
const error = receipt.error === null ? null : boundedUtf8String(receipt.error, "
|
|
13514
|
+
const finalOrigin = receipt.finalOrigin === null ? null : safeString(receipt.finalOrigin, "Ghostget live receipt final origin", 4096);
|
|
13515
|
+
const error = receipt.error === null ? null : boundedUtf8String(receipt.error, "Ghostget live receipt error", MAX_RUN_RECEIPT_ERROR_BYTES);
|
|
13516
13516
|
if (receipt.planDigest !== null) {
|
|
13517
|
-
throw new Error("
|
|
13517
|
+
throw new Error("Ghostget live receipt plan digest is malformed");
|
|
13518
13518
|
}
|
|
13519
|
-
const startedAt = timestamp2(receipt.startedAt, "
|
|
13520
|
-
const finishedAt = timestamp2(receipt.finishedAt, "
|
|
13519
|
+
const startedAt = timestamp2(receipt.startedAt, "Ghostget live receipt start time");
|
|
13520
|
+
const finishedAt = timestamp2(receipt.finishedAt, "Ghostget live receipt finish time");
|
|
13521
13521
|
if (startedAt > finishedAt) {
|
|
13522
|
-
throw new Error("
|
|
13522
|
+
throw new Error("Ghostget live receipt finished before it started");
|
|
13523
13523
|
}
|
|
13524
13524
|
const common = Object.freeze({
|
|
13525
|
-
runId: safeString(receipt.runId, "
|
|
13525
|
+
runId: safeString(receipt.runId, "Ghostget live receipt run ID", 64),
|
|
13526
13526
|
planDigest: null,
|
|
13527
13527
|
adapter: Object.freeze({
|
|
13528
|
-
id: safeString(adapter.id, "
|
|
13529
|
-
version: safeString(adapter.version, "
|
|
13530
|
-
hash: digest(adapter.hash, "
|
|
13528
|
+
id: safeString(adapter.id, "Ghostget live receipt adapter ID", 64),
|
|
13529
|
+
version: safeString(adapter.version, "Ghostget live receipt adapter version", 64),
|
|
13530
|
+
hash: digest(adapter.hash, "Ghostget live receipt adapter hash")
|
|
13531
13531
|
}),
|
|
13532
|
-
operation: providerOperationName(receipt.operation, "
|
|
13532
|
+
operation: providerOperationName(receipt.operation, "Ghostget live receipt operation"),
|
|
13533
13533
|
risk: "R1",
|
|
13534
|
-
inputHash: digest(receipt.inputHash, "
|
|
13534
|
+
inputHash: digest(receipt.inputHash, "Ghostget live receipt input hash"),
|
|
13535
13535
|
auth: Object.freeze({
|
|
13536
|
-
id: safeString(auth.id, "
|
|
13537
|
-
hash: digest(auth.hash, "
|
|
13536
|
+
id: safeString(auth.id, "Ghostget live receipt auth ID", 64),
|
|
13537
|
+
hash: digest(auth.hash, "Ghostget live receipt auth hash"),
|
|
13538
13538
|
kind: authKind
|
|
13539
13539
|
}),
|
|
13540
13540
|
status,
|
|
@@ -13550,18 +13550,18 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13550
13550
|
error
|
|
13551
13551
|
});
|
|
13552
13552
|
if (common.adapter.id !== request.adapterId || common.operation !== request.operationId)
|
|
13553
|
-
throw new Error("
|
|
13553
|
+
throw new Error("Ghostget live receipt route does not match its request");
|
|
13554
13554
|
if (common.auth.id !== expectedRequestAuthId(request, common.auth.kind)) {
|
|
13555
|
-
throw new Error("
|
|
13555
|
+
throw new Error("Ghostget live receipt auth does not match its request");
|
|
13556
13556
|
}
|
|
13557
13557
|
if (common.auth.kind === PUBLIC_WEB_SESSION_AUTHORITY_KIND) {
|
|
13558
13558
|
const authority = publicWebSessionAuthority(request);
|
|
13559
13559
|
if (receipt.schemaVersion !== 4 || receipt.transport !== "web-session-api" || common.auth.hash !== sha2563(canonicalJson2(authority))) {
|
|
13560
|
-
throw new Error("
|
|
13560
|
+
throw new Error("Ghostget live receipt public authority is malformed");
|
|
13561
13561
|
}
|
|
13562
13562
|
}
|
|
13563
13563
|
if (common.inputHash !== expectedInputHash) {
|
|
13564
|
-
throw new Error("
|
|
13564
|
+
throw new Error("Ghostget live receipt input does not match its request");
|
|
13565
13565
|
}
|
|
13566
13566
|
if (receipt.schemaVersion === 2 && receipt.transport === "browser") {
|
|
13567
13567
|
return Object.freeze({ ...common, schemaVersion: 2, transport: "browser" });
|
|
@@ -13571,7 +13571,7 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13571
13571
|
...common,
|
|
13572
13572
|
schemaVersion: 3,
|
|
13573
13573
|
transport: "provider-api",
|
|
13574
|
-
providerContractHash: digest(receipt.providerContractHash, "
|
|
13574
|
+
providerContractHash: digest(receipt.providerContractHash, "Ghostget live receipt provider contract hash")
|
|
13575
13575
|
});
|
|
13576
13576
|
}
|
|
13577
13577
|
if (receipt.schemaVersion === 4 && receipt.transport === "web-session-api") {
|
|
@@ -13579,7 +13579,7 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13579
13579
|
...common,
|
|
13580
13580
|
schemaVersion: 4,
|
|
13581
13581
|
transport: "web-session-api",
|
|
13582
|
-
webSessionContractHash: digest(receipt.webSessionContractHash, "
|
|
13582
|
+
webSessionContractHash: digest(receipt.webSessionContractHash, "Ghostget live receipt web-session contract hash")
|
|
13583
13583
|
});
|
|
13584
13584
|
}
|
|
13585
13585
|
if (receipt.schemaVersion === 5 && receipt.transport === "reviewed-template-api") {
|
|
@@ -13587,13 +13587,13 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13587
13587
|
...common,
|
|
13588
13588
|
schemaVersion: 5,
|
|
13589
13589
|
transport: "reviewed-template-api",
|
|
13590
|
-
reviewedTemplateContractHash: digest(receipt.reviewedTemplateContractHash, "
|
|
13590
|
+
reviewedTemplateContractHash: digest(receipt.reviewedTemplateContractHash, "Ghostget live receipt reviewed-template contract hash")
|
|
13591
13591
|
});
|
|
13592
13592
|
}
|
|
13593
13593
|
if (receipt.schemaVersion === 6 && receipt.transport === "portable-provider-plugin") {
|
|
13594
13594
|
const portablePluginContract = parsePortableOperationIdentity(receipt.portablePluginContract);
|
|
13595
13595
|
if (portablePluginContract.adapterId !== common.adapter.id || portablePluginContract.operation !== common.operation) {
|
|
13596
|
-
throw new Error("
|
|
13596
|
+
throw new Error("Ghostget live portable contract route is malformed");
|
|
13597
13597
|
}
|
|
13598
13598
|
return Object.freeze({
|
|
13599
13599
|
...common,
|
|
@@ -13605,7 +13605,7 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13605
13605
|
if (receipt.schemaVersion === 7 && receipt.transport === "local-cli") {
|
|
13606
13606
|
const localCliContract = parseLocalCliContractIdentity(receipt.localCliContract);
|
|
13607
13607
|
if (localCliContract.action !== common.operation) {
|
|
13608
|
-
throw new Error("
|
|
13608
|
+
throw new Error("Ghostget live local CLI contract route is malformed");
|
|
13609
13609
|
}
|
|
13610
13610
|
return Object.freeze({
|
|
13611
13611
|
...common,
|
|
@@ -13614,30 +13614,30 @@ function parseLiveReceipt(value, request, expectedInputHash) {
|
|
|
13614
13614
|
localCliContract
|
|
13615
13615
|
});
|
|
13616
13616
|
}
|
|
13617
|
-
throw new Error("
|
|
13617
|
+
throw new Error("Ghostget live receipt schema and transport are malformed");
|
|
13618
13618
|
}
|
|
13619
13619
|
function parseLiveResult(value, request, expectedInputHash) {
|
|
13620
|
-
assertExactKeys(value, ["ok", "source", "status", "runId", "replayed", "receipt", "output", "cache"], ["readFailure"], "
|
|
13620
|
+
assertExactKeys(value, ["ok", "source", "status", "runId", "replayed", "receipt", "output", "cache"], ["readFailure"], "Ghostget live response");
|
|
13621
13621
|
if (value.source !== "live")
|
|
13622
|
-
throw new Error("
|
|
13622
|
+
throw new Error("Ghostget live response has the wrong source");
|
|
13623
13623
|
const receipt = parseLiveReceipt(value.receipt, request, expectedInputHash);
|
|
13624
|
-
const status = safeString(value.status, "
|
|
13625
|
-
const responseRunId = safeString(value.runId, "
|
|
13624
|
+
const status = safeString(value.status, "Ghostget live status", 32);
|
|
13625
|
+
const responseRunId = safeString(value.runId, "Ghostget live run ID", 64);
|
|
13626
13626
|
const expectedOk = receipt.status === "succeeded";
|
|
13627
13627
|
if (status !== receipt.status || receipt.runId !== responseRunId || value.ok !== expectedOk) {
|
|
13628
|
-
throw new Error("
|
|
13628
|
+
throw new Error("Ghostget live response is not bound to its receipt");
|
|
13629
13629
|
}
|
|
13630
13630
|
if (typeof value.replayed !== "boolean" || !("output" in value)) {
|
|
13631
|
-
throw new Error("
|
|
13631
|
+
throw new Error("Ghostget live response is incomplete");
|
|
13632
13632
|
}
|
|
13633
13633
|
const cache = parseCacheOutcome(value.cache);
|
|
13634
13634
|
const cacheMatchesReceipt = receipt.status === "succeeded" ? cache.status === "stored" || cache.status === "error" || cache.status === "skipped" : cache.status === "retained" || cache.status === "miss" || cache.status === "error" || cache.status === "skipped";
|
|
13635
13635
|
if (!cacheMatchesReceipt) {
|
|
13636
|
-
throw new Error("
|
|
13636
|
+
throw new Error("Ghostget live cache outcome is inconsistent with its receipt");
|
|
13637
13637
|
}
|
|
13638
13638
|
const live = receipt.status === "failed" ? (() => {
|
|
13639
13639
|
if (value.output !== null) {
|
|
13640
|
-
throw new Error("
|
|
13640
|
+
throw new Error("Ghostget failed live response retained an output");
|
|
13641
13641
|
}
|
|
13642
13642
|
return Object.freeze({
|
|
13643
13643
|
status: "failed",
|
|
@@ -13648,7 +13648,7 @@ function parseLiveResult(value, request, expectedInputHash) {
|
|
|
13648
13648
|
});
|
|
13649
13649
|
})() : (() => {
|
|
13650
13650
|
if (value.readFailure !== undefined) {
|
|
13651
|
-
throw new Error("
|
|
13651
|
+
throw new Error("Ghostget successful live response included a read failure");
|
|
13652
13652
|
}
|
|
13653
13653
|
return Object.freeze({
|
|
13654
13654
|
status: "succeeded",
|
|
@@ -13665,22 +13665,22 @@ function parseLiveResult(value, request, expectedInputHash) {
|
|
|
13665
13665
|
function assertLiveInvocationFences(request, options, executionIdentityBefore, identityBefore, parsed, activity) {
|
|
13666
13666
|
const identityAfter = observeProjectionIdentity(request, options);
|
|
13667
13667
|
if (!projectionIdentitiesMatch(identityBefore, identityAfter)) {
|
|
13668
|
-
throw new Error(`
|
|
13668
|
+
throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
|
|
13669
13669
|
}
|
|
13670
13670
|
if (!executionIdentitiesMatch(executionIdentityBefore, receiptExecutionIdentity(parsed.live.receipt))) {
|
|
13671
|
-
throw new Error(`
|
|
13671
|
+
throw new Error(`Ghostget execution identity changed while ${activity} was running; the live result was discarded`);
|
|
13672
13672
|
}
|
|
13673
13673
|
if (parsed.live.receipt.auth.hash !== identityBefore.authHash) {
|
|
13674
|
-
throw new Error(`
|
|
13674
|
+
throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
|
|
13675
13675
|
}
|
|
13676
13676
|
if (identityBefore.status === "unbound") {
|
|
13677
13677
|
if (parsed.cache.status !== "skipped") {
|
|
13678
|
-
throw new Error(`
|
|
13678
|
+
throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
|
|
13679
13679
|
}
|
|
13680
13680
|
return;
|
|
13681
13681
|
}
|
|
13682
13682
|
if (parsed.cache.status === "skipped" || parsed.cache.status === "stored" && parsed.cache.publication.key !== identityBefore.key) {
|
|
13683
|
-
throw new Error(`
|
|
13683
|
+
throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
|
|
13684
13684
|
}
|
|
13685
13685
|
}
|
|
13686
13686
|
function invokeCapabilitySync(request, options = {}) {
|
|
@@ -13697,10 +13697,10 @@ function invokeCapabilitySync(request, options = {}) {
|
|
|
13697
13697
|
return parsed.live;
|
|
13698
13698
|
}
|
|
13699
13699
|
|
|
13700
|
-
// node_modules/@hraness/
|
|
13701
|
-
var
|
|
13700
|
+
// node_modules/@hraness/ghostget/dist/index-471pfpgn.js
|
|
13701
|
+
var GHOSTGET_VERSION = "0.17.1";
|
|
13702
13702
|
|
|
13703
|
-
// node_modules/@hraness/
|
|
13703
|
+
// node_modules/@hraness/ghostget/dist/beeper-client.js
|
|
13704
13704
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
13705
13705
|
import { existsSync as existsSync4 } from "fs";
|
|
13706
13706
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -13735,7 +13735,7 @@ var LOCAL_MESSAGE_BUNDLE_V1_ARTIFACTS = Object.freeze([
|
|
|
13735
13735
|
Object.freeze({ path: "tombstones.ndjson", kind: "tombstone" })
|
|
13736
13736
|
]);
|
|
13737
13737
|
|
|
13738
|
-
// node_modules/@hraness/
|
|
13738
|
+
// node_modules/@hraness/ghostget/dist/beeper-client.js
|
|
13739
13739
|
import { types as nodeTypes4 } from "util";
|
|
13740
13740
|
var wrench_web_adapter_default = {
|
|
13741
13741
|
schemaVersion: 6,
|
|
@@ -17622,8 +17622,8 @@ var BEEPER_CONTACT_INTERACTION_TRANSFORM = Object.freeze({
|
|
|
17622
17622
|
});
|
|
17623
17623
|
var BEEPER_CONTACT_INTERACTION_IMPLEMENTATION = Object.freeze({
|
|
17624
17624
|
producer: Object.freeze({
|
|
17625
|
-
package: "@hraness/
|
|
17626
|
-
version:
|
|
17625
|
+
package: "@hraness/ghostget",
|
|
17626
|
+
version: GHOSTGET_VERSION
|
|
17627
17627
|
}),
|
|
17628
17628
|
officialCli: Object.freeze({
|
|
17629
17629
|
implementation: BEEPER_CLI_PIN.implementation,
|
|
@@ -18144,7 +18144,7 @@ function parseBeeperContactInteractionExportResult(value) {
|
|
|
18144
18144
|
var MAX_STDERR_BYTES = 8 * 1024;
|
|
18145
18145
|
var PROCESS_TIMEOUT_MS = 6 * 60 * 60 * 1000 + 60000;
|
|
18146
18146
|
function fail22(message) {
|
|
18147
|
-
throw new Error(`
|
|
18147
|
+
throw new Error(`Ghostget Beeper client: ${message}`);
|
|
18148
18148
|
}
|
|
18149
18149
|
function cliSourcePath2() {
|
|
18150
18150
|
const besideSource = fileURLToPath3(new URL("./cli.ts", import.meta.url));
|
|
@@ -18153,11 +18153,11 @@ function cliSourcePath2() {
|
|
|
18153
18153
|
const packagedSource = fileURLToPath3(new URL("../src/cli.ts", import.meta.url));
|
|
18154
18154
|
if (existsSync4(packagedSource))
|
|
18155
18155
|
return packagedSource;
|
|
18156
|
-
return fail22("the installed
|
|
18156
|
+
return fail22("the installed Ghostget CLI source is unavailable");
|
|
18157
18157
|
}
|
|
18158
18158
|
function requireBunRuntime2() {
|
|
18159
18159
|
if (typeof process.versions.bun !== "string") {
|
|
18160
|
-
fail22("@hraness/
|
|
18160
|
+
fail22("@hraness/ghostget/beeper requires Bun to run the installed Ghostget CLI");
|
|
18161
18161
|
}
|
|
18162
18162
|
}
|
|
18163
18163
|
function plainDataObject(value, label) {
|
|
@@ -18391,7 +18391,7 @@ function recordSourceExecutionReceipt(database, input) {
|
|
|
18391
18391
|
return { id: Number(inserted.lastInsertRowid), replayed: false };
|
|
18392
18392
|
}
|
|
18393
18393
|
|
|
18394
|
-
// src/local/
|
|
18394
|
+
// src/local/ghostget-adapter.ts
|
|
18395
18395
|
var DIGEST3 = /^[a-f0-9]{64}$/u;
|
|
18396
18396
|
var RUN_ID = /^(?:[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}|[a-z][a-z0-9._+-]{0,127})$/u;
|
|
18397
18397
|
function contractSha256(receipt) {
|
|
@@ -18419,41 +18419,41 @@ function canonicalTimestamp(value, label) {
|
|
|
18419
18419
|
}
|
|
18420
18420
|
function boundedRunId(value) {
|
|
18421
18421
|
if (!RUN_ID.test(value))
|
|
18422
|
-
throw new Error("
|
|
18422
|
+
throw new Error("Ghostget run ID is invalid");
|
|
18423
18423
|
return value;
|
|
18424
18424
|
}
|
|
18425
|
-
function
|
|
18425
|
+
function validatePeopleBladeGhostgetInvocation(result, request, policy) {
|
|
18426
18426
|
const receipt = result.receipt;
|
|
18427
18427
|
if (result.replayed || receipt.status !== "succeeded" || receipt.error !== null || receipt.planDigest !== null || receipt.risk !== "R1" || receipt.dispatchStarted || receipt.dispatch.planned !== 0 || receipt.dispatch.started !== 0 || receipt.dispatch.verified !== 0)
|
|
18428
|
-
throw new Error("
|
|
18428
|
+
throw new Error("Ghostget invocation crossed PeopleBlade's read-only execution boundary");
|
|
18429
18429
|
if (receipt.adapter.id !== request.adapterId || receipt.adapter.version !== policy.adapterVersion || receipt.operation !== request.operationId || receipt.auth.id !== request.authId || receipt.auth.kind !== policy.authKind || receipt.transport !== policy.transport || receipt.finalOrigin !== policy.finalOrigin)
|
|
18430
|
-
throw new Error("
|
|
18430
|
+
throw new Error("Ghostget invocation route identity drifted");
|
|
18431
18431
|
if (receipt.transport === "local-cli") {
|
|
18432
18432
|
const expected = policy.localCli;
|
|
18433
18433
|
const actual = receipt.localCliContract;
|
|
18434
18434
|
if (expected === undefined || actual.surface !== expected.surface || actual.action !== expected.action || actual.version !== expected.version || actual.tool.id !== expected.toolId || actual.tool.implementation !== expected.toolImplementation || actual.tool.versionScheme !== "semver" || actual.tool.version !== expected.toolVersion || actual.tool.releaseCommit !== expected.toolCommit || actual.tool.releaseManifestSha256 !== expected.toolReleaseManifestSha256)
|
|
18435
|
-
throw new Error("
|
|
18435
|
+
throw new Error("Ghostget local CLI contract identity drifted");
|
|
18436
18436
|
} else if (policy.localCli !== undefined) {
|
|
18437
|
-
throw new Error("
|
|
18437
|
+
throw new Error("Ghostget invocation did not use the required local CLI route");
|
|
18438
18438
|
}
|
|
18439
18439
|
boundedRunId(receipt.runId);
|
|
18440
18440
|
const expectedInput = sha256(canonicalJson(request.input));
|
|
18441
18441
|
if (receipt.inputHash !== expectedInput || !DIGEST3.test(receipt.inputHash)) {
|
|
18442
|
-
throw new Error("
|
|
18442
|
+
throw new Error("Ghostget receipt does not bind the exact input");
|
|
18443
18443
|
}
|
|
18444
18444
|
if (!DIGEST3.test(receipt.adapter.hash))
|
|
18445
|
-
throw new Error("
|
|
18445
|
+
throw new Error("Ghostget adapter identity is invalid");
|
|
18446
18446
|
if (policy.adapterSha256 !== undefined && receipt.adapter.hash !== policy.adapterSha256) {
|
|
18447
|
-
throw new Error("
|
|
18447
|
+
throw new Error("Ghostget adapter implementation drifted");
|
|
18448
18448
|
}
|
|
18449
18449
|
const contract = contractSha256(receipt);
|
|
18450
18450
|
if (contract !== policy.contractSha256 || !DIGEST3.test(policy.contractSha256)) {
|
|
18451
|
-
throw new Error("
|
|
18451
|
+
throw new Error("Ghostget operation contract identity drifted");
|
|
18452
18452
|
}
|
|
18453
|
-
const startedAt = canonicalTimestamp(receipt.startedAt, "
|
|
18454
|
-
const finishedAt = canonicalTimestamp(receipt.finishedAt, "
|
|
18453
|
+
const startedAt = canonicalTimestamp(receipt.startedAt, "Ghostget start");
|
|
18454
|
+
const finishedAt = canonicalTimestamp(receipt.finishedAt, "Ghostget finish");
|
|
18455
18455
|
if (finishedAt < startedAt)
|
|
18456
|
-
throw new Error("
|
|
18456
|
+
throw new Error("Ghostget receipt timing is invalid");
|
|
18457
18457
|
return {
|
|
18458
18458
|
output: result.output,
|
|
18459
18459
|
execution: {
|
|
@@ -18470,13 +18470,13 @@ function validatePeopleBladeWrenchInvocation(result, request, policy) {
|
|
|
18470
18470
|
}
|
|
18471
18471
|
};
|
|
18472
18472
|
}
|
|
18473
|
-
function
|
|
18473
|
+
function callPeopleBladeGhostget(request, invoke = invokeCapabilitySync) {
|
|
18474
18474
|
return invoke(request);
|
|
18475
18475
|
}
|
|
18476
18476
|
function callPeopleBladeBeeperContactInteractions(request, exportInteractions = exportBeeperContactInteractionsSync) {
|
|
18477
18477
|
return parseBeeperContactInteractionExportResult(exportInteractions(request));
|
|
18478
18478
|
}
|
|
18479
|
-
function
|
|
18479
|
+
function ledgerPeopleBladeGhostgetInvocation(database, input) {
|
|
18480
18480
|
const { receipt } = input.execution;
|
|
18481
18481
|
return recordSourceExecutionReceipt(database, {
|
|
18482
18482
|
provider: input.provider,
|
|
@@ -18542,21 +18542,21 @@ function canonicalTimestamp2(value, label) {
|
|
|
18542
18542
|
function readBeeperContactInteractions(request, exportInteractions) {
|
|
18543
18543
|
const result = callPeopleBladeBeeperContactInteractions(request, exportInteractions);
|
|
18544
18544
|
if (result.receipt.auth.id !== request.authId || result.receipt.auth.kind !== "linked-device-store" || result.receipt.auth.provider !== "beeper" || result.receipt.operation !== "beeper.export-contact-interactions" || result.receipt.status !== "succeeded" || result.receipt.transport !== "linked-device")
|
|
18545
|
-
throw new Error("
|
|
18545
|
+
throw new Error("Ghostget Beeper interaction export route identity drifted");
|
|
18546
18546
|
const expectedBounds = {
|
|
18547
18547
|
limitChats: request.limitChats ?? null,
|
|
18548
18548
|
limitMessages: request.limitMessages ?? null,
|
|
18549
18549
|
maxParticipants: request.maxParticipants ?? null
|
|
18550
18550
|
};
|
|
18551
18551
|
if (canonicalJson(result.receipt.bounds) !== canonicalJson(expectedBounds)) {
|
|
18552
|
-
throw new Error("
|
|
18552
|
+
throw new Error("Ghostget Beeper interaction export did not bind the requested bounds");
|
|
18553
18553
|
}
|
|
18554
18554
|
if (result.receipt.output.summarySha256 !== result.output.integrity.summarySha256 || !DIGEST4.test(result.receipt.integrity.receiptSha256) || !DIGEST4.test(result.receipt.auth.identitySha256))
|
|
18555
|
-
throw new Error("
|
|
18555
|
+
throw new Error("Ghostget Beeper interaction export integrity drifted");
|
|
18556
18556
|
canonicalTimestamp2(result.receipt.startedAt, "Beeper interaction export start");
|
|
18557
18557
|
canonicalTimestamp2(result.receipt.finishedAt, "Beeper interaction export finish");
|
|
18558
18558
|
if (result.receipt.finishedAt < result.receipt.startedAt) {
|
|
18559
|
-
throw new Error("
|
|
18559
|
+
throw new Error("Ghostget Beeper interaction export timing is invalid");
|
|
18560
18560
|
}
|
|
18561
18561
|
return result;
|
|
18562
18562
|
}
|
|
@@ -18681,10 +18681,10 @@ function projectBeeperContactInteractions(summary2, coordinates) {
|
|
|
18681
18681
|
}
|
|
18682
18682
|
|
|
18683
18683
|
// src/local/providers/beeper-compatibility.ts
|
|
18684
|
-
var
|
|
18685
|
-
|
|
18686
|
-
version: "0.
|
|
18687
|
-
commit: "
|
|
18684
|
+
var BEEPER_GHOSTGET_COMPATIBILITY = Object.freeze({
|
|
18685
|
+
ghostget: Object.freeze({
|
|
18686
|
+
version: "0.17.1",
|
|
18687
|
+
commit: "b74ae2ac594bcf07c3def71dc4bb2e5a98c826dd"
|
|
18688
18688
|
}),
|
|
18689
18689
|
adapter: Object.freeze({
|
|
18690
18690
|
id: "beeper-local",
|
|
@@ -18721,6 +18721,22 @@ var BEEPER_WRENCH_COMPATIBILITY = Object.freeze({
|
|
|
18721
18721
|
commit: "b9c1714410139c2139b597338cd002d785653e85"
|
|
18722
18722
|
})
|
|
18723
18723
|
});
|
|
18724
|
+
var PREVIOUS_WRENCH_0168_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
|
|
18725
|
+
transport: "local-cli",
|
|
18726
|
+
wrenchVersion: "0.16.8",
|
|
18727
|
+
wrenchCommit: "b0cf2ecbc1113fcc8ef673a824be475c3d7bbb46",
|
|
18728
|
+
adapterId: "beeper-local",
|
|
18729
|
+
adapterVersion: "2.4.0",
|
|
18730
|
+
adapterSha256: "2714af7e821b799c1d0b57106e8e193cb9787e5a6da37e1269f4aae0710a4ddc",
|
|
18731
|
+
cliId: "beeper-cli",
|
|
18732
|
+
cliVersion: "0.6.2",
|
|
18733
|
+
cliCommit: "a416af06023449a87312dc11e54643fd9dc94b8c",
|
|
18734
|
+
contracts: Object.freeze({
|
|
18735
|
+
contactsList: "8048565547c2a09078528d0a35f7a0c3a2e8850b17b075dc572e8b59115fcb57",
|
|
18736
|
+
contactsSearch: "e57cdcc9012ed5fb8f956e16a2368e95adf0a6b8bb404f903e64df85061b1ca1",
|
|
18737
|
+
messagingSearch: "2fc54d139a54d19c31a82237e4b417994e12679db3da5fd71ec9265e3622b0bf"
|
|
18738
|
+
})
|
|
18739
|
+
});
|
|
18724
18740
|
var PEOPLEBLADE_010_WRENCH_0150_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
|
|
18725
18741
|
transport: "local-cli",
|
|
18726
18742
|
wrenchVersion: "0.15.0",
|
|
@@ -18818,15 +18834,15 @@ var BEEPER_INTERACTION_EXPORT_COMPATIBILITY = Object.freeze({
|
|
|
18818
18834
|
sourceVersion: "1.1.0",
|
|
18819
18835
|
transformId: "beeper-direct-contact-interactions",
|
|
18820
18836
|
transformVersion: 1,
|
|
18821
|
-
wrenchVersion:
|
|
18837
|
+
wrenchVersion: BEEPER_GHOSTGET_COMPATIBILITY.ghostget.version,
|
|
18822
18838
|
platform: "darwin-arm64"
|
|
18823
18839
|
});
|
|
18824
18840
|
function beeperSourceBindingMetadata() {
|
|
18825
|
-
const compatibility =
|
|
18841
|
+
const compatibility = BEEPER_GHOSTGET_COMPATIBILITY;
|
|
18826
18842
|
return Object.freeze({
|
|
18827
18843
|
transport: compatibility.adapter.transport,
|
|
18828
|
-
wrenchVersion: compatibility.
|
|
18829
|
-
wrenchCommit: compatibility.
|
|
18844
|
+
wrenchVersion: compatibility.ghostget.version,
|
|
18845
|
+
wrenchCommit: compatibility.ghostget.commit,
|
|
18830
18846
|
adapterId: compatibility.adapter.id,
|
|
18831
18847
|
adapterVersion: compatibility.adapter.version,
|
|
18832
18848
|
adapterSha256: compatibility.adapter.sha256,
|
|
@@ -18844,11 +18860,11 @@ function beeperSourceBindingMetadata() {
|
|
|
18844
18860
|
// src/local/providers/beeper.ts
|
|
18845
18861
|
var PROVIDER4 = "beeper";
|
|
18846
18862
|
var MODE3 = "wrench-contacts-v1";
|
|
18847
|
-
var ADAPTER_ID =
|
|
18848
|
-
var ADAPTER_VERSION =
|
|
18849
|
-
var ADAPTER_SHA256 =
|
|
18850
|
-
var CONTRACT_SHA256 =
|
|
18851
|
-
var FINAL_ORIGIN =
|
|
18863
|
+
var ADAPTER_ID = BEEPER_GHOSTGET_COMPATIBILITY.adapter.id;
|
|
18864
|
+
var ADAPTER_VERSION = BEEPER_GHOSTGET_COMPATIBILITY.adapter.version;
|
|
18865
|
+
var ADAPTER_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.sha256;
|
|
18866
|
+
var CONTRACT_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.list"].sha256;
|
|
18867
|
+
var FINAL_ORIGIN = BEEPER_GHOSTGET_COMPATIBILITY.adapter.origin;
|
|
18852
18868
|
var MAX_ACCOUNTS = 128;
|
|
18853
18869
|
var MAX_CONTACTS2 = 200;
|
|
18854
18870
|
var SUBJECT = /^beeper:local:[a-f0-9]{64}$/u;
|
|
@@ -19011,22 +19027,22 @@ function parseContact(value, label) {
|
|
|
19011
19027
|
}
|
|
19012
19028
|
function parseBeeperContactPage(value, input, authId) {
|
|
19013
19029
|
const request = { adapterId: ADAPTER_ID, operationId: "contacts.list", authId, input };
|
|
19014
|
-
const validated =
|
|
19030
|
+
const validated = validatePeopleBladeGhostgetInvocation(value, request, {
|
|
19015
19031
|
adapterVersion: ADAPTER_VERSION,
|
|
19016
19032
|
adapterSha256: ADAPTER_SHA256,
|
|
19017
19033
|
authKind: "linked-device-store",
|
|
19018
|
-
transport:
|
|
19034
|
+
transport: BEEPER_GHOSTGET_COMPATIBILITY.adapter.transport,
|
|
19019
19035
|
contractSha256: CONTRACT_SHA256,
|
|
19020
19036
|
finalOrigin: FINAL_ORIGIN,
|
|
19021
19037
|
localCli: {
|
|
19022
|
-
surface:
|
|
19038
|
+
surface: BEEPER_GHOSTGET_COMPATIBILITY.adapter.surface,
|
|
19023
19039
|
action: "contacts.list",
|
|
19024
|
-
version:
|
|
19025
|
-
toolId:
|
|
19026
|
-
toolImplementation:
|
|
19027
|
-
toolVersion:
|
|
19028
|
-
toolCommit:
|
|
19029
|
-
toolReleaseManifestSha256:
|
|
19040
|
+
version: BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.list"].version,
|
|
19041
|
+
toolId: BEEPER_GHOSTGET_COMPATIBILITY.cli.id,
|
|
19042
|
+
toolImplementation: BEEPER_GHOSTGET_COMPATIBILITY.cli.implementation,
|
|
19043
|
+
toolVersion: BEEPER_GHOSTGET_COMPATIBILITY.cli.version,
|
|
19044
|
+
toolCommit: BEEPER_GHOSTGET_COMPATIBILITY.cli.commit,
|
|
19045
|
+
toolReleaseManifestSha256: BEEPER_GHOSTGET_COMPATIBILITY.cli.releaseManifestSha256
|
|
19030
19046
|
}
|
|
19031
19047
|
});
|
|
19032
19048
|
const execution = validated.execution;
|
|
@@ -19044,7 +19060,7 @@ function parseBeeperContactPage(value, input, authId) {
|
|
|
19044
19060
|
"continuation"
|
|
19045
19061
|
], "Beeper contact output");
|
|
19046
19062
|
if (output.provider !== "beeper" || output.operation !== "contacts.list" || output.projection !== "bounded-local-desktop-api" || output.query !== null) {
|
|
19047
|
-
throw new Error("
|
|
19063
|
+
throw new Error("Ghostget Beeper output changed projection semantics");
|
|
19048
19064
|
}
|
|
19049
19065
|
const accountSubject = text2(output.accountSubject, "Beeper account subject", 128);
|
|
19050
19066
|
if (!SUBJECT.test(accountSubject))
|
|
@@ -19198,7 +19214,7 @@ function sameExecution(left, right) {
|
|
|
19198
19214
|
return left.authId === right.authId && left.authSha256 === right.authSha256 && left.adapterSha256 === right.adapterSha256 && left.contractSha256 === right.contractSha256;
|
|
19199
19215
|
}
|
|
19200
19216
|
function ledgerBeeperContactRead(database, account, page) {
|
|
19201
|
-
|
|
19217
|
+
ledgerPeopleBladeGhostgetInvocation(database, {
|
|
19202
19218
|
provider: PROVIDER4,
|
|
19203
19219
|
accountKey: account,
|
|
19204
19220
|
capability: "contacts",
|
|
@@ -19273,8 +19289,11 @@ function classifyReviewedBeeperPredecessor(value, currentMetadata) {
|
|
|
19273
19289
|
if (encoded === canonicalJson(PREVIOUS_WRENCH_0167_BEEPER_SOURCE_BINDING_METADATA)) {
|
|
19274
19290
|
return "wrench-0.16.7-beeper-2.4";
|
|
19275
19291
|
}
|
|
19276
|
-
if (encoded ===
|
|
19292
|
+
if (encoded === canonicalJson(PREVIOUS_WRENCH_0168_BEEPER_SOURCE_BINDING_METADATA)) {
|
|
19277
19293
|
return "wrench-0.16.8-beeper-2.4";
|
|
19294
|
+
}
|
|
19295
|
+
if (encoded === currentMetadata)
|
|
19296
|
+
return "ghostget-0.17.1-beeper-2.4";
|
|
19278
19297
|
return null;
|
|
19279
19298
|
}
|
|
19280
19299
|
function assertStoredRealmInventory(database, sourceBindingId, accounts, storedSha256) {
|
|
@@ -19322,7 +19341,7 @@ function rebindBeeperSource(database, options = {}) {
|
|
|
19322
19341
|
if (!AUTH_ID.test(authId))
|
|
19323
19342
|
throw new Error("Beeper auth ID must be lowercase kebab text.");
|
|
19324
19343
|
const input = { limit: 1 };
|
|
19325
|
-
const invocation =
|
|
19344
|
+
const invocation = callPeopleBladeGhostget({
|
|
19326
19345
|
adapterId: ADAPTER_ID,
|
|
19327
19346
|
operationId: "contacts.list",
|
|
19328
19347
|
authId,
|
|
@@ -19353,7 +19372,7 @@ function rebindBeeperSource(database, options = {}) {
|
|
|
19353
19372
|
if (predecessor === null) {
|
|
19354
19373
|
throw new Error("Beeper rebind source coordinates are not a reviewed predecessor.");
|
|
19355
19374
|
}
|
|
19356
|
-
const metadataOnly = sameIdentity && (predecessor === "peopleblade-0.1.0-wrench-0.15-beeper-2.0" || predecessor === "wrench-0.16.7-beeper-2.4");
|
|
19375
|
+
const metadataOnly = sameIdentity && (predecessor === "peopleblade-0.1.0-wrench-0.15-beeper-2.0" || predecessor === "wrench-0.16.7-beeper-2.4" || predecessor === "wrench-0.16.8-beeper-2.4");
|
|
19357
19376
|
if (sameIdentity && !metadataOnly) {
|
|
19358
19377
|
throw new Error("Beeper metadata-only rebind requires an exact reviewed same-identity predecessor.");
|
|
19359
19378
|
}
|
|
@@ -19381,11 +19400,11 @@ function rebindBeeperSource(database, options = {}) {
|
|
|
19381
19400
|
subjectSha256: next.subjectSha256,
|
|
19382
19401
|
authSha256: next.authSha256,
|
|
19383
19402
|
metadataSha256: sha256(currentMetadata),
|
|
19384
|
-
wrenchVersion:
|
|
19385
|
-
adapterVersion:
|
|
19386
|
-
adapterSha256:
|
|
19387
|
-
transport:
|
|
19388
|
-
contractSha256:
|
|
19403
|
+
wrenchVersion: BEEPER_GHOSTGET_COMPATIBILITY.ghostget.version,
|
|
19404
|
+
adapterVersion: BEEPER_GHOSTGET_COMPATIBILITY.adapter.version,
|
|
19405
|
+
adapterSha256: BEEPER_GHOSTGET_COMPATIBILITY.adapter.sha256,
|
|
19406
|
+
transport: BEEPER_GHOSTGET_COMPATIBILITY.adapter.transport,
|
|
19407
|
+
contractSha256: BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.list"].sha256
|
|
19389
19408
|
},
|
|
19390
19409
|
inventory: {
|
|
19391
19410
|
accounts: inventory.accounts.length,
|
|
@@ -19441,7 +19460,7 @@ function syncBeeperContacts(database, options = {}) {
|
|
|
19441
19460
|
const limit = options.contactLimit ?? DEFAULT_BEEPER_CONTACT_LIMIT;
|
|
19442
19461
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_CONTACTS2)
|
|
19443
19462
|
throw new Error("Beeper contact limit must be from 1 through 200.");
|
|
19444
|
-
const invoke = (input) =>
|
|
19463
|
+
const invoke = (input) => callPeopleBladeGhostget({
|
|
19445
19464
|
adapterId: ADAPTER_ID,
|
|
19446
19465
|
operationId: "contacts.list",
|
|
19447
19466
|
authId,
|
|
@@ -19705,12 +19724,12 @@ function beeperStats(database) {
|
|
|
19705
19724
|
var PROVIDER5 = "beeper";
|
|
19706
19725
|
var MODE4 = "wrench-targeted-search-v1";
|
|
19707
19726
|
var ACCEPTANCE_MODE = "search-candidate-acceptance-v1";
|
|
19708
|
-
var ADAPTER_ID2 =
|
|
19709
|
-
var ADAPTER_VERSION2 =
|
|
19710
|
-
var ADAPTER_SHA2562 =
|
|
19711
|
-
var CONTACTS_SEARCH_CONTRACT_SHA256 =
|
|
19712
|
-
var MESSAGING_SEARCH_CONTRACT_SHA256 =
|
|
19713
|
-
var FINAL_ORIGIN2 =
|
|
19727
|
+
var ADAPTER_ID2 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.id;
|
|
19728
|
+
var ADAPTER_VERSION2 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.version;
|
|
19729
|
+
var ADAPTER_SHA2562 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.sha256;
|
|
19730
|
+
var CONTACTS_SEARCH_CONTRACT_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.search"].sha256;
|
|
19731
|
+
var MESSAGING_SEARCH_CONTRACT_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.operations["messaging.search"].sha256;
|
|
19732
|
+
var FINAL_ORIGIN2 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.origin;
|
|
19714
19733
|
var MAX_QUERIES = 50;
|
|
19715
19734
|
var MAX_RESULTS = 20;
|
|
19716
19735
|
var SHA2562 = /^[a-f0-9]{64}$/u;
|
|
@@ -19854,7 +19873,7 @@ function parseConversation(value, label) {
|
|
|
19854
19873
|
}
|
|
19855
19874
|
function parseSearchPage(value, operation, input, authId) {
|
|
19856
19875
|
const expectedContract = operation === "contacts.search" ? CONTACTS_SEARCH_CONTRACT_SHA256 : MESSAGING_SEARCH_CONTRACT_SHA256;
|
|
19857
|
-
const validated =
|
|
19876
|
+
const validated = validatePeopleBladeGhostgetInvocation(value, {
|
|
19858
19877
|
adapterId: ADAPTER_ID2,
|
|
19859
19878
|
operationId: operation,
|
|
19860
19879
|
authId,
|
|
@@ -19863,18 +19882,18 @@ function parseSearchPage(value, operation, input, authId) {
|
|
|
19863
19882
|
adapterVersion: ADAPTER_VERSION2,
|
|
19864
19883
|
adapterSha256: ADAPTER_SHA2562,
|
|
19865
19884
|
authKind: "linked-device-store",
|
|
19866
|
-
transport:
|
|
19885
|
+
transport: BEEPER_GHOSTGET_COMPATIBILITY.adapter.transport,
|
|
19867
19886
|
contractSha256: expectedContract,
|
|
19868
19887
|
finalOrigin: FINAL_ORIGIN2,
|
|
19869
19888
|
localCli: {
|
|
19870
|
-
surface:
|
|
19889
|
+
surface: BEEPER_GHOSTGET_COMPATIBILITY.adapter.surface,
|
|
19871
19890
|
action: operation,
|
|
19872
|
-
version:
|
|
19873
|
-
toolId:
|
|
19874
|
-
toolImplementation:
|
|
19875
|
-
toolVersion:
|
|
19876
|
-
toolCommit:
|
|
19877
|
-
toolReleaseManifestSha256:
|
|
19891
|
+
version: BEEPER_GHOSTGET_COMPATIBILITY.operations[operation].version,
|
|
19892
|
+
toolId: BEEPER_GHOSTGET_COMPATIBILITY.cli.id,
|
|
19893
|
+
toolImplementation: BEEPER_GHOSTGET_COMPATIBILITY.cli.implementation,
|
|
19894
|
+
toolVersion: BEEPER_GHOSTGET_COMPATIBILITY.cli.version,
|
|
19895
|
+
toolCommit: BEEPER_GHOSTGET_COMPATIBILITY.cli.commit,
|
|
19896
|
+
toolReleaseManifestSha256: BEEPER_GHOSTGET_COMPATIBILITY.cli.releaseManifestSha256
|
|
19878
19897
|
}
|
|
19879
19898
|
});
|
|
19880
19899
|
const execution = validated.execution;
|
|
@@ -19892,7 +19911,7 @@ function parseSearchPage(value, operation, input, authId) {
|
|
|
19892
19911
|
"completeness"
|
|
19893
19912
|
], "Beeper search output");
|
|
19894
19913
|
if (output.provider !== "beeper" || output.operation !== operation || output.projection !== "bounded-local-desktop-search" || output.searchSemantics !== "provider-fuzzy-candidates")
|
|
19895
|
-
throw new Error("
|
|
19914
|
+
throw new Error("Ghostget Beeper search changed projection semantics");
|
|
19896
19915
|
const accountSubject = text3(output.accountSubject, "Beeper account subject", 128);
|
|
19897
19916
|
if (!/^beeper:local:[a-f0-9]{64}$/u.test(accountSubject))
|
|
19898
19917
|
throw new Error("Beeper account subject is invalid");
|
|
@@ -20084,7 +20103,7 @@ function stageCandidates(database, snapshot, candidates, query, service) {
|
|
|
20084
20103
|
function ledgerSearchExecution(database, account, operation, execution) {
|
|
20085
20104
|
if (execution.receipt.operation !== operation)
|
|
20086
20105
|
throw new Error("Beeper search execution operation drifted");
|
|
20087
|
-
return !
|
|
20106
|
+
return !ledgerPeopleBladeGhostgetInvocation(database, {
|
|
20088
20107
|
provider: PROVIDER5,
|
|
20089
20108
|
accountKey: account,
|
|
20090
20109
|
capability: "search_people",
|
|
@@ -20114,7 +20133,7 @@ function backfillBeeperSearch(database, options) {
|
|
|
20114
20133
|
}
|
|
20115
20134
|
return normalized;
|
|
20116
20135
|
}));
|
|
20117
|
-
const invoke = (operation, input) =>
|
|
20136
|
+
const invoke = (operation, input) => callPeopleBladeGhostget({ adapterId: ADAPTER_ID2, operationId: operation, authId, input }, options.invoke);
|
|
20118
20137
|
const inventoryInput = { limit: 1 };
|
|
20119
20138
|
const inventory = parseBeeperContactPage(invoke("contacts.list", inventoryInput), inventoryInput, authId);
|
|
20120
20139
|
assertSourceBindingCurrent(database, PROVIDER5, {
|
|
@@ -20124,7 +20143,7 @@ function backfillBeeperSearch(database, options) {
|
|
|
20124
20143
|
metadata: beeperSourceBindingMetadata()
|
|
20125
20144
|
});
|
|
20126
20145
|
let executionReceiptsRecorded = 0;
|
|
20127
|
-
if (!
|
|
20146
|
+
if (!ledgerPeopleBladeGhostgetInvocation(database, {
|
|
20128
20147
|
provider: PROVIDER5,
|
|
20129
20148
|
accountKey: `beeper:binding:${sha256(inventory.accountSubject)}`,
|
|
20130
20149
|
capability: "contacts",
|
|
@@ -20753,7 +20772,7 @@ function parseContact3(value, label, spec) {
|
|
|
20753
20772
|
};
|
|
20754
20773
|
}
|
|
20755
20774
|
function parsePage(value, input, auth, spec) {
|
|
20756
|
-
const validated =
|
|
20775
|
+
const validated = validatePeopleBladeGhostgetInvocation(value, {
|
|
20757
20776
|
adapterId: "gmail",
|
|
20758
20777
|
operationId: "contacts.list",
|
|
20759
20778
|
authId: auth,
|
|
@@ -20766,20 +20785,20 @@ function parsePage(value, input, auth, spec) {
|
|
|
20766
20785
|
finalOrigin: null
|
|
20767
20786
|
});
|
|
20768
20787
|
const execution = validated.execution;
|
|
20769
|
-
const output = record5(validated.output, "
|
|
20770
|
-
exact3(output, ["provider", "operation", "accountSubject", "contactCollection", "statsIncluded", "contacts", "nextCursor", "totalItems", "statsScanLimit", "statsScope"], "
|
|
20788
|
+
const output = record5(validated.output, "Ghostget output");
|
|
20789
|
+
exact3(output, ["provider", "operation", "accountSubject", "contactCollection", "statsIncluded", "contacts", "nextCursor", "totalItems", "statsScanLimit", "statsScope"], "Ghostget output");
|
|
20771
20790
|
if (output.provider !== "gmail" || output.operation !== "contacts.list" || output.contactCollection !== spec.id || output.statsIncluded !== false || output.statsScanLimit !== null || output.statsScope !== "not-requested") {
|
|
20772
|
-
throw new Error("
|
|
20791
|
+
throw new Error("Ghostget Gmail contact projection drifted");
|
|
20773
20792
|
}
|
|
20774
|
-
const accountSubject = text4(output.accountSubject, "
|
|
20793
|
+
const accountSubject = text4(output.accountSubject, "Ghostget account subject", 254).toLowerCase();
|
|
20775
20794
|
if (!ACCOUNT.test(accountSubject) || accountSubject !== output.accountSubject)
|
|
20776
|
-
throw new Error("
|
|
20795
|
+
throw new Error("Ghostget Gmail account subject is invalid");
|
|
20777
20796
|
const limit = integer5(input.limit, "Google page limit", 1, 100);
|
|
20778
|
-
const contacts = array2(output.contacts, "
|
|
20797
|
+
const contacts = array2(output.contacts, "Ghostget contacts", limit).map((entry, index) => parseContact3(entry, `contacts[${index}]`, spec));
|
|
20779
20798
|
if (new Set(contacts.map((contact) => contact.resourceName)).size !== contacts.length)
|
|
20780
|
-
throw new Error("
|
|
20781
|
-
const nextCursor = optionalText2(output.nextCursor, "
|
|
20782
|
-
const totalItems = output.totalItems === null ? null : integer5(output.totalItems, "
|
|
20799
|
+
throw new Error("Ghostget contact page contains duplicate resources");
|
|
20800
|
+
const nextCursor = optionalText2(output.nextCursor, "Ghostget next cursor", 4096);
|
|
20801
|
+
const totalItems = output.totalItems === null ? null : integer5(output.totalItems, "Ghostget total items", 0, MAX_CONTACTS3);
|
|
20783
20802
|
return { collection: spec.id, input, accountSubject, contacts, nextCursor, totalItems, execution };
|
|
20784
20803
|
}
|
|
20785
20804
|
function authId(value) {
|
|
@@ -20788,11 +20807,11 @@ function authId(value) {
|
|
|
20788
20807
|
throw new Error("Google auth ID is invalid");
|
|
20789
20808
|
return parsed;
|
|
20790
20809
|
}
|
|
20791
|
-
function
|
|
20810
|
+
function ghostgetGoogleContactsSnapshot(options = {}, collection = "contacts") {
|
|
20792
20811
|
const spec = collectionSpec(collection);
|
|
20793
20812
|
const auth = authId(options.authId ?? DEFAULT_GOOGLE_AUTH);
|
|
20794
20813
|
const pageSize = options.pageSize === undefined ? DEFAULT_GOOGLE_PAGE_SIZE : integer5(options.pageSize, "Google page size", 1, 100);
|
|
20795
|
-
const call = (input) =>
|
|
20814
|
+
const call = (input) => callPeopleBladeGhostget({
|
|
20796
20815
|
adapterId: "gmail",
|
|
20797
20816
|
operationId: "contacts.list",
|
|
20798
20817
|
authId: auth,
|
|
@@ -20815,7 +20834,7 @@ function wrenchGoogleContactsSnapshot(options = {}, collection = "contacts") {
|
|
|
20815
20834
|
const page = parsePage(call(input), input, auth, spec);
|
|
20816
20835
|
const priorExecution = pages.at(-1)?.execution;
|
|
20817
20836
|
if (priorExecution !== undefined && Date.parse(page.execution.startedAt) < Date.parse(priorExecution.finishedAt)) {
|
|
20818
|
-
throw new Error("
|
|
20837
|
+
throw new Error("Ghostget Google page timing moved backwards during pagination");
|
|
20819
20838
|
}
|
|
20820
20839
|
if (account !== null && page.accountSubject !== account)
|
|
20821
20840
|
throw new Error("Google account changed during pagination");
|
|
@@ -20844,25 +20863,25 @@ function wrenchGoogleContactsSnapshot(options = {}, collection = "contacts") {
|
|
|
20844
20863
|
throw new Error("Google contact total is incomplete or exceeds its bound");
|
|
20845
20864
|
const executions = pages.map((page) => page.execution);
|
|
20846
20865
|
if (new Set(executions.map((item) => item.runId)).size !== executions.length)
|
|
20847
|
-
throw new Error("
|
|
20866
|
+
throw new Error("Ghostget reused a Google run ID");
|
|
20848
20867
|
const first = executions[0];
|
|
20849
20868
|
for (const item of executions)
|
|
20850
20869
|
if (item.authId !== first.authId || item.authSha256 !== first.authSha256 || item.adapterVersion !== first.adapterVersion || item.adapterSha256 !== first.adapterSha256 || item.contractSha256 !== first.contractSha256) {
|
|
20851
|
-
throw new Error("
|
|
20870
|
+
throw new Error("Ghostget Google execution identity changed during pagination");
|
|
20852
20871
|
}
|
|
20853
20872
|
return { schemaVersion: 1, provider: "google-contacts", collection: spec.id, accountSubject: account, authId: auth, pages };
|
|
20854
20873
|
}
|
|
20855
|
-
function
|
|
20856
|
-
const snapshots = COLLECTIONS.map((spec) =>
|
|
20874
|
+
function ghostgetGoogleContactsSnapshots(options = {}) {
|
|
20875
|
+
const snapshots = COLLECTIONS.map((spec) => ghostgetGoogleContactsSnapshot(options, spec.id));
|
|
20857
20876
|
const first = snapshots[0];
|
|
20858
20877
|
const executions = snapshots.flatMap((snapshot) => snapshot.pages.map((page) => page.execution));
|
|
20859
20878
|
if (new Set(executions.map((execution) => execution.runId)).size !== executions.length) {
|
|
20860
|
-
throw new Error("
|
|
20879
|
+
throw new Error("Ghostget reused a Google run ID across contact collections");
|
|
20861
20880
|
}
|
|
20862
20881
|
for (const snapshot of snapshots) {
|
|
20863
20882
|
const execution = snapshot.pages[0].execution;
|
|
20864
20883
|
if (snapshot.accountSubject !== first.accountSubject || snapshot.authId !== first.authId || execution.authSha256 !== first.pages[0].execution.authSha256 || execution.adapterVersion !== first.pages[0].execution.adapterVersion || execution.adapterSha256 !== first.pages[0].execution.adapterSha256 || execution.contractSha256 !== first.pages[0].execution.contractSha256) {
|
|
20865
|
-
throw new Error("
|
|
20884
|
+
throw new Error("Ghostget Google execution identity changed across contact collections");
|
|
20866
20885
|
}
|
|
20867
20886
|
}
|
|
20868
20887
|
return snapshots;
|
|
@@ -21188,10 +21207,10 @@ function importGoogleContactsSnapshots(database, snapshots) {
|
|
|
21188
21207
|
}
|
|
21189
21208
|
}
|
|
21190
21209
|
function syncGoogleContacts(database, options = {}) {
|
|
21191
|
-
const snapshots =
|
|
21210
|
+
const snapshots = ghostgetGoogleContactsSnapshots(options);
|
|
21192
21211
|
for (const snapshot of snapshots)
|
|
21193
21212
|
for (const page of snapshot.pages) {
|
|
21194
|
-
|
|
21213
|
+
ledgerPeopleBladeGhostgetInvocation(database, {
|
|
21195
21214
|
provider: PROVIDER6,
|
|
21196
21215
|
accountKey: snapshot.accountSubject,
|
|
21197
21216
|
capability: "contacts",
|
|
@@ -25113,7 +25132,7 @@ function ownerJid(accountSubject) {
|
|
|
25113
25132
|
return accountSubject.startsWith("whatsapp:pn:") ? `${accountSubject.slice(12)}@s.whatsapp.net` : `${accountSubject.slice(13)}@lid`;
|
|
25114
25133
|
}
|
|
25115
25134
|
function envelope(value, input, auth) {
|
|
25116
|
-
const parsed =
|
|
25135
|
+
const parsed = validatePeopleBladeGhostgetInvocation(value, {
|
|
25117
25136
|
adapterId: "whatsapp-web",
|
|
25118
25137
|
operationId: "contacts.list",
|
|
25119
25138
|
authId: auth,
|
|
@@ -25125,7 +25144,7 @@ function envelope(value, input, auth) {
|
|
|
25125
25144
|
contractSha256: CONTACTS_CONTRACT_SHA2562,
|
|
25126
25145
|
finalOrigin: "https://web.whatsapp.com"
|
|
25127
25146
|
});
|
|
25128
|
-
return { output: record6(parsed.output, "
|
|
25147
|
+
return { output: record6(parsed.output, "Ghostget output"), execution: parsed.execution };
|
|
25129
25148
|
}
|
|
25130
25149
|
var CONTACT_KEYS = ["providerId", "jidKind", "phone", "redactedPhone", "firstName", "fullName", "pushName", "businessName", "displayName", "displayNameBasis", "alias", "tags", "updatedAt", "localProjectionStatsComplete", "sentCount", "sentCountComplete", "sentCountLowerBound", "sentCountTruncated", "receivedCount", "receivedCountComplete", "receivedCountLowerBound", "receivedCountTruncated", "lastSentAt", "lastSentAtComplete", "lastSentAtBasis", "sentStatsIncompleteReasons", "lastReceivedAt", "lastReceivedAtComplete", "lastReceivedAtBasis", "receivedStatsIncompleteReasons"];
|
|
25131
25150
|
function parseContact4(value, label) {
|
|
@@ -25160,7 +25179,7 @@ function parseContactPage(value, input, auth) {
|
|
|
25160
25179
|
const output = parsed.output;
|
|
25161
25180
|
exact4(output, ["provider", "operation", "accountSubject", "projection", "contacts", "nextCursor", "localContactTablePageComplete", "remoteContactSetComplete", "contactSetIncompleteReasons", "statsScope", "statsCompleteness"], "contact output");
|
|
25162
25181
|
if (output.provider !== "whatsapp" || output.operation !== "contacts.list" || output.projection !== "quiescent-account-bound-session-store" || output.remoteContactSetComplete !== false || output.statsScope !== "unavailable" || output.statsCompleteness !== "unavailable" || stableJson6(output.contactSetIncompleteReasons) !== stableJson6(["linked-device-contact-sync-coverage-unknown"]) || input.collection !== "contacts") {
|
|
25163
|
-
throw new Error("
|
|
25182
|
+
throw new Error("Ghostget contact semantics drifted");
|
|
25164
25183
|
}
|
|
25165
25184
|
const limit = integer6(input.limit, "contact limit", 1, 100);
|
|
25166
25185
|
if (!Array.isArray(output.contacts) || output.contacts.length > limit)
|
|
@@ -25271,7 +25290,7 @@ function parseInteractionPage(value, input, auth) {
|
|
|
25271
25290
|
execution: parsed.execution
|
|
25272
25291
|
};
|
|
25273
25292
|
}
|
|
25274
|
-
function
|
|
25293
|
+
function ghostgetWhatsAppSnapshot(options = {}) {
|
|
25275
25294
|
const auth = authId2(options.authId ?? DEFAULT_WHATSAPP_AUTH);
|
|
25276
25295
|
const contactPageSize = options.contactPageSize === undefined ? DEFAULT_WHATSAPP_CONTACT_PAGE_SIZE : integer6(options.contactPageSize, "contact page size", 1, 100);
|
|
25277
25296
|
const interactionPageSize = options.interactionPageSize === undefined ? DEFAULT_WHATSAPP_INTERACTION_PAGE_SIZE : integer6(options.interactionPageSize, "interaction page size", 1, 1000);
|
|
@@ -25281,7 +25300,7 @@ function wrenchWhatsAppSnapshot(options = {}) {
|
|
|
25281
25300
|
const startGeneration = supplied?.generation === undefined ? undefined : generation(supplied.generation);
|
|
25282
25301
|
if (startCursor === "0" !== (startAnchor === null))
|
|
25283
25302
|
throw new Error("checkpoint is inconsistent");
|
|
25284
|
-
const call = (_operation, input) =>
|
|
25303
|
+
const call = (_operation, input) => callPeopleBladeGhostget({
|
|
25285
25304
|
adapterId: "whatsapp-web",
|
|
25286
25305
|
operationId: "contacts.list",
|
|
25287
25306
|
authId: auth,
|
|
@@ -25333,11 +25352,11 @@ function wrenchWhatsAppSnapshot(options = {}) {
|
|
|
25333
25352
|
throw new Error("WhatsApp interaction pagination exceeded its bound");
|
|
25334
25353
|
const executions = [...contactPages, ...interactionPages].map((page) => page.execution);
|
|
25335
25354
|
if (new Set(executions.map((item) => item.runId)).size !== executions.length)
|
|
25336
|
-
throw new Error("
|
|
25355
|
+
throw new Error("Ghostget reused a WhatsApp run ID");
|
|
25337
25356
|
const first = executions[0];
|
|
25338
25357
|
for (const item of executions)
|
|
25339
25358
|
if (item.authId !== first.authId || item.authSha256 !== first.authSha256 || item.adapterVersion !== first.adapterVersion || item.adapterSha256 !== first.adapterSha256 || item.contractSha256 !== first.contractSha256)
|
|
25340
|
-
throw new Error("
|
|
25359
|
+
throw new Error("Ghostget execution identity changed during sync");
|
|
25341
25360
|
return {
|
|
25342
25361
|
schemaVersion: 2,
|
|
25343
25362
|
provider: "whatsapp",
|
|
@@ -25662,9 +25681,9 @@ function syncWhatsAppRelationships(database, options = {}) {
|
|
|
25662
25681
|
const auth = authId2(options.authId ?? DEFAULT_WHATSAPP_AUTH);
|
|
25663
25682
|
if (options.checkpoint !== undefined)
|
|
25664
25683
|
throw new Error("sync checkpoint is database-owned");
|
|
25665
|
-
const snapshot =
|
|
25684
|
+
const snapshot = ghostgetWhatsAppSnapshot({ ...options, authId: auth, checkpoint: databaseCheckpoint(database, auth) });
|
|
25666
25685
|
for (const page of [...snapshot.contactPages, ...snapshot.interactionPages]) {
|
|
25667
|
-
|
|
25686
|
+
ledgerPeopleBladeGhostgetInvocation(database, {
|
|
25668
25687
|
provider: PROVIDER11,
|
|
25669
25688
|
accountKey: snapshot.accountSubject,
|
|
25670
25689
|
capability: "contact_interactions",
|
|
@@ -25679,7 +25698,7 @@ function syncWhatsAppRelationships(database, options = {}) {
|
|
|
25679
25698
|
}
|
|
25680
25699
|
|
|
25681
25700
|
// src/cli/version.ts
|
|
25682
|
-
var peoplebladeVersion = "0.2.
|
|
25701
|
+
var peoplebladeVersion = "0.2.2";
|
|
25683
25702
|
|
|
25684
25703
|
// src/cli/main.ts
|
|
25685
25704
|
var usage = `PeopleBlade \u2014 local-first contact intelligence
|
|
@@ -25719,19 +25738,19 @@ Core:
|
|
|
25719
25738
|
|
|
25720
25739
|
Sources (append --auto-accept to run identity auto-accept after a successful import):
|
|
25721
25740
|
contacts sync [--directory PATH] Sync macOS Contacts from the local AddressBook database
|
|
25722
|
-
beeper sync [--auth ID] Sync connected Beeper accounts sequentially through
|
|
25741
|
+
beeper sync [--auth ID] Sync connected Beeper accounts sequentially through Ghostget
|
|
25723
25742
|
[--with-relationships] Add body-free lower-bound direct interaction counts
|
|
25724
25743
|
beeper search --query TEXT Import bounded fuzzy candidates for explicit identity review
|
|
25725
25744
|
[--query TEXT ...] [--service NAME ...]
|
|
25726
25745
|
beeper rebind --confirm Explicitly transition a verified existing Beeper source binding
|
|
25727
25746
|
beeper stats Show aggregate Beeper realm and completeness statistics
|
|
25728
|
-
google sync [--auth ID] Sync saved and Other Google Contacts through
|
|
25747
|
+
google sync [--auth ID] Sync saved and Other Google Contacts through Ghostget
|
|
25729
25748
|
google stats Show aggregate Google contact statistics by collection
|
|
25730
25749
|
imessage sync [--database PATH] Sync content-free iMessage metadata incrementally
|
|
25731
25750
|
x import ZIP Import exact IDs from an official X data archive
|
|
25732
25751
|
x stats Show aggregate X archive statistics
|
|
25733
|
-
x mutuals sync Sync X mutuals through
|
|
25734
|
-
whatsapp sync [--auth ID] Sync WhatsApp through
|
|
25752
|
+
x mutuals sync Sync X mutuals through Ghostget (requires reviewed Ghostget capability)
|
|
25753
|
+
whatsapp sync [--auth ID] Sync WhatsApp through Ghostget's linked-device projection
|
|
25735
25754
|
linkedin import ZIP Import an official LinkedIn data-export ZIP
|
|
25736
25755
|
linkedin stats Show aggregate LinkedIn import statistics
|
|
25737
25756
|
instagram import ZIP Import an official Instagram JSON archive
|
|
@@ -26471,8 +26490,8 @@ ${verification}`) });
|
|
|
26471
26490
|
fail3(`Unknown argument: ${options[0]}`);
|
|
26472
26491
|
const effectiveAuthId = authId3 ?? DEFAULT_BEEPER_AUTH;
|
|
26473
26492
|
if (withRelationships)
|
|
26474
|
-
console.error("Beeper relationships \xB7 deriving a body-free interaction summary through
|
|
26475
|
-
console.error("Beeper contacts \xB7 discovering connected accounts through
|
|
26493
|
+
console.error("Beeper relationships \xB7 deriving a body-free interaction summary through Ghostget");
|
|
26494
|
+
console.error("Beeper contacts \xB7 discovering connected accounts through Ghostget");
|
|
26476
26495
|
printImport(syncBeeperContacts(database, {
|
|
26477
26496
|
authId: effectiveAuthId,
|
|
26478
26497
|
contactLimit,
|
|
@@ -26498,7 +26517,7 @@ ${verification}`) });
|
|
|
26498
26517
|
if (options.length)
|
|
26499
26518
|
fail3(`Unknown argument: ${options[0]}`);
|
|
26500
26519
|
if (!confirm)
|
|
26501
|
-
fail3("beeper rebind requires --confirm after reviewing the current
|
|
26520
|
+
fail3("beeper rebind requires --confirm after reviewing the current Ghostget binding, release, and connected-account inventory.");
|
|
26502
26521
|
console.error("Beeper binding \xB7 verifying the complete connected-account inventory before an append-only transition");
|
|
26503
26522
|
print(rebindBeeperSource(database, { ...authId3 === undefined ? {} : { authId: authId3 } }), asJson);
|
|
26504
26523
|
return;
|
|
@@ -26625,7 +26644,7 @@ ${verification}`) });
|
|
|
26625
26644
|
return;
|
|
26626
26645
|
}
|
|
26627
26646
|
if (command === "x" && subcommand === "mutuals" && rest[0] === "sync")
|
|
26628
|
-
fail3("X mutual sync is not enabled until
|
|
26647
|
+
fail3("X mutual sync is not enabled until Ghostget ships a reviewed, bounded x-web mutuals capability. No official X API is required.");
|
|
26629
26648
|
fail3(`Unknown command.
|
|
26630
26649
|
|
|
26631
26650
|
${usage}`);
|