user4186: I have a JSON format needed for PlutusData serialization (but the format is not a standard datum in a list). The datum is wrapped in Maybe monad, so you'll note the nested lists (an array inside the outermost fields).
{
  "fields": [
    {
      "fields": [
        { "bytes": "581ccb9fba6103382ffac26484e35af190bc885510f6a25ee3dbdc673bea" }
      ],
      "constructor": 0
    }
  ],
  "constructor": 0
}

The inner bytes are CBOR hex of a sample pubkeyhash. We know that to construct the inner datum we'd do:
const datumPkh = PlutusData.from_bytes(pkhCBORBytes);

to insert that in a list is also trivial:
const innerList = PlutusList.new()
innerList.add(datumPkh)

However, since we cannot add a PlutusList to a PlutusList, would we convert the innerList to bytes and read those bytes into a PlutusDatum like:
const outerList = PlutusList.new()
outerList.add(PlutusData.from_bytes(innerList.to_bytes()))

Or, should we do something else like a ConstrData's value to_bytes() and then a PlutusList.from_bytes...etc.?
We know we can't tell if the end results are the same from the hashes of the data in cardano-cli and the serialization lib as noted in: https://github.com/Emurgo/cardano-serialization-lib/issues/333 and https://github.com/Emurgo/cardano-serialization-lib/issues/247

user4186: Mehul was correct. @strictahq/typhonjs does work correctly and produces the same result as
cardano-cli transaction hash-script-data --script-data-file test.json
Where test.json contents are:
{ "fields": [{ "fields": [{ "bytes": "cb9fba6103382ffac26484e35af190bc885510f6a25ee3dbdc673bea" }], "constructor": 0 }], "constructor": 0 }


and JS content
import { utils } from '@stricahq/typhonjs';
import { Buffer } from 'buffer';
import { PlutusData, hash_plutus_data } from "@emurgo/cardano-serialization-lib-browser"
const pkh = Buffer.from(await getPubKeyHash());
const datum = utils.createPlutusDataCbor({
  fields: [{ fields: [pkh], constructor: 0 }],
  constructor: 0,
});
const plutusDatum = PlutusData.from_bytes(datum);
const datumHash = hash_plutus_data(data);
console.log(Buffer.from(datumHash.to_bytes()).toString('hex'))

We are still trying to determine if that pkh needs to be CBOR encoded first, but that is secondary now that the structure works and produces the same hashes.

user117: Maybe this will help,
typhonjs supports creating plutusDataCbor using utility method
const plutusDataBuffer = typhonjs.utils.createPlutusDataCbor({
    constructor: 0,
    fields: [12, 12],
});

const plutusDataCBOR = plutusDataBuffer.toString('hex');

You can pass in whole JSON object to generate plutusData.

4186: <p>I have a JSON format needed for PlutusData serialization (but the format is not a standard datum in a list). The datum is wrapped in <code>Maybe</code> monad, so you'll note the nested lists (an array inside the outermost <code>fields</code>).</p>
<pre><code>{
  &quot;fields&quot;: [
    {
      &quot;fields&quot;: [
        { &quot;bytes&quot;: &quot;581ccb9fba6103382ffac26484e35af190bc885510f6a25ee3dbdc673bea&quot; }
      ],
      &quot;constructor&quot;: 0
    }
  ],
  &quot;constructor&quot;: 0
}
</code></pre>
<p>The inner bytes are CBOR hex of a sample pubkeyhash. We know that to construct the inner datum we'd do:</p>
<pre><code>const datumPkh = PlutusData.from_bytes(pkhCBORBytes);
</code></pre>
<p>to insert that in a list is also trivial:</p>
<pre><code>const innerList = PlutusList.new()
innerList.add(datumPkh)
</code></pre>
<p>However, since we cannot add a PlutusList to a PlutusList, would we convert the <code>innerList</code> to bytes and read those bytes into a PlutusDatum like:</p>
<pre><code>const outerList = PlutusList.new()
outerList.add(PlutusData.from_bytes(innerList.to_bytes()))
</code></pre>
<p>Or, should we do something else like a ConstrData's value to_bytes() and then a PlutusList.from_bytes...etc.?</p>
<p>We know we can't tell if the end results are the same from the hashes of the data in cardano-cli and the serialization lib as noted in: <a href="https://github.com/Emurgo/cardano-serialization-lib/issues/333" rel="nofollow noreferrer">https://github.com/Emurgo/cardano-serialization-lib/issues/333</a> and <a href="https://github.com/Emurgo/cardano-serialization-lib/issues/247" rel="nofollow noreferrer">https://github.com/Emurgo/cardano-serialization-lib/issues/247</a></p>
 4186: <p><a href="https://cardano.stackexchange.com/users/117/mehul-prajapati">Mehul</a> was correct. <a href="https://www.npmjs.com/package/@stricahq/typhonjs" rel="nofollow noreferrer">@strictahq/typhonjs</a> does work correctly and produces the same result as</p>
<p><code>cardano-cli transaction hash-script-data --script-data-file test.json</code></p>
<p>Where test.json contents are:</p>
<pre><code>{ &quot;fields&quot;: [{ &quot;fields&quot;: [{ &quot;bytes&quot;: &quot;cb9fba6103382ffac26484e35af190bc885510f6a25ee3dbdc673bea&quot; }], &quot;constructor&quot;: 0 }], &quot;constructor&quot;: 0 }

</code></pre>
<p>and JS content</p>
<pre><code>import { utils } from '@stricahq/typhonjs';
import { Buffer } from 'buffer';
import { PlutusData, hash_plutus_data } from &quot;@emurgo/cardano-serialization-lib-browser&quot;
const pkh = Buffer.from(await getPubKeyHash());
const datum = utils.createPlutusDataCbor({
  fields: [{ fields: [pkh], constructor: 0 }],
  constructor: 0,
});
const plutusDatum = PlutusData.from_bytes(datum);
const datumHash = hash_plutus_data(data);
console.log(Buffer.from(datumHash.to_bytes()).toString('hex'))
</code></pre>
<p>We are still trying to determine if that pkh needs to be CBOR encoded first, but that is secondary now that the structure works and produces the same hashes.</p>
 117: <p>Maybe this will help,</p>
<p><a href="https://www.npmjs.com/package/@stricahq/typhonjs" rel="nofollow noreferrer"><code>typhonjs</code></a> supports creating plutusDataCbor using utility method</p>
<pre><code>const plutusDataBuffer = typhonjs.utils.createPlutusDataCbor({
    constructor: 0,
    fields: [12, 12],
});

const plutusDataCBOR = plutusDataBuffer.toString('hex');
</code></pre>
<p>You can pass in whole JSON object to generate plutusData.</p>
