@hraness/peopleblade 0.1.1 → 0.1.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.
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
+ var __require = import.meta.require;
3
4
 
4
5
  // src/cli/main.ts
5
6
  import { existsSync as existsSync5 } from "fs";
@@ -5800,6 +5801,9 @@ function parseGranolaImportJson(raw) {
5800
5801
 
5801
5802
  // src/local/cloud-client.ts
5802
5803
  import { createHash as createHash2, randomBytes } from "crypto";
5804
+ import { z as z6 } from "zod";
5805
+
5806
+ // src/local/cloud-configuration.ts
5803
5807
  import { z as z5 } from "zod";
5804
5808
 
5805
5809
  // src/local/config.ts
@@ -5856,6 +5860,100 @@ function writeLocalConfig(config) {
5856
5860
  renameSync(temporary, path);
5857
5861
  }
5858
5862
 
5863
+ // src/local/cloud-configuration.ts
5864
+ var cloudConfigurationSchema = z5.object({
5865
+ baseUrl: z5.url().max(2048),
5866
+ deviceId: z5.uuid(),
5867
+ token: z5.string().min(20).max(512)
5868
+ }).strict();
5869
+ function cloudConfiguration(override) {
5870
+ const config = override ?? readLocalConfig().cloud;
5871
+ if (config === null)
5872
+ throw new Error("Run `peopleblade cloud signin` first.");
5873
+ return cloudConfigurationSchema.parse(config);
5874
+ }
5875
+
5876
+ // src/local/cloud-transport.ts
5877
+ class CloudHttpError extends Error {
5878
+ status;
5879
+ constructor(status, message) {
5880
+ super(message);
5881
+ this.status = status;
5882
+ this.name = "CloudHttpError";
5883
+ }
5884
+ }
5885
+ async function postJson(fetcher, url, body, bearer, timeoutMs = 45000, signal) {
5886
+ const response = await fetcher(url, {
5887
+ method: "POST",
5888
+ headers: { "content-type": "application/json", ...bearer === undefined ? {} : { authorization: `Bearer ${bearer}` } },
5889
+ body: JSON.stringify(body),
5890
+ redirect: "error",
5891
+ signal: signal === undefined ? AbortSignal.timeout(timeoutMs) : AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)])
5892
+ });
5893
+ if (response.bodyUsed || response.body?.locked)
5894
+ await response.text();
5895
+ const reader = response.body?.getReader();
5896
+ let reachedEof = false;
5897
+ let failed = false;
5898
+ try {
5899
+ const raw = reader === undefined ? "" : await readBoundedText(reader);
5900
+ reachedEof = true;
5901
+ return parseResponse(raw, response);
5902
+ } catch (error) {
5903
+ failed = true;
5904
+ throw error;
5905
+ } finally {
5906
+ if (reader !== undefined) {
5907
+ if (!reachedEof) {
5908
+ try {
5909
+ reader.cancel().catch(() => {
5910
+ return;
5911
+ });
5912
+ } catch {}
5913
+ }
5914
+ try {
5915
+ reader.releaseLock();
5916
+ } catch (error) {
5917
+ if (!failed)
5918
+ throw error;
5919
+ }
5920
+ }
5921
+ }
5922
+ }
5923
+ var MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
5924
+ async function readBoundedText(reader) {
5925
+ const bytes = new Uint8Array(MAX_RESPONSE_BYTES + 3);
5926
+ let length = 0;
5927
+ for (;; ) {
5928
+ const next = await reader.read();
5929
+ if (next.done)
5930
+ break;
5931
+ if (next.value.byteLength > bytes.length - length)
5932
+ throw new Error("PeopleBlade cloud response is too large.");
5933
+ bytes.set(next.value, length);
5934
+ length += next.value.byteLength;
5935
+ }
5936
+ const raw = new TextDecoder().decode(bytes.subarray(0, length));
5937
+ if (Buffer.byteLength(raw) > MAX_RESPONSE_BYTES)
5938
+ throw new Error("PeopleBlade cloud response is too large.");
5939
+ return raw;
5940
+ }
5941
+ function parseResponse(raw, response) {
5942
+ let value;
5943
+ try {
5944
+ value = JSON.parse(raw);
5945
+ } catch {
5946
+ if (!response.ok)
5947
+ throw new CloudHttpError(response.status, `PeopleBlade cloud returned HTTP ${response.status} without a JSON error response.`);
5948
+ throw new Error("PeopleBlade cloud returned invalid JSON.");
5949
+ }
5950
+ if (!response.ok) {
5951
+ const message = value !== null && typeof value === "object" && typeof value.message === "string" ? value.message : `PeopleBlade cloud returned HTTP ${response.status}.`;
5952
+ throw new CloudHttpError(response.status, message);
5953
+ }
5954
+ return value;
5955
+ }
5956
+
5859
5957
  // src/local/projection.ts
