@nuanu-ai/agentify 0.5.0 → 0.5.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 CHANGED
@@ -3,8 +3,10 @@
3
3
  Agentify puts a merchant's existing products where AI agents buy. Each product
4
4
  gets a card in an agent-facing storefront and a paid address of its own,
5
5
  `/x402/<item>/purchase`, where an agent pays for it with the x402 payment
6
- protocol; the money goes from the buyer's wallet to the merchant's without
7
- passing through us.
6
+ protocol. The buyer pays into the merchant's own payout contract, which nobody
7
+ owns and nobody can redirect. It keeps the money until it is paid out, which
8
+ the merchant can do at any time, and then sends 99.9% to the merchant's wallet
9
+ and 0.1% to Agentify ([Money](https://agentify.ad/docs/money)).
8
10
 
9
11
  This package is the merchant's side of it. It publishes the cards, receives
10
12
  paid orders and price questions through one outgoing connection, and closes
package/dist/backoff.d.ts CHANGED
@@ -1,55 +1,33 @@
1
1
  /**
2
- * How long the worker waits before asking a gateway that did not answer.
2
+ * How long the worker waits before asking again a gateway that did not answer.
3
3
  *
4
- * This is protocol behaviour rather than infrastructure, which is why it is
5
- * written here at all. The hand-rolling rule (ADR-0003 §9) reads a wish to
6
- * build retries by hand as a signal that the wrong component was chosen — and
7
- * it is right about the general case. This is not the general case: it is the
8
- * one wait between two calls of one long poll, three constants and a formula,
9
- * and a retry framework brought in to hold them would be a dependency in the
10
- * tree a merchant installs (ADR-0003 §8) for something the loop above it does
11
- * in four lines. If this file ever grows a policy, a registry or a second
12
- * caller with different needs, that is the trigger to stop and choose one.
4
+ * The bounds are chosen for the merchant, not promised by the gateway: half a
5
+ * second costs nothing visible after a dropped connection, and thirty seconds
6
+ * is close to one long-poll window, so a worker that waited out an outage is
7
+ * back within about a window of the gateway's return.
13
8
  *
14
- * The numbers are ours and they are not a claim about the gateway. Half a
15
- * second is short enough that a dropped connection costs a merchant nothing
16
- * visible, and thirty seconds is close to the long poll's own window, so a
17
- * worker that waited out an outage comes back within about one window of the
18
- * gateway returning rather than an hour later.
19
- *
20
- * The jitter is the part that is easy to leave out and expensive to lack. Every
21
- * worker that lost the same gateway failed in the same second; without jitter
22
- * they all come back in the same millisecond, forever, and the gateway that was
23
- * struggling is now being hit by the whole fleet in step. Half the delay is
24
- * fixed and half is drawn, so the delay stays inside the bounds above while no
25
- * two workers keep the same phase.
9
+ * Half of every wait is drawn at random. Workers that lost the same gateway
10
+ * failed in the same second, and without the draw they would all come back in
11
+ * the same millisecond, hitting a struggling gateway in step for ever.
26
12
  */
27
13
  /** The wait after the first failed call. */
28
14
  export declare const FIRST_RETRY_MS = 500;
29
15
  /**
30
- * The longest this file will ever ask a worker to wait.
16
+ * The longest wait between two attempts.
31
17
  *
32
- * Copied outside this package, and the copy is named here rather than only
33
- * where it is read, because whoever raises this number opens this file and not
34
- * that one. `DOUBT_MS` in packages/slice/src/subscription.ts is the window a
35
- * mock merchant waits before it decides its subscription is alive again, and it
36
- * is this ceiling plus the poll deadline plus a margin. Raise this and that
37
- * window is too narrow, which makes a healthcheck report a dead subscription as
38
- * a live one.
18
+ * `DOUBT_MS` in packages/slice/src/subscription.ts is this ceiling plus the
19
+ * poll deadline plus a margin. Raise this without raising that, and a
20
+ * healthcheck reports a dead subscription as a live one.
39
21
  */
40
22
  export declare const RETRY_CEILING_MS = 30000;
41
23
  /** What the wait is multiplied by for each further failure in a row. */
42
24
  export declare const RETRY_GROWTH = 2;
43
25
  /**
44
- * The wait before attempt number `attempt`, given one draw from [0, 1].
45
- *
46
- * The draw is a parameter rather than a call to `Math.random` inside, because
47
- * a test cannot assert a bound it cannot reproduce, and a delay whose bounds
48
- * are not tested is a delay nobody has checked.
26
+ * The wait before attempt number `attempt`, given one draw from [0, 1]. The
27
+ * draw is passed in so that a test can reproduce the bounds.
49
28
  *
50
- * Both refusals are bugs in the caller rather than conditions to handle, so
51
- * they are thrown. A zeroth attempt or a draw outside the range would produce
52
- * a number outside the bounds this file promises, and nothing downstream could
53
- * tell that it had.
29
+ * An attempt that is not a whole number from 1 up, or a draw outside [0, 1],
30
+ * is a bug in the caller and throws a `TypeError`: either would give a wait
31
+ * outside the bounds.
54
32
  */
55
33
  export declare const retryDelayMs: (attempt: number, random: number) => number;
package/dist/backoff.js CHANGED
@@ -1,56 +1,34 @@
1
1
  /**
2
- * How long the worker waits before asking a gateway that did not answer.
2
+ * How long the worker waits before asking again a gateway that did not answer.
3
3
  *
4
- * This is protocol behaviour rather than infrastructure, which is why it is
5
- * written here at all. The hand-rolling rule (ADR-0003 §9) reads a wish to
6
- * build retries by hand as a signal that the wrong component was chosen — and
7
- * it is right about the general case. This is not the general case: it is the
8
- * one wait between two calls of one long poll, three constants and a formula,
9
- * and a retry framework brought in to hold them would be a dependency in the
10
- * tree a merchant installs (ADR-0003 §8) for something the loop above it does
11
- * in four lines. If this file ever grows a policy, a registry or a second
12
- * caller with different needs, that is the trigger to stop and choose one.
4
+ * The bounds are chosen for the merchant, not promised by the gateway: half a
5
+ * second costs nothing visible after a dropped connection, and thirty seconds
6
+ * is close to one long-poll window, so a worker that waited out an outage is
7
+ * back within about a window of the gateway's return.
13
8
  *
14
- * The numbers are ours and they are not a claim about the gateway. Half a
15
- * second is short enough that a dropped connection costs a merchant nothing
16
- * visible, and thirty seconds is close to the long poll's own window, so a
17
- * worker that waited out an outage comes back within about one window of the
18
- * gateway returning rather than an hour later.
19
- *
20
- * The jitter is the part that is easy to leave out and expensive to lack. Every
21
- * worker that lost the same gateway failed in the same second; without jitter
22
- * they all come back in the same millisecond, forever, and the gateway that was
23
- * struggling is now being hit by the whole fleet in step. Half the delay is
24
- * fixed and half is drawn, so the delay stays inside the bounds above while no
25
- * two workers keep the same phase.
9
+ * Half of every wait is drawn at random. Workers that lost the same gateway
10
+ * failed in the same second, and without the draw they would all come back in
11
+ * the same millisecond, hitting a struggling gateway in step for ever.
26
12
  */
27
13
  /** The wait after the first failed call. */
28
14
  export const FIRST_RETRY_MS = 500;
29
15
  /**
30
- * The longest this file will ever ask a worker to wait.
16
+ * The longest wait between two attempts.
31
17
  *
32
- * Copied outside this package, and the copy is named here rather than only
33
- * where it is read, because whoever raises this number opens this file and not
34
- * that one. `DOUBT_MS` in packages/slice/src/subscription.ts is the window a
35
- * mock merchant waits before it decides its subscription is alive again, and it
36
- * is this ceiling plus the poll deadline plus a margin. Raise this and that
37
- * window is too narrow, which makes a healthcheck report a dead subscription as
38
- * a live one.
18
+ * `DOUBT_MS` in packages/slice/src/subscription.ts is this ceiling plus the
19
+ * poll deadline plus a margin. Raise this without raising that, and a
20
+ * healthcheck reports a dead subscription as a live one.
39
21
  */
40
22
  export const RETRY_CEILING_MS = 30_000;
41
23
  /** What the wait is multiplied by for each further failure in a row. */
42
24
  export const RETRY_GROWTH = 2;
43
25
  /**
44
- * The wait before attempt number `attempt`, given one draw from [0, 1].
45
- *
46
- * The draw is a parameter rather than a call to `Math.random` inside, because
47
- * a test cannot assert a bound it cannot reproduce, and a delay whose bounds
48
- * are not tested is a delay nobody has checked.
26
+ * The wait before attempt number `attempt`, given one draw from [0, 1]. The
27
+ * draw is passed in so that a test can reproduce the bounds.
49
28
  *
50
- * Both refusals are bugs in the caller rather than conditions to handle, so
51
- * they are thrown. A zeroth attempt or a draw outside the range would produce
52
- * a number outside the bounds this file promises, and nothing downstream could
53
- * tell that it had.
29
+ * An attempt that is not a whole number from 1 up, or a draw outside [0, 1],
30
+ * is a bug in the caller and throws a `TypeError`: either would give a wait
31
+ * outside the bounds.
54
32
  */
55
33
  export const retryDelayMs = (attempt, random) => {
56
34
  if (!Number.isInteger(attempt) || attempt < 1) {
@@ -1,28 +1,7 @@
1
1
  /**
2
- * Is this card enough for an agent to buy from?
3
- *
4
- * The check is the contracts schema and the contract's price rule, and nothing
5
- * beside them. A second opinion written here would be a second definition of a
6
- * complete card, and the day the two disagreed a merchant would pass one and be
7
- * refused by the other. The price rule is read here for exactly that reason:
8
- * it is the gateway's door that applies it rather than the schema, and a check
9
- * that skipped it would pass a card priced at zero that publishing refuses.
10
- *
11
- * What the check cannot see is worth stating, because a merchant reading a
12
- * short list of findings would otherwise assume it is the whole list. A card is
13
- * checked in two stages: first its shape — which fields are there, what they
14
- * hold, whether any field was invented — and then the rules that compare one
15
- * field against another, such as a delivery deadline being allowed only on the
16
- * modes that wait, and the price rule. The second stage is only reached when
17
- * the first passes. So a card that failed on its shape may still have a finding
18
- * waiting behind the ones it was given, and the report says so instead of
19
- * implying a clean second run. A card that passes has passed both stages and
20
- * there is nothing behind it.
21
- *
22
- * What no local check can decide at all: whether the gateway will accept the
23
- * card. Publishing is the authority — a merchant key already in use, a policy
24
- * nobody has written into the contract — and this check makes no claim about
25
- * any of that.
2
+ * The local check of a card: the contract's card schema and its price rule,
3
+ * and nothing beside them, so a card it passes is not refused at publication
4
+ * for its shape or its price.
26
5
  */
27
6
  import { type Problem } from "@nuanu-ai/agentify-contracts";
28
7
  export interface CardCheck {
@@ -33,4 +12,16 @@ export interface CardCheck {
33
12
  */
34
13
  readonly problems: readonly Problem[];
35
14
  }
15
+ /**
16
+ * Checks a card before it is published, without calling the gateway, and
17
+ * returns every finding under `problems` in the shape the publish call refuses
18
+ * with. It never throws.
19
+ *
20
+ * The card is checked in two stages: its shape first, then the rules between
21
+ * fields and the price rule. The second stage runs only once the first
22
+ * passes, so a card refused on its shape may have more findings behind the
23
+ * ones it was given. Whether the gateway accepts the card is decided only by
24
+ * publishing: the merchant's own settings, such as a seller name, are not
25
+ * checked here.
26
+ */
36
27
  export declare const checkCard: (card: unknown) => CardCheck;
@@ -1,31 +1,22 @@
1
1
  /**
2
- * Is this card enough for an agent to buy from?
3
- *
4
- * The check is the contracts schema and the contract's price rule, and nothing
5
- * beside them. A second opinion written here would be a second definition of a
6
- * complete card, and the day the two disagreed a merchant would pass one and be
7
- * refused by the other. The price rule is read here for exactly that reason:
8
- * it is the gateway's door that applies it rather than the schema, and a check
9
- * that skipped it would pass a card priced at zero that publishing refuses.
10
- *
11
- * What the check cannot see is worth stating, because a merchant reading a
12
- * short list of findings would otherwise assume it is the whole list. A card is
13
- * checked in two stages: first its shape — which fields are there, what they
14
- * hold, whether any field was invented — and then the rules that compare one
15
- * field against another, such as a delivery deadline being allowed only on the
16
- * modes that wait, and the price rule. The second stage is only reached when
17
- * the first passes. So a card that failed on its shape may still have a finding
18
- * waiting behind the ones it was given, and the report says so instead of
19
- * implying a clean second run. A card that passes has passed both stages and
20
- * there is nothing behind it.
21
- *
22
- * What no local check can decide at all: whether the gateway will accept the
23
- * card. Publishing is the authority — a merchant key already in use, a policy
24
- * nobody has written into the contract — and this check makes no claim about
25
- * any of that.
2
+ * The local check of a card: the contract's card schema and its price rule,
3
+ * and nothing beside them, so a card it passes is not refused at publication
4
+ * for its shape or its price.
26
5
  */
27
6
  import { CardSchema, priceProblemsOf } from "@nuanu-ai/agentify-contracts";
28
7
  import { problemsOf } from "./schema.js";
8
+ /**
9
+ * Checks a card before it is published, without calling the gateway, and
10
+ * returns every finding under `problems` in the shape the publish call refuses
11
+ * with. It never throws.
12
+ *
13
+ * The card is checked in two stages: its shape first, then the rules between
14
+ * fields and the price rule. The second stage runs only once the first
15
+ * passes, so a card refused on its shape may have more findings behind the
16
+ * ones it was given. Whether the gateway accepts the card is decided only by
17
+ * publishing: the merchant's own settings, such as a seller name, are not
18
+ * checked here.
19
+ */
29
20
  export const checkCard = (card) => {
30
21
  const result = CardSchema.safeParse(card);
31
22
  return {
package/dist/cli.d.ts CHANGED
@@ -1,21 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * The command installed by `@nuanu-ai/agentify` as `agentify`.
3
+ * The command installed by `@nuanu-ai/agentify` as `agentify`. The work is in
4
+ * `verify.ts`; this is glue.
4
5
  *
5
- * It is glue and nothing else: the work is in `verify.ts`, which answers with
6
- * a number and a stream of lines, so that everything the command does can be
7
- * tested without a process, a shell or a temporary directory of output.
8
- *
9
- * What a merchant runs is not this file but `dist/cli.js` compiled from it, and
10
- * the distinction is the whole reason the package has a build. These sources
11
- * import each other with `.js` specifiers; Node's type stripping does not
12
- * rewrite such a specifier, so it would look for a `.js` file that is not
13
- * there and stop. `tsc` writes exactly that file, and `publishConfig.bin` in
14
- * `package.json` is what points the installed `agentify` command at it.
15
- *
16
- * Nothing in this repository runs the compiled command, so nothing in
17
- * `pnpm test` can tell you it still starts. `pnpm outside` is what does: it
18
- * installs the packed tarball into a directory with no path back here and runs
19
- * the installed `agentify verify` command there.
6
+ * What a merchant runs is `dist/cli.js`, because Node's type stripping does not
7
+ * rewrite the `.js` specifiers these sources import each other by. Nothing in
8
+ * `pnpm test` runs the compiled command; `pnpm outside` installs the packed
9
+ * tarball elsewhere and runs `agentify verify` there.
20
10
  */
21
11
  export {};
package/dist/cli.js CHANGED
@@ -1,22 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * The command installed by `@nuanu-ai/agentify` as `agentify`.
3
+ * The command installed by `@nuanu-ai/agentify` as `agentify`. The work is in
4
+ * `verify.ts`; this is glue.
4
5
  *
5
- * It is glue and nothing else: the work is in `verify.ts`, which answers with
6
- * a number and a stream of lines, so that everything the command does can be
7
- * tested without a process, a shell or a temporary directory of output.
8
- *
9
- * What a merchant runs is not this file but `dist/cli.js` compiled from it, and
10
- * the distinction is the whole reason the package has a build. These sources
11
- * import each other with `.js` specifiers; Node's type stripping does not
12
- * rewrite such a specifier, so it would look for a `.js` file that is not
13
- * there and stop. `tsc` writes exactly that file, and `publishConfig.bin` in
14
- * `package.json` is what points the installed `agentify` command at it.
15
- *
16
- * Nothing in this repository runs the compiled command, so nothing in
17
- * `pnpm test` can tell you it still starts. `pnpm outside` is what does: it
18
- * installs the packed tarball into a directory with no path back here and runs
19
- * the installed `agentify verify` command there.
6
+ * What a merchant runs is `dist/cli.js`, because Node's type stripping does not
7
+ * rewrite the `.js` specifiers these sources import each other by. Nothing in
8
+ * `pnpm test` runs the compiled command; `pnpm outside` installs the packed
9
+ * tarball elsewhere and runs `agentify verify` there.
20
10
  */
21
11
  import { runVerify } from "./verify.js";
22
12
  process.exitCode = await runVerify(process.argv.slice(2), (line) => {