primitive 1.72.2 → 1.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { c as classifySignalContent, y as isTrustedSender } from "./repeats-BL7ZC-_6-CKMKBlx7.js";
1
+ import { b as retryTransient, c as classifySignalContent, q as isTrustedSender } from "./repeats-BL7ZC-_6-B_ESsWTH.js";
2
2
  //#region src/oclif/presence-provenance.ts
3
3
  function readPresenceProjection(detail) {
4
4
  if (!detail || typeof detail !== "object") return null;
@@ -50,6 +50,14 @@ async function readBeforeDeadline(deadline, read) {
50
50
  clearTimeout(timer);
51
51
  }
52
52
  }
53
+ /**
54
+ * readBeforeDeadline for a generated-client read inside a wait: a rate
55
+ * limit, gateway failure or network error is retried with backoff until the
56
+ * deadline instead of being returned. Null when the deadline passes.
57
+ */
58
+ function readApiBeforeDeadline(deadline, read) {
59
+ return retryTransient(() => readBeforeDeadline(deadline, read), { deadline });
60
+ }
53
61
  function address(value) {
54
62
  return value.trim().toLowerCase();
55
63
  }
@@ -89,4 +97,4 @@ function isPlainChatReply(detail) {
89
97
  }).classification === "plain";
90
98
  }
91
99
  //#endregion
92
- export { scopedChatSenderTrust as a, readBeforeDeadline as i, isPlainChatReply as n, presenceDisposition as o, isScopedChatReply as r, readPresenceProjection as s, isConnectedChatCredential as t };
100
+ export { readBeforeDeadline as a, readPresenceProjection as c, readApiBeforeDeadline as i, isPlainChatReply as n, scopedChatSenderTrust as o, isScopedChatReply as r, presenceDisposition as s, isConnectedChatCredential as t };
@@ -125,6 +125,26 @@ function removeOwner(path, owner) {
125
125
  ].includes(error.code ?? "")) throw error;
126
126
  }
127
127
  }
