@lunora/runtime 1.0.0-alpha.22 → 1.0.0-alpha.23
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/dist/index.d.mts
CHANGED
|
@@ -1643,6 +1643,19 @@ interface FunctionRegistryEntry {
|
|
|
1643
1643
|
*/
|
|
1644
1644
|
kind: "action" | "mutation" | "query" | "stream";
|
|
1645
1645
|
visibility?: "internal" | "public";
|
|
1646
|
+
/**
|
|
1647
|
+
* x402 payment tag set by the `.x402({ price })` builder modifier. Present
|
|
1648
|
+
* only on paid public procedures; the origin worker answers an unpaid RPC
|
|
1649
|
+
* for such a function with a real `402` challenge (via the injected
|
|
1650
|
+
* {@link WorkerOptions.x402Charge} gate) before dispatching, then verifies +
|
|
1651
|
+
* settles at the origin boundary so the shard never sees payment state.
|
|
1652
|
+
* Rides along on the registered function object's identity — codegen casts
|
|
1653
|
+
* the real `fn` into `LUNORA_FUNCTIONS`, so reading it needs no change to the
|
|
1654
|
+
* generated shape (same as `fn.rls`).
|
|
1655
|
+
*/
|
|
1656
|
+
x402?: {
|
|
1657
|
+
readonly price: number | string;
|
|
1658
|
+
};
|
|
1646
1659
|
}
|
|
1647
1660
|
/**
|
|
1648
1661
|
* The generated `LUNORA_FUNCTIONS` dispatch table, narrowed to what the
|
|
@@ -1650,6 +1663,25 @@ interface FunctionRegistryEntry {
|
|
|
1650
1663
|
*/
|
|
1651
1664
|
type FunctionRegistryLike = Record<string, FunctionRegistryEntry>;
|
|
1652
1665
|
/**
|
|
1666
|
+
* Injected x402 charge gate — the seam that paywalls a `.x402({ price })`-tagged
|
|
1667
|
+
* procedure at the origin worker without the runtime importing `@lunora/x402`
|
|
1668
|
+
* (which would pull viem/solana into every worker bundle). Build it with
|
|
1669
|
+
* `createProcedureChargeGate(config)` from `@lunora/x402/charge` and pass it as
|
|
1670
|
+
* {@link WorkerOptions.x402Charge}.
|
|
1671
|
+
*
|
|
1672
|
+
* Given the inbound `request`, the paid procedure's `spec` (its `functionPath` —
|
|
1673
|
+
* used as the x402 challenge `resource` — and USD `price`), and a `dispatch`
|
|
1674
|
+
* that runs the real shard forward, it returns a real `402` + `PAYMENT-REQUIRED`
|
|
1675
|
+
* challenge when the request is unpaid, or the dispatched response (with
|
|
1676
|
+
* `X-PAYMENT-RESPONSE` attached) once the client's `X-PAYMENT` is verified and
|
|
1677
|
+
* settled. `dispatch` runs only after payment is verified — an unpaid or
|
|
1678
|
+
* invalid request never reaches the shard.
|
|
1679
|
+
*/
|
|
1680
|
+
type X402ChargeGate = (request: Request, spec: {
|
|
1681
|
+
functionPath: string;
|
|
1682
|
+
price: number | string;
|
|
1683
|
+
}, dispatch: () => Promise<Response>) => Promise<Response>;
|
|
1684
|
+
/**
|
|
1653
1685
|
* Lists objects in the storage bucket for the admin file browser. Structurally
|
|
1654
1686
|
* compatible with `@lunora/storage`'s `Storage["list"]` — the runtime stays free
|
|
1655
1687
|
* of a hard dependency on the storage package.
|
|
@@ -2313,6 +2345,18 @@ interface WorkerOptions {
|
|
|
2313
2345
|
* reports "not configured" and the studio shows the credentials empty state.
|
|
2314
2346
|
*/
|
|
2315
2347
|
workflowsClient?: (env: unknown) => undefined | WorkflowsRestClient;
|
|
2348
|
+
/**
|
|
2349
|
+
* Injected x402 charge gate for paid (`.x402({ price })`) procedures. Build
|
|
2350
|
+
* it with `createProcedureChargeGate(config)` from `@lunora/x402/charge` and
|
|
2351
|
+
* pass it here; the runtime stays free of a hard `@lunora/x402` dependency
|
|
2352
|
+
* (and its viem/solana deps).
|
|
2353
|
+
*
|
|
2354
|
+
* **Required whenever any registered function is `.x402()`-tagged.** The
|
|
2355
|
+
* origin worker refuses to dispatch a paid procedure with a config error
|
|
2356
|
+
* (`500`) when this is absent, rather than serving it free — the paywall is
|
|
2357
|
+
* fail-closed by construction. See {@link X402ChargeGate}.
|
|
2358
|
+
*/
|
|
2359
|
+
x402Charge?: X402ChargeGate;
|
|
2316
2360
|
}
|
|
2317
2361
|
interface RpcContext {
|
|
2318
2362
|
ctx: ExecutionContextLike;
|
package/dist/index.d.ts
CHANGED
|
@@ -1643,6 +1643,19 @@ interface FunctionRegistryEntry {
|
|
|
1643
1643
|
*/
|
|
1644
1644
|
kind: "action" | "mutation" | "query" | "stream";
|
|
1645
1645
|
visibility?: "internal" | "public";
|
|
1646
|
+
/**
|
|
1647
|
+
* x402 payment tag set by the `.x402({ price })` builder modifier. Present
|
|
1648
|
+
* only on paid public procedures; the origin worker answers an unpaid RPC
|
|
1649
|
+
* for such a function with a real `402` challenge (via the injected
|
|
1650
|
+
* {@link WorkerOptions.x402Charge} gate) before dispatching, then verifies +
|
|
1651
|
+
* settles at the origin boundary so the shard never sees payment state.
|
|
1652
|
+
* Rides along on the registered function object's identity — codegen casts
|
|
1653
|
+
* the real `fn` into `LUNORA_FUNCTIONS`, so reading it needs no change to the
|
|
1654
|
+
* generated shape (same as `fn.rls`).
|
|
1655
|
+
*/
|
|
1656
|
+
x402?: {
|
|
1657
|
+
readonly price: number | string;
|
|
1658
|
+
};
|
|
1646
1659
|
}
|
|
1647
1660
|
/**
|
|
1648
1661
|
* The generated `LUNORA_FUNCTIONS` dispatch table, narrowed to what the
|
|
@@ -1650,6 +1663,25 @@ interface FunctionRegistryEntry {
|
|
|
1650
1663
|
*/
|
|
1651
1664
|
type FunctionRegistryLike = Record<string, FunctionRegistryEntry>;
|
|
1652
1665
|
/**
|
|
1666
|
+
* Injected x402 charge gate — the seam that paywalls a `.x402({ price })`-tagged
|
|
1667
|
+
* procedure at the origin worker without the runtime importing `@lunora/x402`
|
|
1668
|
+
* (which would pull viem/solana into every worker bundle). Build it with
|
|
1669
|
+
* `createProcedureChargeGate(config)` from `@lunora/x402/charge` and pass it as
|
|
1670
|
+
* {@link WorkerOptions.x402Charge}.
|
|
1671
|
+
*
|
|
1672
|
+
* Given the inbound `request`, the paid procedure's `spec` (its `functionPath` —
|
|
1673
|
+
* used as the x402 challenge `resource` — and USD `price`), and a `dispatch`
|
|
1674
|
+
* that runs the real shard forward, it returns a real `402` + `PAYMENT-REQUIRED`
|
|
1675
|
+
* challenge when the request is unpaid, or the dispatched response (with
|
|
1676
|
+
* `X-PAYMENT-RESPONSE` attached) once the client's `X-PAYMENT` is verified and
|
|
1677
|
+
* settled. `dispatch` runs only after payment is verified — an unpaid or
|
|
1678
|
+
* invalid request never reaches the shard.
|
|
1679
|
+
*/
|
|
1680
|
+
type X402ChargeGate = (request: Request, spec: {
|
|
1681
|
+
functionPath: string;
|
|
1682
|
+
price: number | string;
|
|
1683
|
+
}, dispatch: () => Promise<Response>) => Promise<Response>;
|
|
1684
|
+
/**
|
|
1653
1685
|
* Lists objects in the storage bucket for the admin file browser. Structurally
|
|
1654
1686
|
* compatible with `@lunora/storage`'s `Storage["list"]` — the runtime stays free
|
|
1655
1687
|
* of a hard dependency on the storage package.
|
|
@@ -2313,6 +2345,18 @@ interface WorkerOptions {
|
|
|
2313
2345
|
* reports "not configured" and the studio shows the credentials empty state.
|
|
2314
2346
|
*/
|
|
2315
2347
|
workflowsClient?: (env: unknown) => undefined | WorkflowsRestClient;
|
|
2348
|
+
/**
|
|
2349
|
+
* Injected x402 charge gate for paid (`.x402({ price })`) procedures. Build
|
|
2350
|
+
* it with `createProcedureChargeGate(config)` from `@lunora/x402/charge` and
|
|
2351
|
+
* pass it here; the runtime stays free of a hard `@lunora/x402` dependency
|
|
2352
|
+
* (and its viem/solana deps).
|
|
2353
|
+
*
|
|
2354
|
+
* **Required whenever any registered function is `.x402()`-tagged.** The
|
|
2355
|
+
* origin worker refuses to dispatch a paid procedure with a config error
|
|
2356
|
+
* (`500`) when this is absent, rather than serving it free — the paywall is
|
|
2357
|
+
* fail-closed by construction. See {@link X402ChargeGate}.
|
|
2358
|
+
*/
|
|
2359
|
+
x402Charge?: X402ChargeGate;
|
|
2316
2360
|
}
|
|
2317
2361
|
interface RpcContext {
|
|
2318
2362
|
ctx: ExecutionContextLike;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { toAirbyteMessages, toFivetranResponse } from './packem_shared/toAirbyteMessages-DrHdplb4.mjs';
|
|
2
|
-
export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-
|
|
2
|
+
export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-CB3pLcCP.mjs';
|
|
3
3
|
export { createCrossShardRelationCapabilities } from './packem_shared/createCrossShardRelationCapabilities-CbcWjkAn.mjs';
|
|
4
4
|
export { DEFAULT_REGISTRY_CACHE_TTL_MS, SHARD_REGISTRY_DO_NAME, createDynamicShardRegistry } from './packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs';
|
|
5
5
|
export { LunoraError, toErrorResponse } from './packem_shared/LunoraError-Bpb9EFJ3.mjs';
|
|
@@ -2028,6 +2028,22 @@ const logRpcDebug = (env, envelope) => {
|
|
|
2028
2028
|
}
|
|
2029
2029
|
console.warn(`[lunora:rpc] ${envelope.fanOut ? "fan-out" : `shard=${envelope.shardKey ?? "(root)"}`} ${envelope.functionPath}`);
|
|
2030
2030
|
};
|
|
2031
|
+
const resolveX402Charge = (envelope, options) => {
|
|
2032
|
+
const x402Tag = options.functions?.[envelope.functionPath]?.x402;
|
|
2033
|
+
if (!x402Tag) {
|
|
2034
|
+
return void 0;
|
|
2035
|
+
}
|
|
2036
|
+
if (envelope.fanOut) {
|
|
2037
|
+
throw new LunoraError("a paid (`.x402`) function cannot be fanned out", { code: "BAD_REQUEST", status: 400 });
|
|
2038
|
+
}
|
|
2039
|
+
if (!options.x402Charge) {
|
|
2040
|
+
throw new LunoraError(`function "${envelope.functionPath}" is marked paid (.x402) but no x402Charge gate is configured on the worker`, {
|
|
2041
|
+
code: "MISCONFIGURED",
|
|
2042
|
+
status: 500
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
return x402Tag;
|
|
2046
|
+
};
|
|
2031
2047
|
const parseEnvelope = async (request) => {
|
|
2032
2048
|
const text = await readBodyTextWithLimit(request);
|
|
2033
2049
|
let body;
|
|
@@ -2621,6 +2637,7 @@ const createWorker = (options) => {
|
|
|
2621
2637
|
}
|
|
2622
2638
|
const { headers: forwardedHeaders, identity } = await resolveForwardContext(request, env, publicResolveIdentity);
|
|
2623
2639
|
await authorizeRpcEnvelope(envelope, identity);
|
|
2640
|
+
const x402Tag = resolveX402Charge(envelope, options);
|
|
2624
2641
|
{
|
|
2625
2642
|
const rpcStartedAt = Date.now();
|
|
2626
2643
|
const { observability } = options;
|
|
@@ -2672,7 +2689,11 @@ const createWorker = (options) => {
|
|
|
2672
2689
|
}
|
|
2673
2690
|
}
|
|
2674
2691
|
const shardKey = envelope.shardKey ?? defaultShard;
|
|
2675
|
-
|
|
2692
|
+
const dispatch = () => dispatchSingleShard(envelope.functionPath, envelope.args ?? {}, shardKey, forwardedHeaders, sinkContext);
|
|
2693
|
+
if (x402Tag && options.x402Charge) {
|
|
2694
|
+
return options.x402Charge(request, { functionPath: envelope.functionPath, price: x402Tag.price }, dispatch);
|
|
2695
|
+
}
|
|
2696
|
+
return dispatch();
|
|
2676
2697
|
}
|
|
2677
2698
|
};
|
|
2678
2699
|
const handleBatchRpc = async (request, env, context) => {
|
|
@@ -2695,6 +2716,19 @@ const createWorker = (options) => {
|
|
|
2695
2716
|
}
|
|
2696
2717
|
const { headers: forwardedHeaders, identity } = await resolveForwardContext(request, env, options.resolveIdentity);
|
|
2697
2718
|
const groups = groupBatchCallsByShard(calls, defaultShard);
|
|
2719
|
+
for (const entries of groups.values()) {
|
|
2720
|
+
for (const entry of entries) {
|
|
2721
|
+
if (options.functions?.[entry.functionPath]?.x402) {
|
|
2722
|
+
throw new LunoraError(
|
|
2723
|
+
`paid (\`.x402\`) function "${entry.functionPath}" cannot be called in a batch; dispatch it individually over ${RPC_PATH}`,
|
|
2724
|
+
{
|
|
2725
|
+
code: "BAD_REQUEST",
|
|
2726
|
+
status: 400
|
|
2727
|
+
}
|
|
2728
|
+
);
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2698
2732
|
await Promise.all(
|
|
2699
2733
|
[...groups.entries()].flatMap(
|
|
2700
2734
|
([shardKey, entries]) => entries.map((entry) => authorizeRpcEnvelope({ functionPath: entry.functionPath, shardKey }, identity))
|