5860
5958
  function parseStringArray(value) {
5861
5959
  const parsed = JSON.parse(value);
@@ -5872,12 +5970,6 @@ function iso(value) {
5872
5970
  function localDatabaseFingerprint(database) {
5873
5971
  return localDatabaseInstanceId(database);
5874
5972
  }
5875
- function localSchemaVersion(database) {
5876
- const row = database.query("SELECT count(*) AS count FROM schema_migrations").get();
5877
- if (row === null || !Number.isSafeInteger(row.count) || row.count < 1)
5878
- throw new Error("PeopleBlade schema is not initialized.");
5879
- return row.count;
5880
- }
5881
5973
  function projectCloudContacts(database) {
5882
5974
  const rows = database.query(`
5883
5975
  WITH
@@ -6090,77 +6182,49 @@ function projectCloudContacts(database) {
6090
6182
  }
6091
6183
 
6092
6184
  // src/local/cloud-client.ts
6093
- var deviceStartResponse = z5.object({
6185
+ var deviceStartResponse = z6.object({
6094
6186
  deviceCode: deviceCodeSchema,
6095
- userCode: z5.string().regex(/^[23456789A-HJ-NP-Z]{8}$/u),
6096
- verificationUri: z5.url().max(2048),
6097
- expiresIn: z5.number().int().min(60).max(3600),
6098
- interval: z5.number().int().min(1).max(30)
6187
+ userCode: z6.string().regex(/^[23456789A-HJ-NP-Z]{8}$/u),
6188
+ verificationUri: z6.url().max(2048),
6189
+ expiresIn: z6.number().int().min(60).max(3600),
6190
+ interval: z6.number().int().min(1).max(30)
6099
6191
  }).strict();
6100
- var deviceStatusResponse = z5.discriminatedUnion("status", [
6101
- z5.object({ status: z5.literal("pending") }).strict(),
6102
- z5.object({ status: z5.literal("expired") }).strict(),
6103
- z5.object({ status: z5.literal("authorized"), deviceId: z5.uuid() }).strict()
6192
+ var deviceStatusResponse = z6.discriminatedUnion("status", [
6193
+ z6.object({ status: z6.literal("pending") }).strict(),
6194
+ z6.object({ status: z6.literal("expired") }).strict(),
6195
+ z6.object({ status: z6.literal("authorized"), deviceId: z6.uuid() }).strict()
6104
6196
  ]);
6105
- var syncStartResponse = z5.object({
6106
- snapshotId: z5.uuid(),
6107
- resumed: z5.boolean(),
6108
- uploadedContacts: z5.number().int().min(0).max(1e6),
6109
- uploadedPages: z5.number().int().min(0).max(1e5),
6110
- uploadedPageContactCounts: z5.array(z5.number().int().min(1).max(200)).max(1e5)
6111
- }).strict().superRefine((value, context) => {
6112
- if (value.uploadedPageContactCounts.length !== value.uploadedPages)
6113
- context.addIssue({
6114
- code: "custom",
6115
- path: ["uploadedPageContactCounts"],
6116
- message: "Uploaded sync-page manifest length does not match its page count"
6117
- });
6118
- const contactCount = value.uploadedPageContactCounts.reduce((sum, count) => sum + count, 0);
6119
- if (contactCount !== value.uploadedContacts)
6120
- context.addIssue({
6121
- code: "custom",
6122
- path: ["uploadedContacts"],
6123
- message: "Uploaded sync-page manifest does not match its contact count"
6124
- });
6125
- if (!value.resumed && (value.uploadedContacts !== 0 || value.uploadedPages !== 0))
6126
- context.addIssue({
6127
- code: "custom",
6128
- path: ["resumed"],
6129
- message: "A fresh sync snapshot cannot report uploaded progress"
6130
- });
6131
- });
6132
- var SYNC_PAGE_TIMEOUT_MS = 240000;
6133
- var boundedModelCoordinateSchema = z5.string().min(1).max(256).regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u);
6134
- var usageOperationSchema = z5.string().regex(/^[a-z][a-z0-9_]{0,63}$/u);
6135
- var usageProviderSchema = z5.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
6136
- var usageUnitSchema = z5.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
6137
- var cliEnrichmentUsageLimitResponse = z5.object({
6197
+ var boundedModelCoordinateSchema = z6.string().min(1).max(256).regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u);
6198
+ var usageOperationSchema = z6.string().regex(/^[a-z][a-z0-9_]{0,63}$/u);
6199
+ var usageProviderSchema = z6.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
6200
+ var usageUnitSchema = z6.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
6201
+ var cliEnrichmentUsageLimitResponse = z6.object({
6138
6202
  operation: usageOperationSchema,
6139
6203
  provider: usageProviderSchema,
6140
6204
  unit: usageUnitSchema,
6141
- maximum: z5.number().int().min(0).max(100)
6205
+ maximum: z6.number().int().min(0).max(100)
6142
6206
  }).strict();
6143
- var cliEnrichmentPreviewResponse = z5.object({
6144
- previewId: z5.uuid(),
6207
+ var cliEnrichmentPreviewResponse = z6.object({
6208
+ previewId: z6.uuid(),
6145
6209
  confirmationToken: cliEnrichmentConfirmationTokenSchema,
6146
- selectedCount: z5.number().int().min(1).max(100),
6147
- availableCredits: z5.number().int().min(0),
6148
- usageLimits: z5.array(cliEnrichmentUsageLimitResponse).min(1).max(16),
6149
- policyVersion: z5.literal(enrichmentPolicyVersion),
6210
+ selectedCount: z6.number().int().min(1).max(100),
6211
+ availableCredits: z6.number().int().min(0),
6212
+ usageLimits: z6.array(cliEnrichmentUsageLimitResponse).min(1).max(16),
6213
+ policyVersion: z6.literal(enrichmentPolicyVersion),
6150
6214
  model: boundedModelCoordinateSchema,
6151
- expiresAt: z5.iso.datetime({ offset: true })
6215
+ expiresAt: z6.iso.datetime({ offset: true })
6152
6216
  }).strict();
6153
- var cliPrioritizedEnrichmentContactResponse = z5.object({
6154
- localPersonId: z5.string().regex(/^[1-9][0-9]{0,18}$/u),
6155
- enrichmentInputVersion: z5.literal(2),
6156
- enrichmentInputSha256: z5.string().regex(/^[a-f0-9]{64}$/u),
6157
- rank: z5.number().int().min(1).max(100),
6158
- score: z5.number().int().min(0).max(1e4),
6159
- components: z5.object({
6160
- engagement: z5.number().int().min(0).max(5500),
6161
- reciprocity: z5.number().int().min(0).max(1000),
6162
- dataGaps: z5.number().int().min(0).max(2000),
6163
- identityReadiness: z5.number().int().min(0).max(1500)
6217
+ var cliPrioritizedEnrichmentContactResponse = z6.object({
6218
+ localPersonId: z6.string().regex(/^[1-9][0-9]{0,18}$/u),
6219
+ enrichmentInputVersion: z6.literal(2),
6220
+ enrichmentInputSha256: z6.string().regex(/^[a-f0-9]{64}$/u),
6221
+ rank: z6.number().int().min(1).max(100),
6222
+ score: z6.number().int().min(0).max(1e4),
6223
+ components: z6.object({
6224
+ engagement: z6.number().int().min(0).max(5500),
6225
+ reciprocity: z6.number().int().min(0).max(1000),
6226
+ dataGaps: z6.number().int().min(0).max(2000),
6227
+ identityReadiness: z6.number().int().min(0).max(1500)
6164
6228
  }).strict()
6165
6229
  }).strict().superRefine((value, context) => {
6166
6230
  const total = value.components.engagement + value.components.reciprocity + value.components.dataGaps + value.components.identityReadiness;
@@ -6168,39 +6232,39 @@ var cliPrioritizedEnrichmentContactResponse = z5.object({
6168
6232
  context.addIssue({ code: "custom", path: ["score"], message: "Priority score components drifted" });
6169
6233
  });
6170
6234
  var cliPrioritizedEnrichmentPreviewResponse = cliEnrichmentPreviewResponse.extend({
6171
- contacts: z5.array(cliPrioritizedEnrichmentContactResponse).min(1).max(100),
6172
- priority: z5.object({
6173
- policyVersion: z5.literal(enrichmentPriorityPolicyVersion),
6174
- asOf: z5.iso.datetime({ offset: true }),
6175
- receiptSha256: z5.string().regex(/^[a-f0-9]{64}$/u),
6176
- eligibleCount: z5.number().int().min(1).max(1e6),
6177
- executionCapacity: z5.tuple([z5.object({
6178
- operation: z5.literal("enrich_email"),
6179
- maximum: z5.number().int().min(0).max(100)
6235
+ contacts: z6.array(cliPrioritizedEnrichmentContactResponse).min(1).max(100),
6236
+ priority: z6.object({
6237
+ policyVersion: z6.literal(enrichmentPriorityPolicyVersion),
6238
+ asOf: z6.iso.datetime({ offset: true }),
6239
+ receiptSha256: z6.string().regex(/^[a-f0-9]{64}$/u),
6240
+ eligibleCount: z6.number().int().min(1).max(1e6),
6241
+ executionCapacity: z6.tuple([z6.object({
6242
+ operation: z6.literal("enrich_email"),
6243
+ maximum: z6.number().int().min(0).max(100)
6180
6244
  }).strict()])
6181
6245
  }).strict()
6182
6246
  }).strict();
6183
- var cliEnrichmentDispatchResponse = z5.object({
6184
- jobId: z5.uuid(),
6185
- dispatchStatus: z5.enum(["dispatching", "launched", "indeterminate"]),
6186
- replayed: z5.boolean()
6247
+ var cliEnrichmentDispatchResponse = z6.object({
6248
+ jobId: z6.uuid(),
6249
+ dispatchStatus: z6.enum(["dispatching", "launched", "indeterminate"]),
6250
+ replayed: z6.boolean()
6187
6251
  }).strict();
6188
- var enrichmentFieldSchema = z5.enum(["headline", "organization", "role", "location", "website", "publicEmail"]);
6189
- var usageBillingSurfaceSchema = z5.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
6252
+ var enrichmentFieldSchema = z6.enum(["headline", "organization", "role", "location", "website", "publicEmail"]);
6253
+ var usageBillingSurfaceSchema = z6.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
6190
6254
  var usageModelSchema = boundedModelCoordinateSchema.nullable();
6191
- var usageBillingUnitSchema = z5.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u).nullable();
6192
- var usageBillingCertaintySchema = z5.enum(["unknown", "reported", "contractual", "conservative"]);
6193
- var usageOutcomeSchema = z5.string().regex(/^[a-z][a-z0-9_]{0,63}$/u);
6194
- var usageErrorCodeSchema = z5.string().regex(/^[A-Z0-9][A-Z0-9_:.-]{2,159}$/u).nullable();
6195
- var usageCostCertaintySchema = z5.enum(["reported", "contractual", "estimated", "unknown", "reconciled"]);
6196
- var usageExecutionRouteSchema = z5.string().regex(/^[a-z][a-z0-9_]{0,63}$/u);
6197
- var usageExecutionProfileSha256Schema = z5.string().regex(/^[0-9a-f]{64}$/u).nullable();
6198
- var boundedUsageCount = z5.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
6199
- var cliEnrichmentUsageCoverageResponse = z5.object({
6200
- ledgerRuns: z5.number().int().min(0).max(100),
6201
- legacyRuns: z5.number().int().min(0).max(100)
6255
+ var usageBillingUnitSchema = z6.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u).nullable();
6256
+ var usageBillingCertaintySchema = z6.enum(["unknown", "reported", "contractual", "conservative"]);
6257
+ var usageOutcomeSchema = z6.string().regex(/^[a-z][a-z0-9_]{0,63}$/u);
6258
+ var usageErrorCodeSchema = z6.string().regex(/^[A-Z0-9][A-Z0-9_:.-]{2,159}$/u).nullable();
6259
+ var usageCostCertaintySchema = z6.enum(["reported", "contractual", "estimated", "unknown", "reconciled"]);
6260
+ var usageExecutionRouteSchema = z6.string().regex(/^[a-z][a-z0-9_]{0,63}$/u);
6261
+ var usageExecutionProfileSha256Schema = z6.string().regex(/^[0-9a-f]{64}$/u).nullable();
6262
+ var boundedUsageCount = z6.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
6263
+ var cliEnrichmentUsageCoverageResponse = z6.object({
6264
+ ledgerRuns: z6.number().int().min(0).max(100),
6265
+ legacyRuns: z6.number().int().min(0).max(100)
6202
6266
  }).strict();
6203
- var cliEnrichmentProviderUsageResponse = z5.object({
6267
+ var cliEnrichmentProviderUsageResponse = z6.object({
6204
6268
  operation: usageOperationSchema,
6205
6269
  executionRoute: usageExecutionRouteSchema,
6206
6270
  executionProfileSha256: usageExecutionProfileSha256Schema,
@@ -6218,57 +6282,57 @@ var cliEnrichmentProviderUsageResponse = z5.object({
6218
6282
  inputTokens: boundedUsageCount,
6219
6283
  outputTokens: boundedUsageCount,
6220
6284
  billingUnit: usageBillingUnitSchema,
6221
- billedUnits: z5.number().min(0).max(Number.MAX_SAFE_INTEGER),
6285
+ billedUnits: z6.number().min(0).max(Number.MAX_SAFE_INTEGER),
6222
6286
  billingCertainty: usageBillingCertaintySchema,
6223
- billingUnknown: z5.boolean(),
6224
- knownCostUsd: z5.number().min(0).max(Number.MAX_SAFE_INTEGER),
6287
+ billingUnknown: z6.boolean(),
6288
+ knownCostUsd: z6.number().min(0).max(Number.MAX_SAFE_INTEGER),
6225
6289
  costCertainty: usageCostCertaintySchema,
6226
6290
  unknownCostAttempts: boundedUsageCount
6227
6291
  }).strict();
6228
- var cliEnrichmentAggregateFieldSourceResponse = z5.object({
6292
+ var cliEnrichmentAggregateFieldSourceResponse = z6.object({
6229
6293
  field: enrichmentFieldSchema,
6230
6294
  operation: usageOperationSchema,
6231
6295
  provider: usageProviderSchema,
6232
- contacts: z5.number().int().min(0).max(100)
6296
+ contacts: z6.number().int().min(0).max(100)
6233
6297
  }).strict();
6234
- var cliEnrichmentFailureResponse = z5.object({
6298
+ var cliEnrichmentFailureResponse = z6.object({
6235
6299
  operation: usageOperationSchema,
6236
- count: z5.number().int().min(1).max(100)
6300
+ count: z6.number().int().min(1).max(100)
6237
6301
  }).strict();
6238
- var cliEnrichmentJobStatusV4Response = z5.object({
6239
- id: z5.uuid(),
6240
- status: z5.enum(["queued", "running", "complete", "partial", "failed"]),
6241
- dispatchStatus: z5.enum(["dispatching", "launched", "indeterminate"]),
6242
- selectedCount: z5.number().int().min(1).max(100),
6243
- completedCount: z5.number().int().min(0).max(100),
6244
- failedCount: z5.number().int().min(0).max(100),
6245
- productCreditsSpent: z5.number().int().min(0).max(100),
6302
+ var cliEnrichmentJobStatusV4Response = z6.object({
6303
+ id: z6.uuid(),
6304
+ status: z6.enum(["queued", "running", "complete", "partial", "failed"]),
6305
+ dispatchStatus: z6.enum(["dispatching", "launched", "indeterminate"]),
6306
+ selectedCount: z6.number().int().min(1).max(100),
6307
+ completedCount: z6.number().int().min(0).max(100),
6308
+ failedCount: z6.number().int().min(0).max(100),
6309
+ productCreditsSpent: z6.number().int().min(0).max(100),
6246
6310
  usageCoverage: cliEnrichmentUsageCoverageResponse,
6247
- providerUsage: z5.array(cliEnrichmentProviderUsageResponse).max(256),
6248
- fieldSources: z5.array(cliEnrichmentAggregateFieldSourceResponse).max(600),
6249
- failures: z5.array(cliEnrichmentFailureResponse).max(9),
6250
- createdAt: z5.iso.datetime({ offset: true }),
6251
- completedAt: z5.iso.datetime({ offset: true }).nullable()
6311
+ providerUsage: z6.array(cliEnrichmentProviderUsageResponse).max(256),
6312
+ fieldSources: z6.array(cliEnrichmentAggregateFieldSourceResponse).max(600),
6313
+ failures: z6.array(cliEnrichmentFailureResponse).max(9),
6314
+ createdAt: z6.iso.datetime({ offset: true }),
6315
+ completedAt: z6.iso.datetime({ offset: true }).nullable()
6252
6316
  }).strict();
6253
- var cliEnrichmentRunDetailResponse = z5.object({
6254
- localPersonId: z5.string().regex(/^[1-9][0-9]{0,18}$/u),
6255
- status: z5.enum(["pending", "running", "complete", "failed"]),
6256
- errorCode: z5.string().min(1).max(200).nullable(),
6317
+ var cliEnrichmentRunDetailResponse = z6.object({
6318
+ localPersonId: z6.string().regex(/^[1-9][0-9]{0,18}$/u),
6319
+ status: z6.enum(["pending", "running", "complete", "failed"]),
6320
+ errorCode: z6.string().min(1).max(200).nullable(),
6257
6321
  failureOperation: usageOperationSchema.nullable(),
6258
- identityMatch: z5.enum(["confirmed", "possible", "insufficient"]).nullable(),
6259
- confidence: z5.number().int().min(0).max(100).nullable(),
6260
- fieldsPresent: z5.array(enrichmentFieldSchema).max(6),
6261
- claimFields: z5.array(enrichmentFieldSchema).max(6)
6322
+ identityMatch: z6.enum(["confirmed", "possible", "insufficient"]).nullable(),
6323
+ confidence: z6.number().int().min(0).max(100).nullable(),
6324
+ fieldsPresent: z6.array(enrichmentFieldSchema).max(6),
6325
+ claimFields: z6.array(enrichmentFieldSchema).max(6)
6262
6326
  }).strict();
6263
- var cliEnrichmentRunUsageResponse = z5.object({
6327
+ var cliEnrichmentRunUsageResponse = z6.object({
6264
6328
  operation: usageOperationSchema,
6265
6329
  executionRoute: usageExecutionRouteSchema,
6266
6330
  executionProfileSha256: usageExecutionProfileSha256Schema,
6267
- attempt: z5.number().int().min(1).max(16),
6331
+ attempt: z6.number().int().min(1).max(16),
6268
6332
  billingSurface: usageBillingSurfaceSchema,
6269
6333
  provider: usageProviderSchema,
6270
6334
  model: usageModelSchema,
6271
- status: z5.enum(["open", "succeeded", "failed", "indeterminate"]),
6335
+ status: z6.enum(["open", "succeeded", "failed", "indeterminate"]),
6272
6336
  outcome: usageOutcomeSchema,
6273
6337
  errorCode: usageErrorCodeSchema,
6274
6338
  results: boundedUsageCount,
@@ -6276,10 +6340,10 @@ var cliEnrichmentRunUsageResponse = z5.object({
6276
6340
  inputTokens: boundedUsageCount,
6277
6341
  outputTokens: boundedUsageCount,
6278
6342
  billingUnit: usageBillingUnitSchema,
6279
- billedUnits: z5.number().min(0).max(Number.MAX_SAFE_INTEGER),
6343
+ billedUnits: z6.number().min(0).max(Number.MAX_SAFE_INTEGER),
6280
6344
  billingCertainty: usageBillingCertaintySchema,
6281
- billingUnknown: z5.boolean(),
6282
- costUsd: z5.number().min(0).max(Number.MAX_SAFE_INTEGER).nullable(),
6345
+ billingUnknown: z6.boolean(),
6346
+ costUsd: z6.number().min(0).max(Number.MAX_SAFE_INTEGER).nullable(),
6283
6347
  costCertainty: usageCostCertaintySchema
6284
6348
  }).strict().superRefine((value, context) => {
6285
6349
  if ((value.status === "open" || value.status === "succeeded") && value.errorCode !== null) {
@@ -6290,27 +6354,22 @@ var cliEnrichmentRunUsageResponse = z5.object({
6290
6354
  });
6291
6355
  }
6292
6356
  });
6293
- var cliEnrichmentRunFieldSourceResponse = z5.object({
6357
+ var cliEnrichmentRunFieldSourceResponse = z6.object({
6294
6358
  field: enrichmentFieldSchema,
6295
- sources: z5.array(z5.object({
6359
+ sources: z6.array(z6.object({
6296
6360
  operation: usageOperationSchema,
6297
6361
  provider: usageProviderSchema,
6298
- evidenceRows: z5.number().int().min(1).max(5)
6362
+ evidenceRows: z6.number().int().min(1).max(5)
6299
6363
  }).strict()).max(5)
6300
6364
  }).strict();
6301
- var cliEnrichmentJobDetailsV4Response = z5.object({
6302
- jobId: z5.uuid(),
6303
- runs: z5.array(cliEnrichmentRunDetailResponse.extend({
6304
- usageCoverage: z5.enum(["ledger", "legacy"]),
6305
- usage: z5.array(cliEnrichmentRunUsageResponse).max(512),
6306
- fieldSources: z5.array(cliEnrichmentRunFieldSourceResponse).max(6)
6365
+ var cliEnrichmentJobDetailsV4Response = z6.object({
6366
+ jobId: z6.uuid(),
6367
+ runs: z6.array(cliEnrichmentRunDetailResponse.extend({
6368
+ usageCoverage: z6.enum(["ledger", "legacy"]),
6369
+ usage: z6.array(cliEnrichmentRunUsageResponse).max(512),
6370
+ fieldSources: z6.array(cliEnrichmentRunFieldSourceResponse).max(6)
6307
6371
  }).strict()).max(100)
6308
6372
  }).strict();
6309
- var cloudConfigurationSchema = z5.object({
6310
- baseUrl: z5.url().max(2048),
6311
- deviceId: z5.uuid(),
6312
- token: z5.string().min(20).max(512)
6313
- }).strict();
6314
6373
  function baseUrl(value) {
6315
6374
  const parsed = new URL(value);
6316
6375
  if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && ["localhost", "127.0.0.1"].includes(parsed.hostname))) {
@@ -6321,40 +6380,6 @@ function baseUrl(value) {
6321
6380
  parsed.hash = "";
6322
6381
  return parsed.toString().replace(/\/$/u, "");
6323
6382
  }
6324
-
6325
- class CloudHttpError extends Error {
6326
- status;
6327
- constructor(status, message) {
6328
- super(message);
6329
- this.status = status;
6330
- this.name = "CloudHttpError";
6331
- }
6332
- }
6333
- async function postJson(fetcher, url, body, bearer, timeoutMs = 45000) {
6334
- const response = await fetcher(url, {
6335
- method: "POST",
6336
- headers: { "content-type": "application/json", ...bearer === undefined ? {} : { authorization: `Bearer ${bearer}` } },
6337
- body: JSON.stringify(body),
6338
- redirect: "error",
6339
- signal: AbortSignal.timeout(timeoutMs)
6340
- });
6341
- const raw = await response.text();
6342
- if (Buffer.byteLength(raw) > 2 * 1024 * 1024)
6343
- throw new Error("PeopleBlade cloud response is too large.");
6344
- let value;
6345
- try {
6346
- value = JSON.parse(raw);
6347
- } catch {
6348
- if (!response.ok)
6349
- throw new CloudHttpError(response.status, `PeopleBlade cloud returned HTTP ${response.status} without a JSON error response.`);
6350
- throw new Error("PeopleBlade cloud returned invalid JSON.");
6351
- }
6352
- if (!response.ok) {
6353
- const message = value !== null && typeof value === "object" && typeof value.message === "string" ? value.message : `PeopleBlade cloud returned HTTP ${response.status}.`;
6354
- throw new CloudHttpError(response.status, message);
6355
- }
6356
- return value;
6357
- }
6358
6383
  function clearCloudCredentials(options) {
6359
6384
  (options.clearCredentials ?? (() => writeLocalConfig({ cloud: null })))();
6360
6385
  }
@@ -6421,62 +6446,8 @@ async function signOutCloud(options = {}) {
6421
6446
  }
6422
6447
  }
6423
6448
  async function syncCloud(database, options = {}) {
6424
- const config = options.configuration ?? readLocalConfig().cloud;
6425
- if (config === null)
6426
- throw new Error("Run `peopleblade cloud signin` first.");
6427
- const validatedConfig = cloudConfigurationSchema.parse(config);
6428
- const fetcher = options.fetcher ?? fetch;
6429
- const pageSize = Math.max(1, Math.min(200, options.pageSize ?? 200));
6430
- const contacts = projectCloudContacts(database);
6431
- const startInput = syncStartSchema.parse({
6432
- contactCount: contacts.length,
6433
- databaseFingerprint: localDatabaseFingerprint(database),
6434
- schemaVersion: localSchemaVersion(database),
6435
- resumeVersion: 1
6436
- });
6437
- const started = syncStartResponse.parse(await postJson(fetcher, `${validatedConfig.baseUrl}/api/cli/sync/start`, startInput, validatedConfig.token, 285000));
6438
- if (started.uploadedContacts > contacts.length) {
6439
- throw new Error("Cloud sync resume progress exceeds the current local projection.");
6440
- }
6441
- let pages = 0;
6442
- let offset = 0;
6443
- for (const priorPageContacts of started.uploadedPageContactCounts) {
6444
- const replayContacts = contacts.slice(offset, offset + priorPageContacts);
6445
- if (replayContacts.length !== priorPageContacts) {
6446
- throw new Error("Cloud sync resume manifest exceeds the current local projection.");
6447
- }
6448
- const input = syncPageSchema.parse({ snapshotId: started.snapshotId, ordinal: pages, contacts: replayContacts });
6449
- await postJson(fetcher, `${validatedConfig.baseUrl}/api/cli/sync/page`, input, validatedConfig.token, SYNC_PAGE_TIMEOUT_MS);
6450
- pages += 1;
6451
- offset += priorPageContacts;
6452
- }
6453
- if (offset !== started.uploadedContacts || pages !== started.uploadedPages) {
6454
- throw new Error("Cloud sync resume manifest did not reproduce its reported progress.");
6455
- }
6456
- for (;offset < contacts.length; offset += pageSize) {
6457
- const input = syncPageSchema.parse({ snapshotId: started.snapshotId, ordinal: pages, contacts: contacts.slice(offset, offset + pageSize) });
6458
- await postJson(fetcher, `${validatedConfig.baseUrl}/api/cli/sync/page`, input, validatedConfig.token, SYNC_PAGE_TIMEOUT_MS);
6459
- pages += 1;
6460
- }
6461
- const finish = syncFinishSchema.parse({ snapshotId: started.snapshotId, pages, contactCount: contacts.length });
6462
- await postJson(fetcher, `${validatedConfig.baseUrl}/api/cli/sync/finish`, finish, validatedConfig.token);
6463
- database.query(`INSERT INTO cloud_sync_state(singleton,base_url,device_id,last_snapshot_id,last_synced_at)
6464
- VALUES (1,?,?,?,CURRENT_TIMESTAMP)
6465
- ON CONFLICT(singleton) DO UPDATE SET base_url=excluded.base_url, device_id=excluded.device_id,
6466
- last_snapshot_id=excluded.last_snapshot_id, last_synced_at=excluded.last_synced_at`).run(validatedConfig.baseUrl, validatedConfig.deviceId, started.snapshotId);
6467
- return {
6468
- snapshotId: started.snapshotId,
6469
- contacts: contacts.length,
6470
- pages,
6471
- resumed: started.resumed,
6472
- replayedPages: started.uploadedPages
6473
- };
6474
- }
6475
- function cloudConfiguration(override) {
6476
- const config = override ?? readLocalConfig().cloud;
6477
- if (config === null)
6478
- throw new Error("Run `peopleblade cloud signin` first.");
6479
- return cloudConfigurationSchema.parse(config);
6449
+ const { startCloudSync } = __require("./cloud-sync-client.js");
6450
+ return startCloudSync(database, options, postJson);
6480
6451
  }
6481
6452
  function selectedLocalContacts(database, personIds, config) {
6482
6453
  const unique = [...new Set(personIds)].sort((left, right) => left - right);
@@ -6504,11 +6475,13 @@ function selectedLocalContacts(database, personIds, config) {
6504
6475
  async function previewCloudEnrichment(database, personIds, options = {}) {
6505
6476
  const config = cloudConfiguration(options.configuration);
6506
6477
  const contacts = selectedLocalContacts(database, personIds, config);
6507
- const response = cliEnrichmentPreviewResponse.parse(await postJson(options.fetcher ?? fetch, `${config.baseUrl}/api/cli/enrich/preview`, { contacts: contacts.map((contact) => ({
6508
- localPersonId: contact.localPersonId,
6509
- enrichmentInputVersion: contact.enrichmentInputVersion,
6510
- enrichmentInputSha256: contact.enrichmentInputSha256
6511
- })) }, config.token));
6478
+ const response = cliEnrichmentPreviewResponse.parse(await postJson(options.fetcher ?? fetch, `${config.baseUrl}/api/cli/enrich/preview`, {
6479
+ contacts: contacts.map((contact) => ({
6480
+ localPersonId: contact.localPersonId,
6481
+ enrichmentInputVersion: contact.enrichmentInputVersion,
6482
+ enrichmentInputSha256: contact.enrichmentInputSha256
6483
+ }))
6484
+ }, config.token));
6512
6485
  const contactCreditLimits = response.usageLimits.filter((limit) => limit.operation === "enrich_contact" && limit.unit === "credit");
6513
6486
  if (response.selectedCount !== contacts.length || contactCreditLimits.length !== 1 || contactCreditLimits[0]?.maximum !== contacts.length || new Set(response.usageLimits.map((limit) => `${limit.operation}\x00${limit.provider}\x00${limit.unit}`)).size !== response.usageLimits.length) {
6514
6487
  throw new Error("PeopleBlade cloud enrichment preview count drifted.");
@@ -6886,12 +6859,13 @@ function assertSourceBindingCurrent(database, authority, binding) {
6886
6859
  const current = readSourceBindingState(database, authority, binding.authId);
6887
6860
  if (current === null)
6888
6861
  return;
6889
- if (current.subjectSha256 !== binding.subjectSha256 || current.authSha256 !== binding.authSha256) {
6890
- throw new Error("Source authorization changed its bound provider target. Run the provider's explicit rebind transition before syncing.");
6862
+ if (current.subjectSha256 !== binding.subjectSha256 || current.authSha256 !== binding.authSha256 || canonicalJson(current.metadata) !== canonicalJson(binding.metadata)) {
6863
+ throw new Error("Source authorization changed its bound provider target or reviewed metadata. Run the provider's explicit rebind transition before syncing.");
6891
6864
  }
6892
6865
  }
6893
6866
  function bindSourceBinding(database, authority, binding, observedAt) {
6894
- const byAuth = getRow(database, `SELECT binding.id,incarnation.subject_sha256,incarnation.auth_sha256
6867
+ const byAuth = getRow(database, `SELECT binding.id,incarnation.subject_sha256,incarnation.auth_sha256,
6868
+ incarnation.metadata_json
6895
6869
  FROM source_bindings binding
6896
6870
  JOIN current_source_binding_incarnations incarnation
6897
6871
  ON incarnation.source_binding_id=binding.id
@@ -6904,29 +6878,47 @@ function bindSourceBinding(database, authority, binding, observedAt) {
6904
6878
  if (byAuth !== null && (byAuth.subject_sha256 !== binding.subjectSha256 || byAuth.auth_sha256 !== binding.authSha256) || bySubject !== null && (bySubject.auth_id !== binding.authId || bySubject.auth_sha256 !== binding.authSha256)) {
6905
6879
  throw new Error("Source authorization is already bound to a different stable realm.");
6906
6880
  }
6881
+ const metadataJson = canonicalJson(binding.metadata);
6882
+ if (byAuth !== null && byAuth.metadata_json !== metadataJson) {
6883
+ throw new Error("Source authorization changed its reviewed metadata. Run the provider's explicit rebind transition before syncing.");
6884
+ }
6907
6885
  if (byAuth === null) {
6908
6886
  return insertedId(database.query(`INSERT INTO source_bindings(
6909
6887
  authority,auth_id,subject_sha256,auth_sha256,first_seen_at,last_seen_at,metadata_json
6910
- ) VALUES (?,?,?,?,?,?,?)`).run(authority, binding.authId, binding.subjectSha256, binding.authSha256, observedAt, observedAt, canonicalJson(binding.metadata)));
6888
+ ) VALUES (?,?,?,?,?,?,?)`).run(authority, binding.authId, binding.subjectSha256, binding.authSha256, observedAt, observedAt, metadataJson));
6911
6889
  }
6912
6890
  const current = getRow(database, "SELECT last_seen_at FROM source_bindings WHERE id=?", byAuth.id);
6913
6891
  if (current === null) {
6914
6892
  throw new Error("Source authorization disappeared while it was being bound.");
6915
6893
  }
6916
6894
  if (isAtLeastAsRecent(observedAt, current.last_seen_at)) {
6917
- database.query("UPDATE source_bindings SET last_seen_at=?,metadata_json=? WHERE id=?").run(observedAt, canonicalJson(binding.metadata), byAuth.id);
6895
+ database.query("UPDATE source_bindings SET last_seen_at=?,metadata_json=? WHERE id=?").run(observedAt, metadataJson, byAuth.id);
6918
6896
  database.query(`UPDATE source_binding_incarnations SET last_seen_at=?,metadata_json=?
6919
- WHERE source_binding_id=? AND retired_at IS NULL`).run(observedAt, canonicalJson(binding.metadata), byAuth.id);
6897
+ WHERE source_binding_id=? AND retired_at IS NULL`).run(observedAt, metadataJson, byAuth.id);
6920
6898
  }
6921
6899
  return byAuth.id;
6922
6900
  }
6923
- function transitionSourceBinding(database, input) {
6901
+ function commitSourceBindingTransition(database, input, transition) {
6924
6902
  if (input.next.authId !== input.authId) {
6925
6903
  throw new Error("Source binding transition cannot change the authorization ID.");
6926
6904
  }
6927
- if (input.next.subjectSha256 === input.expected.subjectSha256 && input.next.authSha256 === input.expected.authSha256) {
6905
+ const identityChanged = input.next.subjectSha256 !== input.expected.subjectSha256 || input.next.authSha256 !== input.expected.authSha256;
6906
+ const metadataChanged = canonicalJson(input.next.metadata) !== input.expected.metadataJson;
6907
+ if (transition === "identity" && !identityChanged) {
6928
6908
  throw new Error("Source binding transition requires a changed subject or authorization identity.");
6929
6909
  }
6910
+ if (transition === "metadata" && identityChanged) {
6911
+ throw new Error("Source binding metadata transition cannot change subject or authorization identity.");
6912
+ }
6913
+ if (transition === "metadata" && !metadataChanged) {
6914
+ throw new Error("Source binding metadata transition requires changed metadata.");
6915
+ }
6916
+ if (transition === "metadata" && (input.expected.completeRealmInventoryObservedAt === null || input.expected.completeRealmInventorySha256 === null || input.completeRealmInventorySha256 !== input.expected.completeRealmInventorySha256 || input.verifyLocked === undefined)) {
6917
+ throw new Error("Source binding metadata transition requires an exact complete inventory proof.");
6918
+ }
6919
+ if (input.next.subjectSha256 === input.expected.subjectSha256 && input.next.authSha256 === input.expected.authSha256 && canonicalJson(input.next.metadata) === input.expected.metadataJson) {
6920
+ throw new Error("Source binding transition cannot append an unchanged incarnation.");
6921
+ }
6930
6922
  const evidenceJson = canonicalJson(input.evidence);
6931
6923
  if (Buffer.byteLength(evidenceJson, "utf8") > 64 * 1024) {
6932
6924
  throw new Error("Source binding transition evidence exceeds 64 KiB.");
@@ -6978,6 +6970,26 @@ function transitionSourceBinding(database, input) {
6978
6970
  throw error;
6979
6971
  }
6980
6972
  }
6973
+ function transitionSourceBinding(database, input) {
6974
+ return commitSourceBindingTransition(database, input, "identity");
6975
+ }
6976
+ function transitionSourceBindingMetadata(database, input) {
6977
+ return commitSourceBindingTransition(database, {
6978
+ authority: input.authority,
6979
+ authId: input.authId,
6980
+ expected: input.expected,
6981
+ next: {
6982
+ authId: input.authId,
6983
+ subjectSha256: input.expected.subjectSha256,
6984
+ authSha256: input.expected.authSha256,
6985
+ metadata: input.nextMetadata
6986
+ },
6987
+ observedAt: input.observedAt,
6988
+ completeRealmInventorySha256: input.completeRealmInventorySha256,
6989
+ evidence: input.evidence,
6990
+ verifyLocked: input.verifyLocked
6991
+ }, "metadata");
6992
+ }
6981
6993
  function bindSourceRealmCoordinates(database, authority, accountKey, binding, realm, observedAt) {
6982
6994
  const sourceBindingId = bindSourceBinding(database, authority, binding, observedAt);
6983
6995
  const existingRealm = getRow(database, `SELECT id,source_binding_id,identity_namespace,external_id_sha256,state_observed_at
@@ -7440,16 +7452,16 @@ import {
7440
7452
  import { basename as basename2, dirname as dirname3, join as join3, resolve as resolve2 } from "path";
7441
7453
 
7442
7454
  // src/lib/ensoul-contracts.ts
7443
- import { z as z6 } from "zod";
7455
+ import { z as z7 } from "zod";
7444
7456
  var ensoulSourcePacketVersion = "ensoul.source-packet.v1";
7445
7457
  var peoplebladeEnsoulAdapter = "peopleblade";
7446
7458
  var peoplebladeEnsoulPayloadSchema = "ensoul.public-enrichment-source.v1";
7447
7459
  var ensoulDigestCanonicalization = "JCS-RFC8785";
7448
- var digestSchema = z6.string().regex(/^[a-f0-9]{64}$/u);
7449
- var prefixedDigestSchema = z6.string().regex(/^sha256:[a-f0-9]{64}$/u);
7450
- var timestampSchema = z6.iso.datetime({ offset: true });
7451
- var boundedText2 = (maximum) => z6.string().trim().min(1).max(maximum);
7452
- var positiveSafeInteger = z6.number().int().positive().max(Number.MAX_SAFE_INTEGER);
7460
+ var digestSchema = z7.string().regex(/^[a-f0-9]{64}$/u);
7461
+ var prefixedDigestSchema = z7.string().regex(/^sha256:[a-f0-9]{64}$/u);
7462
+ var timestampSchema = z7.iso.datetime({ offset: true });
7463
+ var boundedText2 = (maximum) => z7.string().trim().min(1).max(maximum);
7464
+ var positiveSafeInteger = z7.number().int().positive().max(Number.MAX_SAFE_INTEGER);
7453
7465
  function assertWellFormedUnicode(value) {
7454
7466
  for (let index = 0;index < value.length; index += 1) {
7455
7467
  const code = value.charCodeAt(index);
@@ -7491,7 +7503,7 @@ function ensoulJcsCanonicalJson(value) {
7491
7503
  }
7492
7504
  throw new Error("JCS input is not valid JSON.");
7493
7505
  }
7494
- var ensoulSourceClassSchema = z6.enum([
7506
+ var ensoulSourceClassSchema = z7.enum([
7495
7507
  "private_capture",
7496
7508
  "polished_self_presentation",
7497
7509
  "observed_behavior",
@@ -7500,24 +7512,24 @@ var ensoulSourceClassSchema = z6.enum([
7500
7512
  "metadata",
7501
7513
  "public_web_evidence"
7502
7514
  ]);
7503
- var ensoulSourceRecordSemanticSchema = z6.object({
7515
+ var ensoulSourceRecordSemanticSchema = z7.object({
7504
7516
  id: boundedText2(200),
7505
7517
  kind: boundedText2(100),
7506
7518
  occurredAt: timestampSchema.optional(),
7507
7519
  observedAt: timestampSchema.optional(),
7508
- authorRole: z6.enum(["subject", "counterpart", "third_party", "mixed", "unknown"]),
7509
- contentRole: z6.enum(["original", "quoted", "forwarded", "summary", "ai_assisted", "mixed", "unknown"]),
7510
- authorshipConfidence: z6.enum(["verified", "strong", "weak", "unknown"]),
7511
- sentStatus: z6.enum(["sent", "draft", "received", "published", "unknown"]),
7512
- visibility: z6.enum(["public", "private"]),
7520
+ authorRole: z7.enum(["subject", "counterpart", "third_party", "mixed", "unknown"]),
7521
+ contentRole: z7.enum(["original", "quoted", "forwarded", "summary", "ai_assisted", "mixed", "unknown"]),
7522
+ authorshipConfidence: z7.enum(["verified", "strong", "weak", "unknown"]),
7523
+ sentStatus: z7.enum(["sent", "draft", "received", "published", "unknown"]),
7524
+ visibility: z7.enum(["public", "private"]),
7513
7525
  sourceClass: ensoulSourceClassSchema,
7514
- content: z6.object({
7515
- text: z6.string().max(50000).optional(),
7516
- title: z6.string().max(1000).optional(),
7526
+ content: z7.object({
7527
+ text: z7.string().max(50000).optional(),
7528
+ title: z7.string().max(1000).optional(),
7517
7529
  url: httpUrlSchema.optional(),
7518
- truncated: z6.boolean().optional()
7530
+ truncated: z7.boolean().optional()
7519
7531
  }).strict().refine((content) => content.text !== undefined || content.title !== undefined || content.url !== undefined, "Record content requires text, title, or URL"),
7520
- provenance: z6.object({
7532
+ provenance: z7.object({
7521
7533
  provider: boundedText2(100),
7522
7534
  operation: boundedText2(160).optional(),
7523
7535
  sourceId: boundedText2(300).optional(),
@@ -7530,17 +7542,17 @@ var ensoulSourceRecordSemanticSchema = z6.object({
7530
7542
  var ensoulSourceRecordSchema = ensoulSourceRecordSemanticSchema.extend({
7531
7543
  digest: prefixedDigestSchema
7532
7544
  }).strict();
7533
- var ensoulClaimSchema = z6.object({
7545
+ var ensoulClaimSchema = z7.object({
7534
7546
  id: boundedText2(200),
7535
7547
  text: boundedText2(4000),
7536
- recordIds: z6.array(boundedText2(200)).min(1).max(50).refine((values) => new Set(values).size === values.length, "Claim record IDs must be unique"),
7537
- status: z6.enum(["source_reported", "adapter_structured", "contested"]),
7538
- claimantRole: z6.enum(["subject", "counterpart", "third_party", "institutional", "adapter", "unknown"]),
7539
- claimKind: z6.enum(["fact", "stated_belief", "reported_observation", "derived_index"]),
7548
+ recordIds: z7.array(boundedText2(200)).min(1).max(50).refine((values) => new Set(values).size === values.length, "Claim record IDs must be unique"),
7549
+ status: z7.enum(["source_reported", "adapter_structured", "contested"]),
7550
+ claimantRole: z7.enum(["subject", "counterpart", "third_party", "institutional", "adapter", "unknown"]),
7551
+ claimKind: z7.enum(["fact", "stated_belief", "reported_observation", "derived_index"]),
7540
7552
  subjectLocalId: boundedText2(200),
7541
- sensitivity: z6.enum(["ordinary", "sensitive_explicit"])
7553
+ sensitivity: z7.enum(["ordinary", "sensitive_explicit"])
7542
7554
  }).strict();
7543
- var ensoulLimitationSchema = z6.enum([
7555
+ var ensoulLimitationSchema = z7.enum([
7544
7556
  "Public-web evidence plus bounded local subject background only; this packet is not a complete account of the person.",
7545
7557
  "Web authorship is unknown; no record is a direct subject voice sample.",
7546
7558
  "Private messages and CRM notes are excluded.",
@@ -7548,41 +7560,41 @@ var ensoulLimitationSchema = z6.enum([
7548
7560
  "Raw provider payloads, credentials, and unrelated contacts are excluded.",
7549
7561
  "Do not infer sensitive traits, diagnoses, consent, or permission to act from this packet."
7550
7562
  ]);
7551
- var peoplebladeEnsoulPacketBodySchema = z6.object({
7552
- schemaVersion: z6.literal(ensoulSourcePacketVersion),
7553
- digestCanonicalization: z6.literal(ensoulDigestCanonicalization),
7563
+ var peoplebladeEnsoulPacketBodySchema = z7.object({
7564
+ schemaVersion: z7.literal(ensoulSourcePacketVersion),
7565
+ digestCanonicalization: z7.literal(ensoulDigestCanonicalization),
7554
7566
  generatedAt: timestampSchema,
7555
- subject: z6.object({
7567
+ subject: z7.object({
7556
7568
  localId: boundedText2(200),
7557
- kind: z6.literal("person"),
7569
+ kind: z7.literal("person"),
7558
7570
  displayName: boundedText2(300).optional(),
7559
7571
  identityBasis: boundedText2(1000)
7560
7572
  }).strict(),
7561
- scope: z6.object({
7562
- adapter: z6.literal(peoplebladeEnsoulAdapter),
7563
- payloadSchema: z6.literal(peoplebladeEnsoulPayloadSchema),
7573
+ scope: z7.object({
7574
+ adapter: z7.literal(peoplebladeEnsoulAdapter),
7575
+ payloadSchema: z7.literal(peoplebladeEnsoulPayloadSchema),
7564
7576
  asOf: timestampSchema,
7565
7577
  sourceCutoff: timestampSchema.optional(),
7566
- completeness: z6.enum(["complete", "sampled", "bounded", "unknown"]),
7578
+ completeness: z7.enum(["complete", "sampled", "bounded", "unknown"]),
7567
7579
  sourceRevision: boundedText2(300),
7568
- limits: z6.object({
7580
+ limits: z7.object({
7569
7581
  maxCurrentEnrichments: positiveSafeInteger,
7570
7582
  maxRecords: positiveSafeInteger,
7571
7583
  maxClaims: positiveSafeInteger,
7572
7584
  maxPacketBytes: positiveSafeInteger,
7573
7585
  oldestObservedAt: timestampSchema.nullable(),
7574
- exactContactCoordinates: z6.literal("excluded-or-redacted"),
7575
- notes: z6.literal("excluded"),
7576
- messages: z6.literal("excluded"),
7577
- rawProviderPayloads: z6.literal("excluded")
7586
+ exactContactCoordinates: z7.literal("excluded-or-redacted"),
7587
+ notes: z7.literal("excluded"),
7588
+ messages: z7.literal("excluded"),
7589
+ rawProviderPayloads: z7.literal("excluded")
7578
7590
  }).strict()
7579
7591
  }).strict(),
7580
- records: z6.array(ensoulSourceRecordSchema).max(2000),
7581
- claims: z6.array(ensoulClaimSchema).max(500),
7582
- limitations: z6.array(ensoulLimitationSchema).min(1).max(32)
7592
+ records: z7.array(ensoulSourceRecordSchema).max(2000),
7593
+ claims: z7.array(ensoulClaimSchema).max(500),
7594
+ limitations: z7.array(ensoulLimitationSchema).min(1).max(32)
7583
7595
  }).strict();
7584
7596
  var peoplebladeEnsoulPacketSemanticSchema = peoplebladeEnsoulPacketBodySchema.extend({
7585
- packetId: z6.string().trim().min(8).max(160)
7597
+ packetId: z7.string().trim().min(8).max(160)
7586
7598
  }).strict();
7587
7599
  var ensoulSourcePacketSchema = peoplebladeEnsoulPacketSemanticSchema.extend({
7588
7600
  packetDigest: prefixedDigestSchema
@@ -10158,15 +10170,15 @@ function syncAppleContacts(database, options = {}) {
10158
10170
  }
10159
10171
 
10160
10172
  // src/local/source-ingestion.ts
10161
- import { z as z7 } from "zod";
10162
- var providerSchema = z7.string().regex(/^[a-z][a-z0-9-]{0,63}$/u);
10163
- var boundedText3 = (maximum) => z7.string().min(1).max(maximum).refine((value) => !/[\u0000\r]/u.test(value), "Text contains an unsupported control character");
10173
+ import { z as z8 } from "zod";
10174
+ var providerSchema = z8.string().regex(/^[a-z][a-z0-9-]{0,63}$/u);
10175
+ var boundedText3 = (maximum) => z8.string().min(1).max(maximum).refine((value) => !/[\u0000\r]/u.test(value), "Text contains an unsupported control character");
10164
10176
  var nullableText3 = (maximum) => boundedText3(maximum).nullable();
10165
- var digestSchema2 = z7.string().regex(/^[a-f0-9]{64}$/u);
10166
- var timestampSchema2 = z7.iso.datetime({ offset: true });
10177
+ var digestSchema2 = z8.string().regex(/^[a-f0-9]{64}$/u);
10178
+ var timestampSchema2 = z8.iso.datetime({ offset: true });
10167
10179
  var sqliteNoCase = (value) => value.replace(/[A-Z]/gu, (character) => character.toLowerCase());
10168
- var jsonObjectSchema = z7.record(z7.string(), z7.json()).refine((value) => Buffer.byteLength(canonicalJson(value), "utf8") <= 64 * 1024, "Metadata exceeds 64 KiB");
10169
- var personSchema = z7.object({
10180
+ var jsonObjectSchema = z8.record(z8.string(), z8.json()).refine((value) => Buffer.byteLength(canonicalJson(value), "utf8") <= 64 * 1024, "Metadata exceeds 64 KiB");
10181
+ var personSchema = z8.object({
10170
10182
  displayName: nullableText3(1024),
10171
10183
  givenName: nullableText3(1024),
10172
10184
  middleName: nullableText3(1024),
@@ -10179,16 +10191,16 @@ var personSchema = z7.object({
10179
10191
  title: nullableText3(1024),
10180
10192
  birthday: birthdaySchema,
10181
10193
  observationBasis: boundedText3(128),
10182
- observationPriority: z7.number().int().min(0).max(1000),
10194
+ observationPriority: z8.number().int().min(0).max(1000),
10183
10195
  metadata: jsonObjectSchema
10184
10196
  }).strict();
10185
- var resourceSchema = z7.object({
10197
+ var resourceSchema = z8.object({
10186
10198
  type: boundedText3(64),
10187
10199
  id: boundedText3(4096),
10188
10200
  username: nullableText3(2048),
10189
10201
  profileUrl: nullableText3(4096),
10190
- profileUrlIdentityEligible: z7.boolean(),
10191
- nameIdentityEligible: z7.boolean(),
10202
+ profileUrlIdentityEligible: z8.boolean(),
10203
+ nameIdentityEligible: z8.boolean(),
10192
10204
  displayName: nullableText3(2048),
10193
10205
  metadata: jsonObjectSchema
10194
10206
  }).strict().superRefine((resource, context) => {
@@ -10199,20 +10211,20 @@ var resourceSchema = z7.object({
10199
10211
  message: "An identity-eligible profile URL must be a stored HTTP(S) profile URL"
10200
10212
  });
10201
10213
  });
10202
- var methodSchema = z7.object({
10203
- kind: z7.enum(["email", "phone", "url", "address", "date", "social", "other"]),
10214
+ var methodSchema = z8.object({
10215
+ kind: z8.enum(["email", "phone", "url", "address", "date", "social", "other"]),
10204
10216
  value: boundedText3(8192),
10205
10217
  normalizedValue: boundedText3(8192),
10206
- label: z7.string().max(256),
10207
- primary: z7.boolean(),
10208
- confidence: z7.enum(["exact", "likely", "possible", "unknown"]),
10209
- identityEligible: z7.boolean(),
10218
+ label: z8.string().max(256),
10219
+ primary: z8.boolean(),
10220
+ confidence: z8.enum(["exact", "likely", "possible", "unknown"]),
10221
+ identityEligible: z8.boolean(),
10210
10222
  metadata: jsonObjectSchema
10211
10223
  }).strict();
10212
- var contactSchema = z7.object({
10224
+ var contactSchema = z8.object({
10213
10225
  person: personSchema,
10214
10226
  resource: resourceSchema,
10215
- methods: z7.array(methodSchema).max(1000)
10227
+ methods: z8.array(methodSchema).max(1000)
10216
10228
  }).strict().superRefine((contact, context) => {
10217
10229
  const coordinates = new Set;
10218
10230
  contact.methods.forEach((method, index) => {
@@ -10223,24 +10235,24 @@ var contactSchema = z7.object({
10223
10235
  coordinates.add(coordinate);
10224
10236
  });
10225
10237
  });
10226
- var completenessSchema = z7.enum(["complete", "partial", "lower-bound", "unknown"]);
10227
- var coverageSchema = z7.object({
10228
- localEnumerationComplete: z7.boolean(),
10229
- remoteSetComplete: z7.boolean(),
10230
- truncated: z7.boolean(),
10231
- absencePolicy: z7.enum(["reconcile-observed", "preserve"]),
10232
- warnings: z7.array(boundedText3(128)).max(32)
10238
+ var completenessSchema = z8.enum(["complete", "partial", "lower-bound", "unknown"]);
10239
+ var coverageSchema = z8.object({
10240
+ localEnumerationComplete: z8.boolean(),
10241
+ remoteSetComplete: z8.boolean(),
10242
+ truncated: z8.boolean(),
10243
+ absencePolicy: z8.enum(["reconcile-observed", "preserve"]),
10244
+ warnings: z8.array(boundedText3(128)).max(32)
10233
10245
  }).strict();
10234
- var interactionSchema = z7.object({
10246
+ var interactionSchema = z8.object({
10235
10247
  resourceType: boundedText3(64),
10236
10248
  resourceId: boundedText3(4096),
10237
- sentCount: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
10238
- receivedCount: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
10239
- interactionCount: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
10240
- conversationCount: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable(),
10249
+ sentCount: z8.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
10250
+ receivedCount: z8.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
10251
+ interactionCount: z8.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
10252
+ conversationCount: z8.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable(),
10241
10253
  firstInteractionAt: timestampSchema2.nullable(),
10242
10254
  lastInteractionAt: timestampSchema2.nullable(),
10243
- reciprocal: z7.boolean(),
10255
+ reciprocal: z8.boolean(),
10244
10256
  completeness: completenessSchema,
10245
10257
  metadata: jsonObjectSchema
10246
10258
  }).strict().superRefine((interaction, context) => {
@@ -10253,32 +10265,32 @@ var interactionSchema = z7.object({
10253
10265
  if (interaction.interactionCount === 0 && (interaction.firstInteractionAt !== null || interaction.lastInteractionAt !== null) || interaction.interactionCount > 0 && (interaction.firstInteractionAt === null || interaction.lastInteractionAt === null) || interaction.firstInteractionAt !== null && interaction.lastInteractionAt !== null && Date.parse(interaction.firstInteractionAt) > Date.parse(interaction.lastInteractionAt))
10254
10266
  context.addIssue({ code: "custom", path: ["firstInteractionAt"], message: "Interaction timestamps do not match the observed count" });
10255
10267
  });
10256
- var sourceBindingSchema = z7.object({
10268
+ var sourceBindingSchema = z8.object({
10257
10269
  authId: boundedText3(128),
10258
10270
  authSha256: digestSchema2,
10259
10271
  subjectSha256: digestSchema2,
10260
10272
  metadata: jsonObjectSchema
10261
10273
  }).strict();
10262
- var sourceRealmSchema = z7.object({
10274
+ var sourceRealmSchema = z8.object({
10263
10275
  service: boundedText3(64),
10264
10276
  identityNamespace: boundedText3(128),
10265
10277
  externalIdSha256: digestSchema2,
10266
10278
  metadata: jsonObjectSchema
10267
10279
  }).strict();
10268
- var sourceRealmInventoryEntrySchema = z7.object({
10280
+ var sourceRealmInventoryEntrySchema = z8.object({
10269
10281
  accountKey: boundedText3(256),
10270
10282
  sourceRealm: sourceRealmSchema
10271
10283
  }).strict();
10272
- var sourceRealmInventorySchema = z7.object({
10273
- schemaVersion: z7.literal(1),
10284
+ var sourceRealmInventorySchema = z8.object({
10285
+ schemaVersion: z8.literal(1),
10274
10286
  provider: providerSchema,
10275
10287
  observedAt: timestampSchema2,
10276
10288
  sourceBinding: sourceBindingSchema,
10277
- localEnumerationComplete: z7.boolean(),
10278
- truncated: z7.boolean(),
10279
- absencePolicy: z7.enum(["reconcile-observed", "preserve"]),
10280
- realms: z7.array(sourceRealmInventoryEntrySchema).max(128),
10281
- warnings: z7.array(boundedText3(128)).max(32)
10289
+ localEnumerationComplete: z8.boolean(),
10290
+ truncated: z8.boolean(),
10291
+ absencePolicy: z8.enum(["reconcile-observed", "preserve"]),
10292
+ realms: z8.array(sourceRealmInventoryEntrySchema).max(128),
10293
+ warnings: z8.array(boundedText3(128)).max(32)
10282
10294
  }).strict().superRefine((inventory, context) => {
10283
10295
  if (inventory.absencePolicy === "reconcile-observed" && (!inventory.localEnumerationComplete || inventory.truncated)) {
10284
10296
  context.addIssue({
@@ -10301,8 +10313,8 @@ var sourceRealmInventorySchema = z7.object({
10301
10313
  externalIds.add(entry.sourceRealm.externalIdSha256);
10302
10314
  });
10303
10315
  });
10304
- var contactSourceSnapshotSchema = z7.object({
10305
- schemaVersion: z7.literal(1),
10316
+ var contactSourceSnapshotSchema = z8.object({
10317
+ schemaVersion: z8.literal(1),
10306
10318
  provider: providerSchema,
10307
10319
  accountKey: boundedText3(256),
10308
10320
  mode: boundedText3(64),
@@ -10313,8 +10325,8 @@ var contactSourceSnapshotSchema = z7.object({
10313
10325
  observedAt: timestampSchema2,
10314
10326
  sourceBinding: sourceBindingSchema,
10315
10327
  sourceRealm: sourceRealmSchema,
10316
- contacts: z7.array(contactSchema).max(250000),
10317
- interactions: z7.array(interactionSchema).max(250000),
10328
+ contacts: z8.array(contactSchema).max(250000),
10329
+ interactions: z8.array(interactionSchema).max(250000),
10318
10330
  metadata: jsonObjectSchema
10319
10331
  }).strict().superRefine((snapshot, context) => {
10320
10332
  if (snapshot.coverage.absencePolicy === "reconcile-observed" && (!snapshot.coverage.localEnumerationComplete || snapshot.coverage.truncated)) {
@@ -10354,19 +10366,19 @@ function resourceStableKey(snapshot, resource) {
10354
10366
  return `source:${sha256(canonicalJson([snapshot.provider, snapshot.accountKey, resource.type, resource.id]))}`;
10355
10367
  }
10356
10368
  function parseCachedResult(value) {
10357
- return z7.object({
10358
- account_key: z7.string(),
10359
- source_rows: z7.number().int(),
10360
- people_created: z7.number().int(),
10361
- people_matched: z7.number().int(),
10362
- methods_touched: z7.number().int(),
10363
- interactions_touched: z7.number().int(),
10364
- resources_removed: z7.number().int(),
10365
- reconciled: z7.boolean(),
10369
+ return z8.object({
10370
+ account_key: z8.string(),
10371
+ source_rows: z8.number().int(),
10372
+ people_created: z8.number().int(),
10373
+ people_matched: z8.number().int(),
10374
+ methods_touched: z8.number().int(),
10375
+ interactions_touched: z8.number().int(),
10376
+ resources_removed: z8.number().int(),
10377
+ reconciled: z8.boolean(),
10366
10378
  completeness: completenessSchema,
10367
- local_enumeration_complete: z7.boolean(),
10368
- remote_set_complete: z7.boolean(),
10369
- truncated: z7.boolean()
10379
+ local_enumeration_complete: z8.boolean(),
10380
+ remote_set_complete: z8.boolean(),
10381
+ truncated: z8.boolean()
10370
10382
  }).strict().transform((result) => ({ ...result, cached: true })).parse(JSON.parse(value));
10371
10383
  }
10372
10384
  function bindSourceRealm(database, snapshot) {
@@ -11994,8 +12006,8 @@ function invokeCapabilitySync(request, options = {}) {
11994
12006
  return parsed.live;
11995
12007
  }
11996
12008
 
11997
- // node_modules/@hraness/wrench/dist/index-q9xsrgw8.js
11998
- var WRENCH_VERSION = "0.16.7";
12009
+ // node_modules/@hraness/wrench/dist/index-j1f3cp88.js
12010
+ var WRENCH_VERSION = "0.16.8";
11999
12011
 
12000
12012
  // node_modules/@hraness/wrench/dist/beeper-client.js
12001
12013
  import { spawnSync as spawnSync2 } from "child_process";
@@ -16980,8 +16992,8 @@ function projectBeeperContactInteractions(summary, coordinates) {
16980
16992
  // src/local/providers/beeper-compatibility.ts
16981
16993
  var BEEPER_WRENCH_COMPATIBILITY = Object.freeze({
16982
16994
  wrench: Object.freeze({
16983
- version: "0.16.7",
16984
- commit: "a2b321081335ac28e5df0ccbb67ebea0424d49f5"
16995
+ version: "0.16.8",
16996
+ commit: "b0cf2ecbc1113fcc8ef673a824be475c3d7bbb46"
16985
16997
  }),
16986
16998
  adapter: Object.freeze({
16987
16999
  id: "beeper-local",
@@ -17018,6 +17030,22 @@ var BEEPER_WRENCH_COMPATIBILITY = Object.freeze({
17018
17030
  commit: "b9c1714410139c2139b597338cd002d785653e85"
17019
17031
  })
17020
17032
  });
17033
+ var PEOPLEBLADE_010_WRENCH_0150_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
17034
+ transport: "local-cli",
17035
+ wrenchVersion: "0.15.0",
17036
+ wrenchCommit: "41b16fcbf9ed0e8d8a332aa380b7187642aac2e3",
17037
+ adapterId: "beeper-local",
17038
+ adapterVersion: "2.0.0",
17039
+ adapterSha256: "e0e1adb52a667af64289db74bad0016753fff2e9fc784ed3cdaae457eb1f19c6",
17040
+ cliId: "beeper-cli",
17041
+ cliVersion: "0.6.2",
17042
+ cliCommit: "a416af06023449a87312dc11e54643fd9dc94b8c",
17043
+ contracts: Object.freeze({
17044
+ contactsList: "eac1536860bc19ff8b9c59abe44c33414ee559e9c550be9d1185ed8375e27d7f",
17045
+ contactsSearch: "bc88cfbca7b8bd9cf5f297cb7d3c922d70dedcaf6d5000e20ed97f9e7b864482",
17046
+ messagingSearch: "27196d8d2cc5eeb855d61d8e27134e81dc56b64f20ea8033d4406c959dffd6f6"
17047
+ })
17048
+ });
17021
17049
  var PREVIOUS_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
17022
17050
  transport: "local-cli",
17023
17051
  wrenchVersion: "0.16.6",
@@ -17066,6 +17094,22 @@ var LEGACY_WRENCH_0167_SEARCH_V1_SOURCE_BINDING_METADATA = Object.freeze({
17066
17094
  messagingSearch: "27b45f4fd370bddaf94c991bf65393556f246fc466c17a360689e467539e41c2"
17067
17095
  })
17068
17096
  });
17097
+ var PREVIOUS_WRENCH_0167_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
17098
+ transport: "local-cli",
17099
+ wrenchVersion: "0.16.7",
17100
+ wrenchCommit: "a2b321081335ac28e5df0ccbb67ebea0424d49f5",
17101
+ adapterId: "beeper-local",
17102
+ adapterVersion: "2.4.0",
17103
+ adapterSha256: "2714af7e821b799c1d0b57106e8e193cb9787e5a6da37e1269f4aae0710a4ddc",
17104
+ cliId: "beeper-cli",
17105
+ cliVersion: "0.6.2",
17106
+ cliCommit: "a416af06023449a87312dc11e54643fd9dc94b8c",
17107
+ contracts: Object.freeze({
17108
+ contactsList: "8048565547c2a09078528d0a35f7a0c3a2e8850b17b075dc572e8b59115fcb57",
17109
+ contactsSearch: "e57cdcc9012ed5fb8f956e16a2368e95adf0a6b8bb404f903e64df85061b1ca1",
17110
+ messagingSearch: "2fc54d139a54d19c31a82237e4b417994e12679db3da5fd71ec9265e3622b0bf"
17111
+ })
17112
+ });
17069
17113
  var LEGACY_BEEPER_WRENCH_COMPATIBILITY = Object.freeze({
17070
17114
  wrenchVersion: "0.14.0",
17071
17115
  adapterId: "beeper-local",
@@ -17523,6 +17567,9 @@ function classifyReviewedBeeperPredecessor(value, currentMetadata) {
17523
17567
  if (isLegacyBindingMetadata(value))
17524
17568
  return "wrench-0.14-beeper-1.1";
17525
17569
  const encoded = canonicalJson(value);
17570
+ if (encoded === canonicalJson(PEOPLEBLADE_010_WRENCH_0150_BEEPER_SOURCE_BINDING_METADATA)) {
17571
+ return "peopleblade-0.1.0-wrench-0.15-beeper-2.0";
17572
+ }
17526
17573
  if (encoded === canonicalJson(LEGACY_MISLABELED_BEEPER_SOURCE_BINDING_METADATA)) {
17527
17574
  return "peopleblade-pre-0.1.1-mislabeled-beeper-search";
17528
17575
  }
@@ -17532,8 +17579,11 @@ function classifyReviewedBeeperPredecessor(value, currentMetadata) {
17532
17579
  if (encoded === canonicalJson(LEGACY_WRENCH_0167_SEARCH_V1_SOURCE_BINDING_METADATA)) {
17533
17580
  return "wrench-0.16.7-beeper-2.4-search-v1";
17534
17581
  }
17535
- if (encoded === currentMetadata)
17582
+ if (encoded === canonicalJson(PREVIOUS_WRENCH_0167_BEEPER_SOURCE_BINDING_METADATA)) {
17536
17583
  return "wrench-0.16.7-beeper-2.4";
17584
+ }
17585
+ if (encoded === currentMetadata)
17586
+ return "wrench-0.16.8-beeper-2.4";
17537
17587
  return null;
17538
17588
  }
17539
17589
  function assertStoredRealmInventory(database, sourceBindingId, accounts, storedSha256) {
@@ -17596,10 +17646,9 @@ function rebindBeeperSource(database, options = {}) {
17596
17646
  }
17597
17647
  const verifiedInventorySha256 = assertStoredRealmInventory(database, current.id, inventory.accounts, current.completeRealmInventorySha256);
17598
17648
  const currentMetadata = canonicalJson(beeperSourceBindingMetadata());
17599
- if (current.subjectSha256 === next.subjectSha256 && current.authSha256 === next.authSha256) {
17600
- if (canonicalJson(current.metadata) !== currentMetadata) {
17601
- throw new Error("Current Beeper binding metadata does not match the pinned Wrench route.");
17602
- }
17649
+ const sameIdentity = current.subjectSha256 === next.subjectSha256 && current.authSha256 === next.authSha256;
17650
+ const storedMetadata = canonicalJson(current.metadata);
17651
+ if (sameIdentity && storedMetadata === currentMetadata) {
17603
17652
  return {
17604
17653
  transitioned: false,
17605
17654
  source_binding_id: current.id,
@@ -17613,6 +17662,10 @@ function rebindBeeperSource(database, options = {}) {
17613
17662
  if (predecessor === null) {
17614
17663
  throw new Error("Beeper rebind source coordinates are not a reviewed predecessor.");
17615
17664
  }
17665
+ const metadataOnly = sameIdentity && (predecessor === "peopleblade-0.1.0-wrench-0.15-beeper-2.0" || predecessor === "wrench-0.16.7-beeper-2.4");
17666
+ if (sameIdentity && !metadataOnly) {
17667
+ throw new Error("Beeper metadata-only rebind requires an exact reviewed same-identity predecessor.");
17668
+ }
17616
17669
  if (predecessor === "wrench-0.14-beeper-1.1") {
17617
17670
  assertLegacyBeeperReceipt(database, current);
17618
17671
  const derivedLegacySubjectSha256 = sha256(legacyBeeperAccountSubject(inventory.accounts));
@@ -17622,7 +17675,7 @@ function rebindBeeperSource(database, options = {}) {
17622
17675
  }
17623
17676
  const evidence = {
17624
17677
  schemaVersion: 1,
17625
- kind: "beeper-source-binding-rebind",
17678
+ kind: metadataOnly ? "beeper-source-binding-metadata-rebind" : "beeper-source-binding-rebind",
17626
17679
  authority: PROVIDER4,
17627
17680
  authId,
17628
17681
  sourceBindingId: current.id,
@@ -17653,25 +17706,36 @@ function rebindBeeperSource(database, options = {}) {
17653
17706
  finishedAt: inventory.execution.finishedAt
17654
17707
  }
17655
17708
  };
17656
- const result = transitionSourceBinding(database, {
17709
+ const expected = {
17710
+ subjectSha256: current.subjectSha256,
17711
+ authSha256: current.authSha256,
17712
+ incarnationId: current.incarnationId,
17713
+ lastSeenAt: current.lastSeenAt,
17714
+ metadataJson: storedMetadata,
17715
+ completeRealmInventoryObservedAt: current.completeRealmInventoryObservedAt,
17716
+ completeRealmInventorySha256: current.completeRealmInventorySha256
17717
+ };
17718
+ const verifyLocked = () => {
17719
+ assertStoredRealmInventory(database, current.id, inventory.accounts, current.completeRealmInventorySha256);
17720
+ };
17721
+ const result = metadataOnly ? transitionSourceBindingMetadata(database, {
17657
17722
  authority: PROVIDER4,
17658
17723
  authId,
17659
- expected: {
17660
- subjectSha256: current.subjectSha256,
17661
- authSha256: current.authSha256,
17662
- incarnationId: current.incarnationId,
17663
- lastSeenAt: current.lastSeenAt,
17664
- metadataJson: canonicalJson(current.metadata),
17665
- completeRealmInventoryObservedAt: current.completeRealmInventoryObservedAt,
17666
- completeRealmInventorySha256: current.completeRealmInventorySha256
17667
- },
17724
+ expected,
17725
+ nextMetadata: next.metadata,
17726
+ observedAt: inventory.execution.finishedAt,
17727
+ completeRealmInventorySha256: verifiedInventorySha256,
17728
+ evidence,
17729
+ verifyLocked
17730
+ }) : transitionSourceBinding(database, {
17731
+ authority: PROVIDER4,
17732
+ authId,
17733
+ expected,
17668
17734
  next,
17669
17735
  observedAt: inventory.execution.finishedAt,
17670
17736
  completeRealmInventorySha256: verifiedInventorySha256,
17671
17737
  evidence,
17672
- verifyLocked: () => {
17673
- assertStoredRealmInventory(database, current.id, inventory.accounts, current.completeRealmInventorySha256);
17674
- }
17738
+ verifyLocked
17675
17739
  });
17676
17740
  return {
17677
17741
  transitioned: true,
@@ -17694,9 +17758,9 @@ function syncBeeperContacts(database, options = {}) {
17694
17758
  }, options.invoke);
17695
17759
  const inventoryInput = { limit: 1 };
17696
17760
  const inventory = parseBeeperContactPage(invoke(inventoryInput), inventoryInput, authId);
17697
- ledgerBeeperContactRead(database, `beeper:binding:${sha256(inventory.accountSubject)}`, inventory);
17698
17761
  const inventoryBinding = sourceBinding(inventory, authId);
17699
17762
  assertSourceBindingCurrent(database, PROVIDER4, inventoryBinding);
17763
+ ledgerBeeperContactRead(database, `beeper:binding:${sha256(inventory.accountSubject)}`, inventory);
17700
17764
  const inventorySha256 = accountInventorySha256(inventory.accounts);
17701
17765
  const orderedAccounts = [...inventory.accounts].sort((left, right) => {
17702
17766
  const serviceOrder = normalizeService(left).localeCompare(normalizeService(right));
@@ -18362,6 +18426,12 @@ function backfillBeeperSearch(database, options) {
18362
18426
  const invoke = (operation, input) => callPeopleBladeWrench({ adapterId: ADAPTER_ID2, operationId: operation, authId, input }, options.invoke);
18363
18427
  const inventoryInput = { limit: 1 };
18364
18428
  const inventory = parseBeeperContactPage(invoke("contacts.list", inventoryInput), inventoryInput, authId);
18429
+ assertSourceBindingCurrent(database, PROVIDER5, {
18430
+ authId,
18431
+ authSha256: inventory.execution.authSha256,
18432
+ subjectSha256: sha256(inventory.accountSubject),
18433
+ metadata: beeperSourceBindingMetadata()
18434
+ });
18365
18435
  let executionReceiptsRecorded = 0;
18366
18436
  if (!ledgerPeopleBladeWrenchInvocation(database, {
18367
18437
  provider: PROVIDER5,
@@ -18372,12 +18442,6 @@ function backfillBeeperSearch(database, options) {
18372
18442
  metadata: { subjectSha256: sha256(inventory.accountSubject) }
18373
18443
  }).replayed)
18374
18444
  executionReceiptsRecorded += 1;
18375
- assertSourceBindingCurrent(database, PROVIDER5, {
18376
- authId,
18377
- authSha256: inventory.execution.authSha256,
18378
- subjectSha256: sha256(inventory.accountSubject),
18379
- metadata: beeperSourceBindingMetadata()
18380
- });
18381
18445
  const accounts = [...inventory.accounts].filter((account) => requestedServices === null || requestedServices.has(normalizeService2(account))).sort((left, right) => normalizeService2(left).localeCompare(normalizeService2(right)) || left.accountId.localeCompare(right.accountId));
18382
18446
  if (requestedServices !== null) {
18383
18447
  const found = new Set(accounts.map(normalizeService2));
@@ -23924,7 +23988,7 @@ function syncWhatsAppRelationships(database, options = {}) {
23924
23988
  }
23925
23989
 
23926
23990
  // src/cli/version.ts
23927
- var peoplebladeVersion = "0.1.1";
23991
+ var peoplebladeVersion = "0.1.2";
23928
23992
 
23929
23993
  // src/cli/main.ts
23930
23994
  var usage = `PeopleBlade \u2014 local-first contact intelligence
@@ -24500,7 +24564,7 @@ ${verification}`) });
24500
24564
  if (options.length)
24501
24565
  fail3(`Unknown argument: ${options[0]}`);
24502
24566
  if (!confirm)
24503
- fail3("beeper rebind requires --confirm after reviewing the Wrench force-rebind and connected-account inventory.");
24567
+ fail3("beeper rebind requires --confirm after reviewing the current Wrench binding, release, and connected-account inventory.");
24504
24568
  console.error("Beeper binding \xB7 verifying the complete connected-account inventory before an append-only transition");
24505
24569
  print(rebindBeeperSource(database, { ...authId3 === undefined ? {} : { authId: authId3 } }), asJson);
24506
24570
  return;