128
+ /**
129
+ * True while a live process holds the lock {@link acquireListenLock} takes
130
+ * for this directory and scope. Read-only; a lock whose owner exited, or
131
+ * whose owner record cannot be read, counts as free.
132
+ */
133
+ function listenLockHeld(directory, scope) {
134
+ const key = createHash("sha256").update(scope).digest("hex");
135
+ const path = join(directory, `${key}.lock`);
136
+ try {
137
+ const entries = readdirSync(path);
138
+ const match = entries.length === 1 ? /^(\d+)-[a-f0-9-]{36}$/.exec(entries[0] ?? "") : null;
139
+ if (!match) return false;
140
+ const pid = Number(match[1]);
141
+ if (!processAlive(pid)) return false;
142
+ const saved = ownerIdentity(join(path, entries[0] ?? ""));
143
+ return compareListenProcessIdentity(saved, saved === null ? null : listenProcessIdentity(pid)) !== false;
144
+ } catch {
145
+ return false;
146
+ }
147
+ }
128
148
  function acquireListenLock(directory, scope) {
129
149
  privateDirectory(directory);
130
150
  const key = createHash("sha256").update(scope).digest("hex");
@@ -352,4 +372,4 @@ function mailTime(value) {
352
372
  return new Date(time).toISOString();
353
373
  }
354
374
  //#endregion
355
- export { resolveListenSubscription as S, acquireListenLock as _, mailLockBusy as a, listenProcessIdentity as b, mailTime as c, readMailJson as d, removeMailFile as f, ListenStateError as g, writeMailJson as h, mailId as i, privateMailDirectory as l, withMailLock as m, invalidSharedMail as n, mailObject as o, syncMailDirectory as p, mailAddress as r, mailString as s, SharedMailStateError as t, privateMailPermissions as u, compareListenProcessIdentity as v, normalizeListenOrigin as x, listenIdentity as y };
375
+ export { resolveListenSubscription as C, normalizeListenOrigin as S, acquireListenLock as _, mailLockBusy as a, listenLockHeld as b, mailTime as c, readMailJson as d, removeMailFile as f, ListenStateError as g, writeMailJson as h, mailId as i, privateMailDirectory as l, withMailLock as m, invalidSharedMail as n, mailObject as o, syncMailDirectory as p, mailAddress as r, mailString as s, SharedMailStateError as t, privateMailPermissions as u, compareListenProcessIdentity as v, listenProcessIdentity as x, listenIdentity as y };
@@ -1,4 +1,4 @@
1
- import { _ as acquireListenLock, a as mailLockBusy, b as listenProcessIdentity, c as mailTime, d as readMailJson, f as removeMailFile, h as writeMailJson, i as mailId, n as invalidSharedMail, o as mailObject, s as mailString, v as compareListenProcessIdentity } from "./shared-mail-files-MwlVE90c.js";
1
+ import { _ as acquireListenLock, a as mailLockBusy, c as mailTime, d as readMailJson, f as removeMailFile, h as writeMailJson, i as mailId, n as invalidSharedMail, o as mailObject, s as mailString, v as compareListenProcessIdentity, x as listenProcessIdentity } from "./shared-mail-files-CZfm7E2k.js";
2
2
  import { watch } from "node:fs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { join } from "node:path";
@@ -1,8 +1,8 @@
1
- import { h as sendPreparedSignal, p as prepareSignalEmail } from "./repeats-BL7ZC-_6-CKMKBlx7.js";
2
- import { D as bareAddress, St as successfulSendOutcome, er as listSentEmails, kn as getEmail, o as extractErrorPayload, ot as classifySendError, sn as createEndpoint, vr as sendEmail } from "./api-command-BrwPbyPP.js";
3
- import { _ as acquireListenLock, b as listenProcessIdentity, c as mailTime, d as readMailJson, f as removeMailFile, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, n as invalidSharedMail, o as mailObject, p as syncMailDirectory, r as mailAddress, s as mailString, t as SharedMailStateError, v as compareListenProcessIdentity, y as listenIdentity } from "./shared-mail-files-MwlVE90c.js";
4
- import { a as scopedChatSenderTrust, i as readBeforeDeadline, n as isPlainChatReply } from "./scoped-chat-DTFkP360.js";
5
- import { n as tryOwnSharedMail, r as waitForSharedMailChange, t as readSharedMailOwner } from "./shared-mail-watch-DtKpsgg8.js";
1
+ import { Dn as sendEmail, Ft as getEmail, _ as describeApiFailure, cn as listSentEmails, h as sendPreparedSignal, p as prepareSignalEmail, pt as createEndpoint } from "./repeats-BL7ZC-_6-B_ESsWTH.js";
2
+ import { _ as acquireListenLock, c as mailTime, d as readMailJson, f as removeMailFile, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, n as invalidSharedMail, o as mailObject, p as syncMailDirectory, r as mailAddress, s as mailString, t as SharedMailStateError, v as compareListenProcessIdentity, x as listenProcessIdentity, y as listenIdentity } from "./shared-mail-files-CZfm7E2k.js";
3
+ import { Y as classifySendError, dt as successfulSendOutcome, h as bareAddress, o as extractErrorPayload } from "./api-command-fKP3NYa7.js";
4
+ import { i as readApiBeforeDeadline, n as isPlainChatReply, o as scopedChatSenderTrust } from "./scoped-chat-DAiOb622.js";
5
+ import { n as tryOwnSharedMail, r as waitForSharedMailChange, t as readSharedMailOwner } from "./shared-mail-watch-DyQB0MK0.js";
6
6
  import { recordSentSignal } from "./oclif/auto-signals.js";
7
7
  import { Errors } from "@oclif/core";
8
8
  import { opendirSync } from "node:fs";
@@ -2087,7 +2087,7 @@ async function openSharedMailReceiver(options) {
2087
2087
  //#region src/oclif/reconcile-chat-send.ts
2088
2088
  /** Lookup only. An empty result never authorizes another send. */
2089
2089
  async function reconcileChatSend(params) {
2090
- const result = await readBeforeDeadline(params.deadline, (signal) => listSentEmails({
2090
+ const result = await readApiBeforeDeadline(params.deadline, (signal) => listSentEmails({
2091
2091
  client: params.apiClient.client,
2092
2092
  query: {
2093
2093
  idempotency_key: params.idempotencyKey,
@@ -2097,8 +2097,9 @@ async function reconcileChatSend(params) {
2097
2097
  responseStyle: "fields"
2098
2098
  }));
2099
2099
  if (result === null) return null;
2100
+ if (result.error) throw new Errors.CLIError(`Could not reconcile the saved send intent: ${describeApiFailure(result)}. Its outcome remains unknown; do not send again.`, { exit: 1 });
2100
2101
  const page = result.data;
2101
- if (result.error || !page || !Array.isArray(page.data) || !page.meta || page.meta.cursor !== null || page.data.length > 1) throw new Errors.CLIError("Could not reconcile the saved send intent. Its outcome remains unknown; do not send again.", { exit: 1 });
2102
+ if (!page || !Array.isArray(page.data) || !page.meta || page.meta.cursor !== null || page.data.length > 1) throw new Errors.CLIError("Could not reconcile the saved send intent. Its outcome remains unknown; do not send again.", { exit: 1 });
2102
2103
  const sent = page.data[0];
2103
2104
  if (!sent) return null;
2104
2105
  if (sent.client_idempotency_key !== params.idempotencyKey || typeof sent.from_address !== "string" || sent.from_address.trim().toLowerCase() !== params.from.trim().toLowerCase() || typeof sent.to_address !== "string" || sent.to_address.trim().toLowerCase() !== params.recipient.trim().toLowerCase() || typeof sent.id !== "string" || !sent.id) throw new Errors.CLIError("The saved send lookup returned conflicting identity metadata. Inspect the existing send before retrying.", { exit: 1 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primitive",
3
- "version": "1.72.2",
3
+ "version": "1.73.0",
4
4
  "description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
5
5
  "type": "module",
6
6
  "sideEffects": false,