@artblocks/abx-sdk 0.1.0-alpha.1 → 0.1.0-alpha.11
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 +131 -0
- package/dist/abi/generated.d.ts +585 -12
- package/dist/abi/generated.d.ts.map +1 -1
- package/dist/abi/generated.js +16 -16
- package/dist/abi/generated.js.map +1 -1
- package/dist/abi/index.d.ts +209 -12
- package/dist/abi/index.d.ts.map +1 -1
- package/dist/anchors.d.ts +150 -0
- package/dist/anchors.d.ts.map +1 -0
- package/dist/anchors.js +290 -0
- package/dist/anchors.js.map +1 -0
- package/dist/chains.d.ts +20 -9
- package/dist/chains.d.ts.map +1 -1
- package/dist/chains.js +27 -18
- package/dist/chains.js.map +1 -1
- package/dist/chunks.d.ts +53 -23
- package/dist/chunks.d.ts.map +1 -1
- package/dist/chunks.js +68 -6
- package/dist/chunks.js.map +1 -1
- package/dist/clients.d.ts +23 -11
- package/dist/clients.d.ts.map +1 -1
- package/dist/clients.js +17 -18
- package/dist/clients.js.map +1 -1
- package/dist/creator-token.d.ts +65 -0
- package/dist/creator-token.d.ts.map +1 -0
- package/dist/creator-token.js +93 -0
- package/dist/creator-token.js.map +1 -0
- package/dist/deploy.d.ts +24 -10
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +62 -87
- package/dist/deploy.js.map +1 -1
- package/dist/deployments.d.ts.map +1 -1
- package/dist/deployments.js +38 -22
- package/dist/deployments.js.map +1 -1
- package/dist/deps.d.ts +122 -5
- package/dist/deps.d.ts.map +1 -1
- package/dist/deps.js +248 -6
- package/dist/deps.js.map +1 -1
- package/dist/env.d.ts +11 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +42 -2
- package/dist/env.js.map +1 -1
- package/dist/errors.d.ts +74 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +102 -0
- package/dist/errors.js.map +1 -0
- package/dist/execute.d.ts +115 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/execute.js +142 -0
- package/dist/execute.js.map +1 -0
- package/dist/gateways.d.ts +32 -0
- package/dist/gateways.d.ts.map +1 -0
- package/dist/gateways.js +53 -0
- package/dist/gateways.js.map +1 -0
- package/dist/generator-document.d.ts +57 -0
- package/dist/generator-document.d.ts.map +1 -0
- package/dist/generator-document.js +123 -0
- package/dist/generator-document.js.map +1 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +48 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +290 -0
- package/dist/inspect.js.map +1 -0
- package/dist/migrate.d.ts +41 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +140 -0
- package/dist/migrate.js.map +1 -0
- package/dist/mime.d.ts +11 -0
- package/dist/mime.d.ts.map +1 -0
- package/dist/mime.js +40 -0
- package/dist/mime.js.map +1 -0
- package/dist/node.d.ts +10 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +24 -0
- package/dist/node.js.map +1 -0
- package/dist/onchain-uri.d.ts +96 -0
- package/dist/onchain-uri.d.ts.map +1 -0
- package/dist/onchain-uri.js +231 -0
- package/dist/onchain-uri.js.map +1 -0
- package/dist/ops.d.ts +113 -5
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +172 -13
- package/dist/ops.js.map +1 -1
- package/dist/reconstruct.d.ts +37 -1
- package/dist/reconstruct.d.ts.map +1 -1
- package/dist/reconstruct.js +153 -50
- package/dist/reconstruct.js.map +1 -1
- package/dist/resume.d.ts +96 -0
- package/dist/resume.d.ts.map +1 -0
- package/dist/resume.js +95 -0
- package/dist/resume.js.map +1 -0
- package/dist/service.d.ts +369 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +376 -0
- package/dist/service.js.map +1 -0
- package/dist/staging.d.ts +95 -0
- package/dist/staging.d.ts.map +1 -0
- package/dist/staging.js +57 -0
- package/dist/staging.js.map +1 -0
- package/dist/tokendata.d.ts +62 -2
- package/dist/tokendata.d.ts.map +1 -1
- package/dist/tokendata.js +60 -16
- package/dist/tokendata.js.map +1 -1
- package/dist/tokens.d.ts +55 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +152 -0
- package/dist/tokens.js.map +1 -0
- package/dist/util.d.ts +74 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +106 -0
- package/dist/util.js.map +1 -0
- package/package.json +10 -2
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gas limits for a sequenced transaction — decided HERE, once, rather than re-read at signing time.
|
|
3
|
+
*
|
|
4
|
+
* The failure this exists to prevent, in full, because it is not obvious and it cost a reporter every
|
|
5
|
+
* `deploy-code` attempt of a session: a project deploys in two transactions, and the second targets
|
|
6
|
+
* the contract the first just created. If the node answering `eth_estimateGas` has not yet seen the
|
|
7
|
+
* deploy block, the target looks like an account with no code — and an estimate for a call to a
|
|
8
|
+
* codeless account is just the calldata cost, around 200k. That number is then sent as the gas limit.
|
|
9
|
+
* Once the contract does exist the same call needs ~941k, because storing a program on-chain is
|
|
10
|
+
* dominated by CREATE code deposit at ~200 gas per byte. The CREATE receives 63/64 of a budget that
|
|
11
|
+
* cannot cover the deposit, returns 0, and Solady's `SSTORE2.write` reverts `DeploymentFailed()` — a
|
|
12
|
+
* revert that reads like a contract bug and is really an out-of-gas.
|
|
13
|
+
*
|
|
14
|
+
* (Measured, from the real transactions: `gasLimit 201,616 / gasUsed 198,870` and
|
|
15
|
+
* `gasLimit 169,301 / gasUsed 166,810` — 98.6% and 98.5% of their limits. Replaying those payloads
|
|
16
|
+
* against a codeless address reproduces both limits to the gas; against the real contract the same
|
|
17
|
+
* calls estimate at 941,331.)
|
|
18
|
+
*
|
|
19
|
+
* The deploy loop already pinned the *nonce* against exactly this read-after-write lag on a
|
|
20
|
+
* distributed RPC. The rule generalizes, and it is the reason this module exists: **anything read at
|
|
21
|
+
* send time on a distributed RPC needs pinning, not just the nonce.**
|
|
22
|
+
*/
|
|
23
|
+
import type { Account, Address, Hex, PublicClient, TransactionReceipt, WalletClient } from 'viem';
|
|
24
|
+
import type { PreparedTx } from './ops.js';
|
|
25
|
+
/**
|
|
26
|
+
* Wait until `address` has code from THIS client's point of view. A deploy receipt proves the
|
|
27
|
+
* contract exists on chain; it does not prove the node answering the next request has caught up.
|
|
28
|
+
* Bounded — on timeout we proceed and let the gas floor carry it, since a slow RPC is not a reason
|
|
29
|
+
* to refuse to continue a deploy that already spent money.
|
|
30
|
+
*/
|
|
31
|
+
export declare function waitForCodeAt(client: PublicClient, address: Address, timeoutMs?: number): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* Decide a transaction's gas limit once, here.
|
|
34
|
+
*
|
|
35
|
+
* The important design point, because the obvious approach is wrong: when an estimate looks too low
|
|
36
|
+
* we do **not** substitute a computed number. A caller can only compute the *provable* part of a
|
|
37
|
+
* payload's cost (see `PreparedTx.gasFloor` — code deposit is 200 gas/byte and nothing else is
|
|
38
|
+
* physics); the same setup multicall also carries schema writes, dependency legs, URI legs and
|
|
39
|
+
* mints, whose cost we cannot derive without simulating them. A "probably enough" constant is a
|
|
40
|
+
* number tuned to whatever case was in front of its author: it papers over the symptom, then
|
|
41
|
+
* under-funds the next payload that carries a few more legs, producing the identical
|
|
42
|
+
* `DeploymentFailed()` with a fresh mystery attached.
|
|
43
|
+
*
|
|
44
|
+
* So the floor is used as a **detector**. An estimate below a provable minimum is not "low", it is
|
|
45
|
+
* *impossible* — proof that the node answering us is looking at the wrong state (typically it has
|
|
46
|
+
* not seen the deploy block yet, so the target reads as an account with no code and the estimate
|
|
47
|
+
* comes back as the calldata cost alone). The right response to a broken measurement is to take it
|
|
48
|
+
* again, and if it stays broken, to refuse — sending a transaction we can prove is under-funded
|
|
49
|
+
* would burn the gas AND orphan the contract.
|
|
50
|
+
*
|
|
51
|
+
* When the estimate IS plausible it is trusted, plus headroom for state drift between estimate and
|
|
52
|
+
* inclusion.
|
|
53
|
+
*/
|
|
54
|
+
export declare function pinGas(client: PublicClient, tx: {
|
|
55
|
+
from: Address;
|
|
56
|
+
to: Address | null;
|
|
57
|
+
data: Hex;
|
|
58
|
+
value?: Hex;
|
|
59
|
+
gasFloor?: Hex;
|
|
60
|
+
}, opts?: {
|
|
61
|
+
attempts?: number;
|
|
62
|
+
delayMs?: number;
|
|
63
|
+
}): Promise<bigint>;
|
|
64
|
+
/** Sign + broadcast one {@link PreparedTx} and return its mined receipt (for event parsing). The
|
|
65
|
+
* SDK's one send-injection point: a hot key ({@link makeHotSender}), a browser wallet (a
|
|
66
|
+
* `WalletSession`), or anything else a caller wires up — the SDK never picks or performs the
|
|
67
|
+
* signing itself. */
|
|
68
|
+
export type SendTx = (tx: PreparedTx) => Promise<TransactionReceipt>;
|
|
69
|
+
/** Progress from a {@link SendTx} built by {@link makeHotSender}, so a caller can narrate without
|
|
70
|
+
* the SDK printing anything itself (the SDK never prints — see clients.ts / chunks.ts for the same
|
|
71
|
+
* `onEvent` pattern). */
|
|
72
|
+
export type SendEvent = {
|
|
73
|
+
kind: 'sending';
|
|
74
|
+
tx: PreparedTx;
|
|
75
|
+
} | {
|
|
76
|
+
kind: 'mined';
|
|
77
|
+
receipt: TransactionReceipt;
|
|
78
|
+
tx: PreparedTx;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Build a {@link SendTx} that signs with an env-style hot key and broadcasts — the generalization of
|
|
82
|
+
* what used to be hand-rolled per call site (a deploy-then-setup loop in the CLI, the hot lane in
|
|
83
|
+
* `signer.ts`, the chunk-staging sender in `ownerops.ts`): one function that gets the read-after-
|
|
84
|
+
* write-lag handling right ONCE.
|
|
85
|
+
*
|
|
86
|
+
* Two lags, pinned once at construction / tracked locally per send, rather than re-read at send time:
|
|
87
|
+
* - the NONCE — fetched once here, then incremented locally per tx. Right after a tx is mined a
|
|
88
|
+
* distributed RPC (e.g. Alchemy) can briefly serve a stale `pending` transaction count
|
|
89
|
+
* (read-after-write lag), so re-fetching it for the NEXT send in the same sequence risks reusing
|
|
90
|
+
* the just-spent nonce — the tx it already has in the mempool rejects the duplicate as
|
|
91
|
+
* "replacement transaction underpriced", and that send is silently lost.
|
|
92
|
+
* - GAS, one field over: a tx after the first in a sequence may target a contract an EARLIER tx in
|
|
93
|
+
* this same sequence just created. If the node answering `eth_estimateGas` hasn't seen that
|
|
94
|
+
* block yet, the target looks codeless and the estimate comes back as the calldata cost alone —
|
|
95
|
+
* see `pinGas` above for the full story (and the measured numbers). So every send after the
|
|
96
|
+
* first waits for its target's code to be visible before estimating.
|
|
97
|
+
*
|
|
98
|
+
* Every send: wait for code at the target when it's not the first send in this sender's sequence
|
|
99
|
+
* (mirrors the exact rule the deploy-code hot lane hand-rolled: every tx after the first, since the
|
|
100
|
+
* first is what creates what the rest target), pin the gas (a provable floor detector, never a
|
|
101
|
+
* substitute limit), broadcast, wait for the receipt, and throw a typed {@link TxRevertedError} —
|
|
102
|
+
* carrying the tx hash — on a `reverted` status rather than reporting a burned transaction as
|
|
103
|
+
* "confirmed".
|
|
104
|
+
*/
|
|
105
|
+
export declare function makeHotSender(args: {
|
|
106
|
+
wallet: WalletClient;
|
|
107
|
+
account: Account;
|
|
108
|
+
publicClient: PublicClient;
|
|
109
|
+
onEvent?: (e: SendEvent) => void;
|
|
110
|
+
}): SendTx;
|
|
111
|
+
/** Send a list of prepared txs, in order, via `send`; returns their receipts in the same order.
|
|
112
|
+
* A small convenience for the common "just run this sequence" case — narration (if any) rides
|
|
113
|
+
* `send`'s own `onEvent`, not a callback here. */
|
|
114
|
+
export declare function runPrepared(txs: PreparedTx[], send: SendTx): Promise<TransactionReceipt[]>;
|
|
115
|
+
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../src/execute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAC,MAAM,MAAM,CAAC;AAChG,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AAGzC;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAQhH;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,MAAM,CAC1B,MAAM,EAAE,YAAY,EACpB,EAAE,EAAE;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,EAAE,GAAG,CAAA;CAAC,EAC/E,IAAI,GAAE;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,GAC/C,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED;;;sBAGsB;AACtB,MAAM,MAAM,MAAM,GAAG,CAAC,EAAE,EAAE,UAAU,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAErE;;0BAE0B;AAC1B,MAAM,MAAM,SAAS,GACjB;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAC,GACjC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;CAClC,GAAG,MAAM,CAkCT;AAED;;mDAEmD;AACnD,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAIhG"}
|
package/dist/execute.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { GasEstimateBelowFloorError, TxRevertedError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Wait until `address` has code from THIS client's point of view. A deploy receipt proves the
|
|
4
|
+
* contract exists on chain; it does not prove the node answering the next request has caught up.
|
|
5
|
+
* Bounded — on timeout we proceed and let the gas floor carry it, since a slow RPC is not a reason
|
|
6
|
+
* to refuse to continue a deploy that already spent money.
|
|
7
|
+
*/
|
|
8
|
+
export async function waitForCodeAt(client, address, timeoutMs = 15_000) {
|
|
9
|
+
const deadline = Date.now() + timeoutMs;
|
|
10
|
+
for (;;) {
|
|
11
|
+
const code = await client.getCode({ address }).catch(() => undefined);
|
|
12
|
+
if (code && code !== '0x')
|
|
13
|
+
return true;
|
|
14
|
+
if (Date.now() >= deadline)
|
|
15
|
+
return false;
|
|
16
|
+
await new Promise((r) => setTimeout(r, 750));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Decide a transaction's gas limit once, here.
|
|
21
|
+
*
|
|
22
|
+
* The important design point, because the obvious approach is wrong: when an estimate looks too low
|
|
23
|
+
* we do **not** substitute a computed number. A caller can only compute the *provable* part of a
|
|
24
|
+
* payload's cost (see `PreparedTx.gasFloor` — code deposit is 200 gas/byte and nothing else is
|
|
25
|
+
* physics); the same setup multicall also carries schema writes, dependency legs, URI legs and
|
|
26
|
+
* mints, whose cost we cannot derive without simulating them. A "probably enough" constant is a
|
|
27
|
+
* number tuned to whatever case was in front of its author: it papers over the symptom, then
|
|
28
|
+
* under-funds the next payload that carries a few more legs, producing the identical
|
|
29
|
+
* `DeploymentFailed()` with a fresh mystery attached.
|
|
30
|
+
*
|
|
31
|
+
* So the floor is used as a **detector**. An estimate below a provable minimum is not "low", it is
|
|
32
|
+
* *impossible* — proof that the node answering us is looking at the wrong state (typically it has
|
|
33
|
+
* not seen the deploy block yet, so the target reads as an account with no code and the estimate
|
|
34
|
+
* comes back as the calldata cost alone). The right response to a broken measurement is to take it
|
|
35
|
+
* again, and if it stays broken, to refuse — sending a transaction we can prove is under-funded
|
|
36
|
+
* would burn the gas AND orphan the contract.
|
|
37
|
+
*
|
|
38
|
+
* When the estimate IS plausible it is trusted, plus headroom for state drift between estimate and
|
|
39
|
+
* inclusion.
|
|
40
|
+
*/
|
|
41
|
+
export async function pinGas(client, tx, opts = {}) {
|
|
42
|
+
const floor = tx.gasFloor ? BigInt(tx.gasFloor) : 0n;
|
|
43
|
+
const attempts = opts.attempts ?? 3;
|
|
44
|
+
let lastEstimate = null;
|
|
45
|
+
let lastError;
|
|
46
|
+
for (let i = 0; i < attempts; i++) {
|
|
47
|
+
try {
|
|
48
|
+
const estimate = await client.estimateGas({
|
|
49
|
+
account: tx.from,
|
|
50
|
+
to: tx.to ?? undefined,
|
|
51
|
+
data: tx.data,
|
|
52
|
+
...(tx.value && tx.value !== '0x0' ? { value: BigInt(tx.value) } : {}),
|
|
53
|
+
});
|
|
54
|
+
// Plausible (or nothing provable to check it against) → trust it.
|
|
55
|
+
if (estimate >= floor)
|
|
56
|
+
return (estimate * 125n) / 100n;
|
|
57
|
+
lastEstimate = estimate;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
lastError = err;
|
|
61
|
+
// A revert during estimation is a real answer about the transaction, not a lagging node —
|
|
62
|
+
// surface it immediately, since its message ("caller is not the owner") is the useful part.
|
|
63
|
+
if (floor === 0n)
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
if (i < attempts - 1)
|
|
67
|
+
await new Promise((r) => setTimeout(r, opts.delayMs ?? 1_500));
|
|
68
|
+
}
|
|
69
|
+
if (lastEstimate !== null) {
|
|
70
|
+
throw new GasEstimateBelowFloorError(lastEstimate, floor);
|
|
71
|
+
}
|
|
72
|
+
throw lastError instanceof Error ? lastError : new Error('gas estimation failed');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build a {@link SendTx} that signs with an env-style hot key and broadcasts — the generalization of
|
|
76
|
+
* what used to be hand-rolled per call site (a deploy-then-setup loop in the CLI, the hot lane in
|
|
77
|
+
* `signer.ts`, the chunk-staging sender in `ownerops.ts`): one function that gets the read-after-
|
|
78
|
+
* write-lag handling right ONCE.
|
|
79
|
+
*
|
|
80
|
+
* Two lags, pinned once at construction / tracked locally per send, rather than re-read at send time:
|
|
81
|
+
* - the NONCE — fetched once here, then incremented locally per tx. Right after a tx is mined a
|
|
82
|
+
* distributed RPC (e.g. Alchemy) can briefly serve a stale `pending` transaction count
|
|
83
|
+
* (read-after-write lag), so re-fetching it for the NEXT send in the same sequence risks reusing
|
|
84
|
+
* the just-spent nonce — the tx it already has in the mempool rejects the duplicate as
|
|
85
|
+
* "replacement transaction underpriced", and that send is silently lost.
|
|
86
|
+
* - GAS, one field over: a tx after the first in a sequence may target a contract an EARLIER tx in
|
|
87
|
+
* this same sequence just created. If the node answering `eth_estimateGas` hasn't seen that
|
|
88
|
+
* block yet, the target looks codeless and the estimate comes back as the calldata cost alone —
|
|
89
|
+
* see `pinGas` above for the full story (and the measured numbers). So every send after the
|
|
90
|
+
* first waits for its target's code to be visible before estimating.
|
|
91
|
+
*
|
|
92
|
+
* Every send: wait for code at the target when it's not the first send in this sender's sequence
|
|
93
|
+
* (mirrors the exact rule the deploy-code hot lane hand-rolled: every tx after the first, since the
|
|
94
|
+
* first is what creates what the rest target), pin the gas (a provable floor detector, never a
|
|
95
|
+
* substitute limit), broadcast, wait for the receipt, and throw a typed {@link TxRevertedError} —
|
|
96
|
+
* carrying the tx hash — on a `reverted` status rather than reporting a burned transaction as
|
|
97
|
+
* "confirmed".
|
|
98
|
+
*/
|
|
99
|
+
export function makeHotSender(args) {
|
|
100
|
+
const { wallet, account, publicClient } = args;
|
|
101
|
+
const notify = args.onEvent ?? (() => { });
|
|
102
|
+
let nonce;
|
|
103
|
+
let sent = 0;
|
|
104
|
+
return async (tx) => {
|
|
105
|
+
if (nonce === undefined) {
|
|
106
|
+
// Fetch once, then increment locally per send — see the read-after-write-lag reasoning above.
|
|
107
|
+
nonce = await publicClient.getTransactionCount({ address: account.address, blockTag: 'pending' });
|
|
108
|
+
}
|
|
109
|
+
// The SAME lag, one field over: every send after the first in this sender's sequence may target
|
|
110
|
+
// what an earlier send just created.
|
|
111
|
+
if (sent > 0 && tx.to)
|
|
112
|
+
await waitForCodeAt(publicClient, tx.to);
|
|
113
|
+
const gas = await pinGas(publicClient, { from: account.address, to: tx.to, data: tx.data, value: tx.value, gasFloor: tx.gasFloor });
|
|
114
|
+
notify({ kind: 'sending', tx });
|
|
115
|
+
const hash = await wallet.sendTransaction({
|
|
116
|
+
to: tx.to ?? undefined,
|
|
117
|
+
data: tx.data,
|
|
118
|
+
value: tx.value && tx.value !== '0x0' ? BigInt(tx.value) : undefined,
|
|
119
|
+
account,
|
|
120
|
+
chain: wallet.chain,
|
|
121
|
+
nonce,
|
|
122
|
+
gas,
|
|
123
|
+
});
|
|
124
|
+
nonce += 1;
|
|
125
|
+
sent += 1;
|
|
126
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
127
|
+
if (receipt.status !== 'success')
|
|
128
|
+
throw new TxRevertedError(tx.op, hash);
|
|
129
|
+
notify({ kind: 'mined', receipt, tx });
|
|
130
|
+
return receipt;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Send a list of prepared txs, in order, via `send`; returns their receipts in the same order.
|
|
134
|
+
* A small convenience for the common "just run this sequence" case — narration (if any) rides
|
|
135
|
+
* `send`'s own `onEvent`, not a callback here. */
|
|
136
|
+
export async function runPrepared(txs, send) {
|
|
137
|
+
const receipts = [];
|
|
138
|
+
for (const tx of txs)
|
|
139
|
+
receipts.push(await send(tx));
|
|
140
|
+
return receipts;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../src/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** The locator's network, which decides which gateways can be asked about it. `http` locators
|
|
2
|
+
* carry their own base (they are already an absolute URL) and resolve to `''` here — a caller
|
|
3
|
+
* returns them verbatim before consulting a gateway. */
|
|
4
|
+
export type LocatorNetwork = 'arweave' | 'ipfs' | 'http';
|
|
5
|
+
/** Resolved gateway overrides for the two content-addressed networks — the shape both
|
|
6
|
+
* {@link resolveGatewayBase} and {@link gatewayConfigFromEnv} speak. */
|
|
7
|
+
export interface GatewayOverrides {
|
|
8
|
+
ipfs?: string;
|
|
9
|
+
arweave?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The gateway BASE for a locator network, given already-resolved `overrides` — PURE, no env
|
|
13
|
+
* read. Defaults to the generic public gateways (`ipfs.io` / `arweave.net`) when `overrides`
|
|
14
|
+
* doesn't name one; any other `network` (e.g. `http`, which carries its own base) resolves to
|
|
15
|
+
* `''`. Callers that want override → env → default precedence compose this with
|
|
16
|
+
* {@link gatewayConfigFromEnv} themselves (see `@artblocks/abx-storage`'s `resolveGatewayBase`
|
|
17
|
+
* for the reference compose) — kept separate so a host with its own config source never has this
|
|
18
|
+
* function reach into `process.env` on its behalf.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveGatewayBase(network: 'ipfs' | 'arweave' | string, overrides?: GatewayOverrides): string;
|
|
21
|
+
/**
|
|
22
|
+
* The ONLY env-reading piece of this module: `ABX_IPFS_GATEWAY` / `ABX_ARWEAVE_GATEWAY`, read via
|
|
23
|
+
* {@link readEnv} (safe where `process` doesn't exist). Exported separately from
|
|
24
|
+
* {@link resolveGatewayBase} so a host with its own gateway configuration (a database row, a
|
|
25
|
+
* remote config service) never has to touch `process.env` through this package at all — it just
|
|
26
|
+
* never calls this function and passes its own overrides straight to the pure resolver instead.
|
|
27
|
+
*/
|
|
28
|
+
export declare function gatewayConfigFromEnv(): GatewayOverrides;
|
|
29
|
+
/** Build the URL that asks `gateway` for `id`. A locator that is already an absolute URL is asked
|
|
30
|
+
* verbatim — rewriting someone's URL would answer a question they didn't ask. */
|
|
31
|
+
export declare function gatewayUrlFor(network: LocatorNetwork, id: string, gateway: string): string;
|
|
32
|
+
//# sourceMappingURL=gateways.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateways.d.ts","sourceRoot":"","sources":["../src/gateways.ts"],"names":[],"mappings":"AAWA;;yDAEyD;AACzD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzD;yEACyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,SAAS,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAI7G;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,CAOvD;AAED;kFACkF;AAClF,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAK1F"}
|
package/dist/gateways.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway resolution for content-addressed locators (`ipfs://…`, `ar://…`) — hoisted from
|
|
3
|
+
* `@artblocks/abx-storage` (the abx-services integrator ask), split into a PURE resolver and a
|
|
4
|
+
* separate env-reading piece so a host with its own gateway config never has to touch
|
|
5
|
+
* `process.env` through this module at all, and so this stays reachable from a browser bundle
|
|
6
|
+
* (see `test/browser-bundle.test.ts` — no `process.env` read outside {@link gatewayConfigFromEnv},
|
|
7
|
+
* which itself goes through {@link readEnv} and degrades to "no override" rather than throwing
|
|
8
|
+
* where `process` doesn't exist).
|
|
9
|
+
*/
|
|
10
|
+
import { readEnv } from './util.js';
|
|
11
|
+
/**
|
|
12
|
+
* The gateway BASE for a locator network, given already-resolved `overrides` — PURE, no env
|
|
13
|
+
* read. Defaults to the generic public gateways (`ipfs.io` / `arweave.net`) when `overrides`
|
|
14
|
+
* doesn't name one; any other `network` (e.g. `http`, which carries its own base) resolves to
|
|
15
|
+
* `''`. Callers that want override → env → default precedence compose this with
|
|
16
|
+
* {@link gatewayConfigFromEnv} themselves (see `@artblocks/abx-storage`'s `resolveGatewayBase`
|
|
17
|
+
* for the reference compose) — kept separate so a host with its own config source never has this
|
|
18
|
+
* function reach into `process.env` on its behalf.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveGatewayBase(network, overrides) {
|
|
21
|
+
if (network === 'ipfs')
|
|
22
|
+
return overrides?.ipfs || 'https://ipfs.io';
|
|
23
|
+
if (network === 'arweave')
|
|
24
|
+
return overrides?.arweave || 'https://arweave.net';
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The ONLY env-reading piece of this module: `ABX_IPFS_GATEWAY` / `ABX_ARWEAVE_GATEWAY`, read via
|
|
29
|
+
* {@link readEnv} (safe where `process` doesn't exist). Exported separately from
|
|
30
|
+
* {@link resolveGatewayBase} so a host with its own gateway configuration (a database row, a
|
|
31
|
+
* remote config service) never has to touch `process.env` through this package at all — it just
|
|
32
|
+
* never calls this function and passes its own overrides straight to the pure resolver instead.
|
|
33
|
+
*/
|
|
34
|
+
export function gatewayConfigFromEnv() {
|
|
35
|
+
const ipfs = readEnv('ABX_IPFS_GATEWAY');
|
|
36
|
+
const arweave = readEnv('ABX_ARWEAVE_GATEWAY');
|
|
37
|
+
const out = {};
|
|
38
|
+
if (ipfs)
|
|
39
|
+
out.ipfs = ipfs;
|
|
40
|
+
if (arweave)
|
|
41
|
+
out.arweave = arweave;
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
/** Build the URL that asks `gateway` for `id`. A locator that is already an absolute URL is asked
|
|
45
|
+
* verbatim — rewriting someone's URL would answer a question they didn't ask. */
|
|
46
|
+
export function gatewayUrlFor(network, id, gateway) {
|
|
47
|
+
if (/^https?:\/\//i.test(id))
|
|
48
|
+
return id;
|
|
49
|
+
const base = gateway.replace(/\/+$/, '');
|
|
50
|
+
// A path suffix (a directory manifest entry, e.g. `<txid>/index.html`) rides along untouched.
|
|
51
|
+
return network === 'ipfs' ? `${base}/ipfs/${id}` : `${base}/${id}`;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=gateways.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateways.js","sourceRoot":"","sources":["../src/gateways.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAclC;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAoC,EAAE,SAA4B;IACnG,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,SAAS,EAAE,IAAI,IAAI,iBAAiB,CAAC;IACpE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,EAAE,OAAO,IAAI,qBAAqB,CAAC;IAC9E,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1B,IAAI,OAAO;QAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACnC,OAAO,GAAG,CAAC;AACb,CAAC;AAED;kFACkF;AAClF,MAAM,UAAU,aAAa,CAAC,OAAuB,EAAE,EAAU,EAAE,OAAe;IAChF,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzC,8FAA8F;IAC9F,OAAO,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generator-document family — the template-mode runtime companion, the inline-safety
|
|
3
|
+
* escapes, and the pure document-shape builders. Hoisted from `@artblocks/abx-token-api`
|
|
4
|
+
* (the abx-services integrator ask): every piece here is a pure string operation with no chain
|
|
5
|
+
* access and no Node dependency, so it belongs in the neutral layer a resolver, a CLI preview,
|
|
6
|
+
* and any third-party provider all consume identically — one definition of the runtime surface
|
|
7
|
+
* and the document shape, so none of them can quietly drift from what the others emit.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* `abx.js` — the runtime companion (the hl-gen.js analog), served at `/abx.js` and
|
|
11
|
+
* inlined into template-mode documents. Convention, not protocol: a directory build
|
|
12
|
+
* includes it; the generator injects the same surface.
|
|
13
|
+
*
|
|
14
|
+
* tokenData resolution order (the durability chain): the injected `window.abxTokenData`
|
|
15
|
+
* global (template mode) → the `?abx=` query param (base64url canonical JSON — the
|
|
16
|
+
* live-view route) → the `?chainId&contract&tokenId` coordinate floor (a build opened
|
|
17
|
+
* bare from a gateway still knows which token it is; full param reads from RPC are the
|
|
18
|
+
* render-node's job, not this shim's).
|
|
19
|
+
*/
|
|
20
|
+
export declare const ABX_JS = "(function () {\n var abx = (window.abx = window.abx || {});\n function fromQuery() {\n try {\n var q = new URLSearchParams(location.search);\n var packed = q.get('abx');\n if (packed) {\n var b64 = packed.replace(/-/g, '+').replace(/_/g, '/');\n return JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(b64), function (c) { return c.charCodeAt(0); })));\n }\n // coordinate floor: enough for a deterministic piece opened bare from a gateway\n if (q.get('contract') && q.get('tokenId')) {\n return {\n chainId: Number(q.get('chainId') || 1),\n contractAddress: String(q.get('contract')).toLowerCase(),\n tokenId: String(q.get('tokenId')),\n };\n }\n } catch (e) {}\n return null;\n }\n abx.tokenData = window.abxTokenData || fromQuery();\n abx.__traits = null;\n abx.__done = false;\n /** The script reports its computed traits (script-defined features; captured at render). */\n abx.traits = function (t) {\n abx.__traits = t;\n try { document.dispatchEvent(new CustomEvent('abx:traits', {detail: t})); } catch (e) {}\n return t;\n };\n /** Output-complete \u2014 the capture point for the render effect. Optional (timeout fallback). */\n abx.done = function () {\n abx.__done = true;\n try { document.dispatchEvent(new CustomEvent('abx:done')); } catch (e) {}\n };\n})();\n";
|
|
21
|
+
/**
|
|
22
|
+
* Inline-document safety — the one HTML parsing rule that matters when embedding
|
|
23
|
+
* content inside <script> elements: the parser ends the element at the first
|
|
24
|
+
* `</script`, regardless of JS string/comment context. Two content shapes, two
|
|
25
|
+
* semantics-preserving escapes:
|
|
26
|
+
*
|
|
27
|
+
* - JS source (libraries, artist scripts): `</script` → `<\/script`. In valid JS the
|
|
28
|
+
* sequence can only occur inside a string, template, regex, or comment — contexts
|
|
29
|
+
* where `\/` is identical to `/` — so the transform never changes behavior.
|
|
30
|
+
* - JSON (the injected `window.abxTokenData`): every `<` → `\u003c`. `<` only occurs
|
|
31
|
+
* inside JSON strings (never in the syntax), and `\u003c` parses to the same
|
|
32
|
+
* character — the canonical (hashed) serialization is untouched; only the delivery
|
|
33
|
+
* form differs.
|
|
34
|
+
*/
|
|
35
|
+
/** JS source safe to inline inside a <script> element. */
|
|
36
|
+
export declare function escapeInlineScript(src: string): string;
|
|
37
|
+
/** A JSON payload safe to inline inside a <script> element (parse-identical). */
|
|
38
|
+
export declare function escapeInlineJson(json: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Inject `window.abxTokenData` (and, when the document doesn't already carry one, a
|
|
41
|
+
* `<base href="{code root}/">` so relative asset paths keep riding the gateway) at the
|
|
42
|
+
* very top of `<head>` — before any build script can execute; abx.js resolves the global
|
|
43
|
+
* first. String-level and deliberately robust rather than a full HTML parse: no `<head>`
|
|
44
|
+
* → inject right after `<html …>`; neither → prepend. First `<base>` wins in HTML, so an
|
|
45
|
+
* existing one is never doubled.
|
|
46
|
+
*/
|
|
47
|
+
export declare function injectTokenDataIntoHtml(html: string, tokenDataJson: string, codeRoot: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* The template-mode document shape, pure — no chain access, so a caller that already has a
|
|
50
|
+
* script + dep tags in hand (the resolver's own chain-fetched assembly; `abx preview`'s offline
|
|
51
|
+
* studio, local-file + CDN-resolved) can build the byte-identical document. Exported for exactly
|
|
52
|
+
* that reason: **one** definition of the shape, so a caller can never quietly drift from what the
|
|
53
|
+
* generator actually serves — the failure mode a hand-maintained duplicate (with a "keep these in
|
|
54
|
+
* sync" comment and nothing enforcing it) invites.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildGeneratorDocument(script: string, tokenDataJson: string, depTags: string[]): string;
|
|
57
|
+
//# sourceMappingURL=generator-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator-document.d.ts","sourceRoot":"","sources":["../src/generator-document.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,o4CAoClB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AAEH,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcrG;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAYvG"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generator-document family — the template-mode runtime companion, the inline-safety
|
|
3
|
+
* escapes, and the pure document-shape builders. Hoisted from `@artblocks/abx-token-api`
|
|
4
|
+
* (the abx-services integrator ask): every piece here is a pure string operation with no chain
|
|
5
|
+
* access and no Node dependency, so it belongs in the neutral layer a resolver, a CLI preview,
|
|
6
|
+
* and any third-party provider all consume identically — one definition of the runtime surface
|
|
7
|
+
* and the document shape, so none of them can quietly drift from what the others emit.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* `abx.js` — the runtime companion (the hl-gen.js analog), served at `/abx.js` and
|
|
11
|
+
* inlined into template-mode documents. Convention, not protocol: a directory build
|
|
12
|
+
* includes it; the generator injects the same surface.
|
|
13
|
+
*
|
|
14
|
+
* tokenData resolution order (the durability chain): the injected `window.abxTokenData`
|
|
15
|
+
* global (template mode) → the `?abx=` query param (base64url canonical JSON — the
|
|
16
|
+
* live-view route) → the `?chainId&contract&tokenId` coordinate floor (a build opened
|
|
17
|
+
* bare from a gateway still knows which token it is; full param reads from RPC are the
|
|
18
|
+
* render-node's job, not this shim's).
|
|
19
|
+
*/
|
|
20
|
+
export const ABX_JS = `(function () {
|
|
21
|
+
var abx = (window.abx = window.abx || {});
|
|
22
|
+
function fromQuery() {
|
|
23
|
+
try {
|
|
24
|
+
var q = new URLSearchParams(location.search);
|
|
25
|
+
var packed = q.get('abx');
|
|
26
|
+
if (packed) {
|
|
27
|
+
var b64 = packed.replace(/-/g, '+').replace(/_/g, '/');
|
|
28
|
+
return JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(b64), function (c) { return c.charCodeAt(0); })));
|
|
29
|
+
}
|
|
30
|
+
// coordinate floor: enough for a deterministic piece opened bare from a gateway
|
|
31
|
+
if (q.get('contract') && q.get('tokenId')) {
|
|
32
|
+
return {
|
|
33
|
+
chainId: Number(q.get('chainId') || 1),
|
|
34
|
+
contractAddress: String(q.get('contract')).toLowerCase(),
|
|
35
|
+
tokenId: String(q.get('tokenId')),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
} catch (e) {}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
abx.tokenData = window.abxTokenData || fromQuery();
|
|
42
|
+
abx.__traits = null;
|
|
43
|
+
abx.__done = false;
|
|
44
|
+
/** The script reports its computed traits (script-defined features; captured at render). */
|
|
45
|
+
abx.traits = function (t) {
|
|
46
|
+
abx.__traits = t;
|
|
47
|
+
try { document.dispatchEvent(new CustomEvent('abx:traits', {detail: t})); } catch (e) {}
|
|
48
|
+
return t;
|
|
49
|
+
};
|
|
50
|
+
/** Output-complete — the capture point for the render effect. Optional (timeout fallback). */
|
|
51
|
+
abx.done = function () {
|
|
52
|
+
abx.__done = true;
|
|
53
|
+
try { document.dispatchEvent(new CustomEvent('abx:done')); } catch (e) {}
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
56
|
+
`;
|
|
57
|
+
/**
|
|
58
|
+
* Inline-document safety — the one HTML parsing rule that matters when embedding
|
|
59
|
+
* content inside <script> elements: the parser ends the element at the first
|
|
60
|
+
* `</script`, regardless of JS string/comment context. Two content shapes, two
|
|
61
|
+
* semantics-preserving escapes:
|
|
62
|
+
*
|
|
63
|
+
* - JS source (libraries, artist scripts): `</script` → `<\/script`. In valid JS the
|
|
64
|
+
* sequence can only occur inside a string, template, regex, or comment — contexts
|
|
65
|
+
* where `\/` is identical to `/` — so the transform never changes behavior.
|
|
66
|
+
* - JSON (the injected `window.abxTokenData`): every `<` → `\u003c`. `<` only occurs
|
|
67
|
+
* inside JSON strings (never in the syntax), and `\u003c` parses to the same
|
|
68
|
+
* character — the canonical (hashed) serialization is untouched; only the delivery
|
|
69
|
+
* form differs.
|
|
70
|
+
*/
|
|
71
|
+
/** JS source safe to inline inside a <script> element. */
|
|
72
|
+
export function escapeInlineScript(src) {
|
|
73
|
+
return src.replace(/<\/(script)/gi, '<\\/$1');
|
|
74
|
+
}
|
|
75
|
+
/** A JSON payload safe to inline inside a <script> element (parse-identical). */
|
|
76
|
+
export function escapeInlineJson(json) {
|
|
77
|
+
return json.replace(/</g, '\\u003c');
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Inject `window.abxTokenData` (and, when the document doesn't already carry one, a
|
|
81
|
+
* `<base href="{code root}/">` so relative asset paths keep riding the gateway) at the
|
|
82
|
+
* very top of `<head>` — before any build script can execute; abx.js resolves the global
|
|
83
|
+
* first. String-level and deliberately robust rather than a full HTML parse: no `<head>`
|
|
84
|
+
* → inject right after `<html …>`; neither → prepend. First `<base>` wins in HTML, so an
|
|
85
|
+
* existing one is never doubled.
|
|
86
|
+
*/
|
|
87
|
+
export function injectTokenDataIntoHtml(html, tokenDataJson, codeRoot) {
|
|
88
|
+
const baseTag = /<base[\s/>]/i.test(html) ? '' : `<base href="${codeRoot}">`;
|
|
89
|
+
const injection = `${baseTag}<script>window.abxTokenData=${escapeInlineJson(tokenDataJson)};</script>`;
|
|
90
|
+
const head = /<head(\s[^>]*)?>/i.exec(html);
|
|
91
|
+
if (head) {
|
|
92
|
+
const at = head.index + head[0].length;
|
|
93
|
+
return html.slice(0, at) + injection + html.slice(at);
|
|
94
|
+
}
|
|
95
|
+
const htmlTag = /<html(\s[^>]*)?>/i.exec(html);
|
|
96
|
+
if (htmlTag) {
|
|
97
|
+
const at = htmlTag.index + htmlTag[0].length;
|
|
98
|
+
return html.slice(0, at) + injection + html.slice(at);
|
|
99
|
+
}
|
|
100
|
+
return injection + html;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The template-mode document shape, pure — no chain access, so a caller that already has a
|
|
104
|
+
* script + dep tags in hand (the resolver's own chain-fetched assembly; `abx preview`'s offline
|
|
105
|
+
* studio, local-file + CDN-resolved) can build the byte-identical document. Exported for exactly
|
|
106
|
+
* that reason: **one** definition of the shape, so a caller can never quietly drift from what the
|
|
107
|
+
* generator actually serves — the failure mode a hand-maintained duplicate (with a "keep these in
|
|
108
|
+
* sync" comment and nothing enforcing it) invites.
|
|
109
|
+
*/
|
|
110
|
+
export function buildGeneratorDocument(script, tokenDataJson, depTags) {
|
|
111
|
+
return [
|
|
112
|
+
'<!doctype html>',
|
|
113
|
+
'<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">',
|
|
114
|
+
'<style>html,body{margin:0;padding:0;overflow:hidden}canvas{display:block}</style>',
|
|
115
|
+
`<script>window.abxTokenData=${escapeInlineJson(tokenDataJson)};</script>`,
|
|
116
|
+
`<script>${ABX_JS}</script>`,
|
|
117
|
+
...depTags,
|
|
118
|
+
'</head><body>',
|
|
119
|
+
`<script>\n${escapeInlineScript(script)}\n</script>`,
|
|
120
|
+
'</body></html>',
|
|
121
|
+
].join('\n');
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=generator-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator-document.js","sourceRoot":"","sources":["../src/generator-document.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCrB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AAEH,0DAA0D;AAC1D,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AAChD,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,aAAqB,EAAE,QAAgB;IAC3F,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,QAAQ,IAAI,CAAC;IAC7E,MAAM,SAAS,GAAG,GAAG,OAAO,+BAA+B,gBAAgB,CAAC,aAAa,CAAC,YAAY,CAAC;IACvG,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,SAAS,GAAG,IAAI,CAAC;AAC1B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,aAAqB,EAAE,OAAiB;IAC7F,OAAO;QACL,iBAAiB;QACjB,uGAAuG;QACvG,mFAAmF;QACnF,+BAA+B,gBAAgB,CAAC,aAAa,CAAC,YAAY;QAC1E,WAAW,MAAM,WAAW;QAC5B,GAAG,OAAO;QACV,eAAe;QACf,aAAa,kBAAkB,CAAC,MAAM,CAAC,aAAa;QACpD,gBAAgB;KACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,19 +13,33 @@ export * from './types.js';
|
|
|
13
13
|
export * from './spine.js';
|
|
14
14
|
export * from './chains.js';
|
|
15
15
|
export * from './clients.js';
|
|
16
|
-
export * from './deploy.js';
|
|
17
16
|
export * from './ops.js';
|
|
17
|
+
export * from './execute.js';
|
|
18
|
+
export * from './errors.js';
|
|
19
|
+
export * from './deploy.js';
|
|
20
|
+
export * from './anchors.js';
|
|
18
21
|
export * from './reconstruct.js';
|
|
22
|
+
export * from './resume.js';
|
|
19
23
|
export * from './tokendata.js';
|
|
20
24
|
export * from './probe.js';
|
|
21
25
|
export * from './token.js';
|
|
26
|
+
export * from './tokens.js';
|
|
22
27
|
export * from './traits.js';
|
|
23
28
|
export * from './fastlz.js';
|
|
24
29
|
export * from './chunks.js';
|
|
25
30
|
export * from './create2.js';
|
|
31
|
+
export * from './creator-token.js';
|
|
26
32
|
export * from './deployments.js';
|
|
27
33
|
export * from './deps.js';
|
|
34
|
+
export * from './gateways.js';
|
|
28
35
|
export * from './generator.js';
|
|
29
|
-
export
|
|
36
|
+
export * from './generator-document.js';
|
|
37
|
+
export * from './inspect.js';
|
|
38
|
+
export * from './migrate.js';
|
|
39
|
+
export * from './mime.js';
|
|
40
|
+
export * from './onchain-uri.js';
|
|
41
|
+
export * from './service.js';
|
|
42
|
+
export * from './staging.js';
|
|
43
|
+
export * from './util.js';
|
|
30
44
|
export { oneOfOneImageAbi, oneOfOneImageFactoryAbi, seriesImageAbi, seriesImageFactoryAbi, seriesCodeAbi, seriesCodeFactoryAbi, abxSeedSourceAbi, abxMetadataRendererAbi, abxChunkStoreAbi, abxFixedPriceMinterAbi, spineEventAbi, } from './abi/index.js';
|
|
31
45
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,YAAY,EAAC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAC,MAAM,MAAM,CAAC;AAE5E,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,YAAY,EAAC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAC,MAAM,MAAM,CAAC;AAE5E,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,19 +2,33 @@ export * from './types.js';
|
|
|
2
2
|
export * from './spine.js';
|
|
3
3
|
export * from './chains.js';
|
|
4
4
|
export * from './clients.js';
|
|
5
|
-
export * from './deploy.js';
|
|
6
5
|
export * from './ops.js';
|
|
6
|
+
export * from './execute.js';
|
|
7
|
+
export * from './errors.js';
|
|
8
|
+
export * from './deploy.js';
|
|
9
|
+
export * from './anchors.js';
|
|
7
10
|
export * from './reconstruct.js';
|
|
11
|
+
export * from './resume.js';
|
|
8
12
|
export * from './tokendata.js';
|
|
9
13
|
export * from './probe.js';
|
|
10
14
|
export * from './token.js';
|
|
15
|
+
export * from './tokens.js';
|
|
11
16
|
export * from './traits.js';
|
|
12
17
|
export * from './fastlz.js';
|
|
13
18
|
export * from './chunks.js';
|
|
14
19
|
export * from './create2.js';
|
|
20
|
+
export * from './creator-token.js';
|
|
15
21
|
export * from './deployments.js';
|
|
16
22
|
export * from './deps.js';
|
|
23
|
+
export * from './gateways.js';
|
|
17
24
|
export * from './generator.js';
|
|
18
|
-
export
|
|
25
|
+
export * from './generator-document.js';
|
|
26
|
+
export * from './inspect.js';
|
|
27
|
+
export * from './migrate.js';
|
|
28
|
+
export * from './mime.js';
|
|
29
|
+
export * from './onchain-uri.js';
|
|
30
|
+
export * from './service.js';
|
|
31
|
+
export * from './staging.js';
|
|
32
|
+
export * from './util.js';
|
|
19
33
|
export { oneOfOneImageAbi, oneOfOneImageFactoryAbi, seriesImageAbi, seriesImageFactoryAbi, seriesCodeAbi, seriesCodeFactoryAbi, abxSeedSourceAbi, abxMetadataRendererAbi, abxChunkStoreAbi, abxFixedPriceMinterAbi, spineEventAbi, } from './abi/index.js';
|
|
20
34
|
//# sourceMappingURL=index.js.map
|