@cognite/sdk-wells

Cognite wells SDK is tool for interacting with the CDF Wells Data Layer (WDL). All queries are passed through a service API called the 'Well-Service' that handles ingestion and queries into the well data layer.

Usage no npm install needed!

<script type="module">
  import cogniteSdkWells from 'https://cdn.skypack.dev/@cognite/sdk-wells';
</script>

README

Cognite Wells nodejs SDK

Cognite wells SDK is tool for interacting with the CDF Wells Data Layer (WDL). All queries are passed through a service API called the 'Well-Service' that handles ingestion and queries into the well data layer.

The wells data layer is an abstraction on top of CDF resources able to concatenate well data from different sources into a single contextualized representation that is independent of source and customer. This allows apps, such as Discover or customer apps, and also geoscientists running advanced models on top of well data, to be able to find data in a consistent way without having to worry about the details of many different source formats.

install and build

yarn install
yarn build

Formatting, linting, and pre-commit hook

  • To run all the lints, run yarn lint.
    • Some of the linting errors (eg. formatting) can be fixed with yarn lint:fix.
    • If you are running visual studio code, you should install the prettier extension and auto format on save:
      "[typescript]": {
          "editor.formatOnSave": true,
          "editor.defaultFormatter": "esbenp.prettier-vscode"
      },
      
  • We are using pre-commit to automatically check the code before committing. Install it with pre-commit install.

Testing

Testing the wells package locally

This repo contains some integration tests that require a CDF api key for subsurface-test tenant. Talk to any of the contributors or leave an issue and it'll get sorted. Travis will run the test and has its own api key.

Run all tests:

navigate to wells package root directory:

cd /cognite-sdk-js/packages/wells

(Optional) Autogenerate data classes (model). Requires openapi-generator-cli

$ make

Run all tests:

$ yarn build
$ COGNITE_PROJECT=<project-tenant> COGNITE_API_KEY=<your-api-key> yarn test

Run single test, i.e:

$ yarn jest --config=jest.config.js -t 'ingest casings'

Local packaging for testing

In the root of this library, write:

$ yarn link

In the root of the target project in which you'd like to test out a locally package npm version of the wells sdk, write:

$ yarn link @cognite/sdk-wells

PS! If there is already an existing version of the wells sdk configured with the target project (where you use the wells nodejs sdk), remember to comment out this version in your package.json before linking to a local version of the sdk.

consuming

set your env variables (must be valid for both cdf and geospatial API)

COGNITE_PROJECT=<project-tenant>
COGNITE_API_KEY=<your-api-key>

set up client with Api-Key

import { createWellsClient, Cluster } from "@cognite/sdk-wells";

// base url of the cdf cluster your project is in
const baseUrl = "https://greenfield.cognitedata.com";
let client = createWellsClient("app id", baseUrl);

await client.loginWithApiKey({
  project: process.env.COGNITE_PROJECT,
  apiKey: process.env.COGNITE_API_KEY,
});

console.log("logged in: ", client.isLoggedIn);

set up client with token refresh callback

import { createWellsClient, Cluster } from "@cognite/sdk-wells";

// base url of the cdf cluster your project is in
const baseUrl = "https://greenfield.cognitedata.com";
let client = createWellsClient("app id", baseUrl);

const functionThatReturnsANewToken: RefreshMethod = async () =>
  "new fresh token";

await client.loginWithToken({
  project: "subsurface-test",
  tokenRefreshCallback: functionThatReturnsANewToken,
});

console.log("logged in: ", client.isLoggedIn);

set up client with Azure AD Auth flow

Azure AD auth flow can be used via the loginWithToken method of CogniteWellsClient.

Requirements

Here is a list of requirements, that must be in place to use Azure AD authentication flow:

  • The CDF project, you're trying to sign in to, must be configured to accept tokens issued by Azure AD.
  • You should have the clientId of your Azure AD application. It is used to provide Azure AD auth flow for your application.

Azure tenantId is also something that should be defined to authenticate to Azure application which supports single tenant authentication only. In case of multi tenant application, you can skip tenantId parameter to use microsoft https://login.microsoftonline.com/common endpoint instead https://login.microsoftonline.com/:tenantId. You can find more information about single/multi tenant Azure AD application here

import { createWellsClient, Cluster } from "@cognite/sdk-wells";

// base url of the cdf cluster your project is in
const baseUrl = "https://bluefield.cognitedata.com";
let client = createWellsClient("app id", baseUrl);

const authFlow: WellsAuthFlowType = {
  type: "AAD_OAUTH", // optional: AAD_OAUTH | CDF_OAUTH | ADFS_OAUTH | OIDC_AUTHORIZATION_CODE_FLOW | CUSTOM
  options: {
    cluster: "cdf-cluster-name",
    clientId: "azure-application-client-id",
    tenantId: "azure-tenant-id",
  },
};

await client.loginWithToken({
  project: "your-cdf-project",
  accessToken: "your-access-token",
  authenticationFlow: authFlow,
});

console.log("logged in: ", client.isLoggedIn);

Source queries

Get a list of sources in the project

import { SourceItems } from "@cognite/sdk-wells";

const sources: SourceItems = await client.sources.list();

Well queries

Ingest wells

import { WellIngestion, WellItems } from "@cognite/sdk-wells";

const exampleWellIngestionItems: WellIngestion[] = [
  {
    name: "34/10-8",
    waterDepth: {
      value: 100.0,
      unit: "meter",
    },
    wellhead: {
      x: 457008.04,
      y: 6781760.88,
      crs: "EPSG:23031",
    },
    source: {
      assetExternalId: "asset:34/10-8",
      sourceName: "Petrel",
    },
    description: "this is a test well ingestion",
    country: "Norway",
    quadrant: "8",
    spudDate: "2017-05-17",
    block: "34/10",
    field: "field",
    operator: "Op1",
    wellType: "production",
    license: "MIT",
  },
];

const wells: WellItems = await client.wells.ingest(exampleWellIngestionItems);

Get wells by identifiers:

import { WellItems, IdentifierItems } from "@cognite/sdk-wells";

const wellIds: IdentifierItems = {
  items: [{ assetExternalId: "VOLVE:15/9-F-15" }, { matchingId: "GlkS359" }],
};
const wells: WellItems = await client.wells.retrieveMultiple(wellIds);

List wells:

import { WellItems } from "@cognite/sdk-wells";

const cursor = "some-cursor";
const limit = 100;
const wells: WellItems = await client.wells.list({
  cursor: cursor,
  limit: limit,
});
wells.items.forEach((well) => {
  console.log(well.externalId);
});

Get filter limits

import { WaterDepthLimits, SpudDateLimits } from "@cognite/sdk-wells";

const waterDepthLimits: WaterDepthLimits =
  await client.wells.waterDepthLimits();
const spudDateLimits: SpudDateLimits = await client.wells.spudDateLimits();

Filter wells by wkt polygon:

Currently only wkt polygons are supported by the wells service.

import { WellFilterRequest } from "@cognite/sdk-wells";

const polygon = "POLYGON ((0.0 0.0, 0.0 80.0, 80.0 80.0, 80.0 0.0, 0.0 0.0))";
const filter: WellFilterRequest = {
  filter: {
    polygon: { geometry: polygon, crs: "epsg:4326", geometryType: "wkt" },
    sources: ["edm"],
  },
};

const cursor = "some-cursor";
const limit = 100;
const wells = await client.wells.filter(filter, cursor, limit);

Filter wells by wkt polygon, fuzzy matched name and specify desired outputCrs

import { WellFilterRequest } from "@cognite/sdk-wells";

const testPolygon =
  "POLYGON ((0.0 0.0, 0.0 80.0, 80.0 80.0, 80.0 0.0, 0.0 0.0))";
const filter: WellFilterRequest = {
  filter: {
    polygon: { geometry: testPolygon, crs: "EPSG:4326" },
  },
  search: {
    query: "Field",
  },
  outputCrs: "EPSG:23031",
};

const wells = await client.wells.list(filter);
const retrievedCrs = wells.items.map((well) => well.wellhead?.crs);

Filter wells by npt events

This allows you to filter wells on associated npt events.

duration: how long did the event last in hours.

measuredDepth: at what depth the event occured.

nptCodes: what npt codes are associated to the event.

nptCodeDetails: what npt code details are associated to the event

import { WellFilterRequest, DistanceUnitEnum } from "@cognite/sdk-wells";

const filter: WellFilterRequest = {
  filter: {
    npt: {
      duration: { min: 1.0, max: 3000.0 }, // duration in hours
      measuredDepth: { min: 1800, max: 3000.0, unit: DistanceUnitEnum.METER },
      nptCodes: { containsAny: ["FJSB", "GSLB", "XSLC"] },
      nptCodeDetails: { containsAny: ["SLSN", "OLSF", "ZJST"] },
    },
  },
};

const wells = await client.wells.list(filter);

Filter wells that match on all associated npt codes / code details

import { WellFilter, LengthUnitEnum } from "@cognite/sdk-wells";

const filter: WellFilter = {
  filter: {
    npt: {
      nptCodes: { containsAll: ["FJSB", "GSLB", "XSLC"] },
      nptCodeDetails: { containsAll: ["SLSN", "OLSF", "ZJST"] },
    },
  },
};

const wells = await client.wells.list(filter);

Filter wells that match on any associated npt codes/ code details

import { WellFilterRequest } from "@cognite/sdk-wells";

const filter: WellFilterRequest = {
  filter: {
    npt: {
      nptCodes: { containsAny: ["FJSB", "GSLB", "XSLC"] },
      nptCodeDetails: { containsAny: ["SLSN", "OLSF", "ZJST"] },
    },
  },
};

const wells = await client.wells.list(filter);

Filter wells by nds events

This allows you to filter wells on associated nds events.

severities: severity of the risk, value from 0-4.

probabilities: probability of the risk, value from 0-5.

riskTypes: what risk type is associated to the event.

Filter wells that match on any associated nds risk type

import { WellFilterRequest } from "@cognite/sdk-wells";

const filter: WellFilterRequest = {
  filter: {
    nds: {
      severities: { containsAll: [1, 4] },
      probabilities: { containsAny: [2, 3] },
      ndsRiskTypes: { containsAll: ["Mechanical", "Hydraulics"] },
    },
  },
};

const wells = await client.wells.list(filter);

Get wells that have a trajectory

import { WellFilter } from "@cognite/sdk-wells";

const filter: WellFilter = { filter: { trajectories: {} } };
const wells = await client.wells.list(filter);

Get wells that have a trajectory with data between certain measured depths

import { WellFilter } from "@cognite/sdk-wells";

const filter: WellFilter = {
  filter: {
    trajectories = {
      maxMeasuredDepth: {
        minDepth: 1300.0,
        maxDepth: 1700.0,
        unit: DistanceUnitEnum.METER,
      },
    },
  },
};
const wells = await client.wells.list(filter);

Get wells that has the right set of measurement types

import { MeasurementFilter, MeasurementFilters } from "@cognite/sdk-wells";

const measurementFilter: WellMeasurementFilter = {
  measurementTypes: {
    containsAny: [
      MeasurementType.GammaRay,
      MeasurementType.Density,
      MeasurementType.Geomechanics,
    ],
  },
};

// OR, look for wells that match on ALL
const measurementFilter: WellMeasurementFilter = {
  measurementTypes: {
    containsAll: [
      MeasurementType.GammaRay,
      MeasurementType.Density,
      MeasurementType.Geomechanics,
    ],
  },
};

const wells = await client.wells.list({
  filter: { measurements: measurementFilter },
});

Filter - list all labels:

const blockLabels: string[] = await client.wells.blocks();
const fieldLabels: string[] = await client.wells.fields();
const operatorLabels: string[] = await client.wells.operators();
const quadrantLabels: string[] = await client.wells.quadrants();
const measurementTypeLabels: string[] = await client.wells.measurements();

Wellbore queries

Ingest wellbores

PS! you have to ingest the parent well ingestion before you ingest its descendant wellbore

import { WellboreItems, IdentifierItems } from "@cognite/sdk-wells";

const exampleWellboreIngestionItems: WellboreIngestion[] = [
  {
    name: "F-15 Example",
    wellAssetExternalId: "asset:34/10-8",
    source: {
      assetExternalId: "Petrel:Example-wellbore",
      sourceName: "Petrel",
    },
    description: "This wellbore is very good",
    datum: {
      elevation: { unit: "meter", value: 10.0 },
      reference: "KB",
    },
  },
];

const wellbores: WellboreItems = await client.wellbores.ingest(
  exampleWellboreIngestionItems
);

Get wellbores for a well id identifiers:

import { WellboreItems, IdentifierItems } from "@cognite/sdk-wells";

const wellIds: IdentifierItems = {
  items: [
    { assetExternalId: "VOLVE:15/9-F-15" },
    { assetExternalId: "VOLVE:15/9-F-4" },
  ],
};

const wells: WellItems = await client.wellbores.retrieveMultipleByWells(
  wellIds
);

// print out the wellbores per well
wells.forEach{ well => console.log(well.wellbores}

Get wellbores from multiple well ids:

import { Wellbore } from "@cognite/sdk-wells";

const wellIds = ["15/9-F-4", "15/9-F-5"];
const wellbores: WellboreItems = await client.wellbores.retrieveMultipleByWells(
  wellIds
);

Get wellbore by id, or ids:

import { WellboreItems, IdentifierItems } from "@cognite/sdk-wells";

const wellboreIds: IdentifierItems = {
  items: [{ assetExternalId: "15/9-F-4 B" }, { assetExternalId: "15/9-F-4 A" }],
};

const wellbores: WellboreItems = await client.wellbores.retrieveMultiple(
  wellboreIds
);

Trajectory queries

Ingest trajectories

PS! you have to ingest parent wellbore ingestion items before ingesting its descendant trajectories

import {
  TrajectoryIngestion,
  AngleUnitEnum,
  DistanceUnitEnum,
  TrajectoryItems,
} from "@cognite/sdk-wells";

const exampleTrajectoryIngestion: TrajectoryIngestion = {
  wellboreAssetExternalId: "Petrel:Example-wellbore",
  source: { sequenceExternalId: "some-sequence", sourceName: "Petrel" },
  type: "ACTUAL",
  measuredDepthUnit: DistanceUnitEnum.Meter,
  azimuthUnit: AngleUnitEnum.Degree,
  inclinationUnit: AngleUnitEnum.Degree,
  isDefinitive: true,
  rows: [
    { measuredDepth: 328.084, inclination: 0.0, azimuth: 0.0 },
    { measuredDepth: 656.168, inclination: 0.0, azimuth: 0.0 },
    { measuredDepth: 984.252, inclination: 0.0, azimuth: 0.0 },
  ],
};

const trajectories: TrajectoryItems = await client.trajectories.ingest([
  exampleTrajectoryIngestion,
]);

Get trajectories from wellbore identifiers

import { TrajectoryFilterRequest } from "@cognite/sdk-wells";

const wellboreIds: TrajectoryFilterRequest = {
  filter: {
    wellboreIds: [
      { assetExternalId: "VOLVE:13/10-F-11 T2" },
      { assetExternalId: "VOLVE:13/10-F-11 B" },
    ],
  },
};

const trajectoryItems = await client.trajectories.list(wellboreIIds);

Get data from a trajectories

import { DistanceUnitEnum, TrajectoryData } from "@cognite/sdk-wells";

// Get the data for this trajectory between the measured depths of 1000-1500m
const trajectoryDataRequest = {
  externalId: "Example Trajectory",
  measuredDepthRange: {
    minDepth: 1000.0,
    maxDepth: 1500.0,
    unit: DistanceUnitEnum.METER,
  },
};

const trajectoryDataItems = await client.trajectories.listData([
  trajectoryDataRequest,
]);
const trajectoryData: TrajectoryData = trajectoryDataItems.items[0];

We can also fetch data in a true vertical depth range

import { DistanceUnitEnum, TrajectoryData } from "@cognite/sdk-wells";

// Get the data for this trajectory between the true vertical depths of 8000-13000ft
const trajectoryDataRequest = {
  externalId: "Example Trajectory",
  trueVerticalDepthRange: {
    minDepth: 8000.0,
    maxDepth: 13000.0,
    unit: DistanceUnitEnum.FOOT,
  },
};

const trajectoryDataItems = await client.trajectories.data([
  trajectoryDataRequest,
]);
const trajectoryData: TrajectoryData = trajectoryDataItems.items[0];

Measurement queries

Ingest measurements

import { DepthMeasurement, MeasurementType } from "@cognite/sdk-wells";

const exampleDepthMeasurement: DepthMeasurement = {
  wellboreAssetExternalId: "Petrel:USA0000650400",
  source: {
    sequenceExternalId: "USA0000650400_Depthlogs_Petrel log_00",
    sourceName: "Petrel",
  },
  measuredDepth: { columnExternalId: "DEPT", unit: "foot" },
  columns: [
    {
      measurementType: MeasurementType.GammaRay,
      columnExternalId: "GR",
      unit: "gAPI",
    },
    {
      measurementType: MeasurementType.ResistivityDeep,
      columnExternalId: "RDEEP",
      unit: "ohm.m",
    },
    {
      measurementType: MeasurementType.ResistivityMedium,
      columnExternalId: "RMED",
      unit: "ohm.m",
    },
  ],
};

const measurements = await client.measurements.ingest([
  exampleDepthMeasurement,
]);

Get measurements from wellbore identifiers

import {
  DepthMeasurementItems,
  DepthMeasurementFilterRequest,
} from "@cognite/sdk-wells";

const wellboreIds: MeasurementFilterRequest = {
  filter: {
    wellboreIds: [
      { assetExternalId: "VOLVE:13/10-F-11 T2" },
      { assetExternalId: "VOLVE:13/10-F-11 B" },
    ],
  },
};

const measurementItems: DepthMeasurementItems = await client.measurements.list(
  wellboreIds
);

Get data from a measurements

import {
  DistanceUnitEnum,
  DepthMeasurementDataItems,
} from "@cognite/sdk-wells";

// Get the data for this measurement between the measured depths of 1000-1500m
const measurementDataRequest = {
  sequenceExternalId: "cdf sequence",
  measuredDepthRange: {
    minDepth: 1000.0,
    maxDepth: 1500.0,
    unit: DistanceUnitEnum.METER,
  },
};

const measurementDataItems: DepthMeasurementDataItems =
  await client.measurements.listData([measurementDataRequest]);

NPT queries

Ingest casings

PS! you have to ingest parent wellbore ingestion items before ingesting its descendant casings

import {
  CasingIngestionItems,
  CasingSchematic,
  CasingAssembly,
} from "@cognite/sdk-wells";

const exampleCasingAssembly: CasingAssembly = {
  minInsideDiameter: { value: 8.625, unit: "inch" },
  minOutsideDiameter: { value: 9.625, unit: "inch" },
  maxOutsideDiameter: { value: 10.625, unit: "inch" },
  originalMeasuredDepthTop: { value: 0.0, unit: "foot" },
  originalMeasuredDepthBase: { value: 0.0, unit: "foot" },
};

export const exampleCasingIngestionItems: CasingIngestionItems = {
  items: [
    {
      wellboreAssetExternalId: "VOLVE:15/9-F-15 A",
      source: { sequenceExternalId: "some-sequence-1", sourceName: "VOLVE" },
      phase: "ACTUAL",
      casingAssemblies: [exampleCasingAssembly],
    },
  ],
};

const casings: CasingSchematic[] = await client.casings.ingest(
  exampleCasingIngestionItems
);

Retrieve multiple casings by wellbore identifiers

import { CasingFilterRequest, CasingItems } from "@cognite/sdk-wells";

const wellboreIds: CasingFilterRequest = {
  filter: {
    wellboreIds: [
      { assetExternalId: "VOLVE:13/10-F-11 T2" },
      { assetExternalId: "VOLVE:13/10-F-11 B" },
    ],
  },
};

const casings: CasingItems = await client.casings.list(wellboreIds);

NPT queries

Ingest NPT events

PS! you have to ingest parent wellbore ingestion items before ingesting its descendant trajectories

import { NptItems, NptIngestion } from "@cognite/sdk-wells";

const exampleNptIngestion: NptIngestion = {
  wellboreAssetExternalId: "Petrel:Example-wellbore",
  source: {
    eventExternalId: "test_ingest",
    sourceName: "Petrel",
  },
  startTime: new Date("2020-01-02T12:00:00.00Z").getTime(),
  endTime: new Date("2020-01-02T14:00:00.00Z").getTime(),
};

const nptItems: NptItems = await client.npt.ingest([exampleNptIngestion]);

Filter NPT events

import { Npt, NptFilter, NptFilter, LengthUnitEnum } from "@cognite/sdk-wells";
const filter: NptFilter = {
  duration: { min: 1.0, max: 30.0 }, // filter on npt event duration range in hours
  measuredDepth: { min: 1800.0, max: 3000.0, unit: LengthUnitEnum.METER }, // filter on measured depth range that npt events took place
  nptCodes: ["FJSB", "GSLB"], // filter on npt events that match on any of the codes
  nptCodeDetails: ["SLSN", "OLSF"], // filter on npt events that match on any of the code details
  wellboreExternalIds: ["wellbore:A", "wellbore:B"], // filter on npt events that are associated to wellbore ids
};
const cursor = "some cursor"; // optional
const limit = 100; // optional

const nptFilter = {
  filter: filter,
  cursor: cursor,
  limit: limit,
};

const nptItems: NptItems = await client.npt.list(nptFilter);

List all npt codes

const nptCodes: StringItems = await client.npt.codes();

List all npt code details

const nptCodes: StringItems = await client.npt.detailCodes();

NDS queries

Ingest NDS events

import { NdsItems, NdsIngestion } from "@cognite/sdk-wells";

const exampleNdsIngestion: NdsIngestion = {
  wellboreAssetExternalId: "Petrel:Example-wellbore",
  source: {
    eventExternalId: "test_ingest",
    sourceName: "Petrel",
  },
  holeStart: { value: 100.0, unit: "meter" },
  holeEnd: { value: 100.0, unit: "meter" },
  holeDiameter: { value: 100.0, unit: "meter" },
  probability: 1,
  severity: 2,
};

const ndsItems: NdsItems = await client.nds.ingest([exampleNdsIngestion]);

Filter nds events

import { Nds, NdsFilter, NdsFilter, LengthUnitEnum } from "@cognite/sdk-wells";
const filter: NdsFilter = {
  holeStart: { min: 180.0, max: 300.0, unit: LengthUnitEnum.METER }, // filter on measured depth of the start point of the hole
  holeEnd: { min: 1800.0, max: 3000.0, unit: LengthUnitEnum.METER }, // filter on measured depth of the end point of the hole
  probabilities: [1, 2], // filter on a list of nds probabilities (0-5)
  severities: [2, 4], // filter on a list of nds severities (0-4)
  wellboreExternalIds: ["wellbore:A", "wellbore:B"], // filter on npt events that are associated to wellbore ids
};
const cursor = "some cursor"; // optional
const limit = 100; // optional

const ndsFilter: NdsFilter = {
  filter: filter,
  cursor: cursor,
  limit: limit,
};

const ndsItems: NdsItems = await client.nds.list(ndsFilter);

List all nds risk types

const ndsRiskTypes: StringItems = await client.nds.riskTypes();

Ingestion Endpoints

Before ingesting any resources, source systems where data will be ingested from must be ingested. Additionally, rules for how wells and wellbores should be merged from the source systems must also be specified.

Ingest sources

import { Source, SourceItems } from "@cognite/sdk-wells";

const sourcesToIngest: Source[] = [
  {
    source: "EDM",
  },
  {
    source: "VOLVE",
  },
];

const ingestedSources: SourceItems = await client.sources.ingest(
  sourcesToIngest
);

Set merge rules for the wells

import { WellMergeRules } from '@cognite/sdk-wells';

// Merge rules can be set by specifying the order for each attribute directly:
const mergeRules: WellMergeRules = {
  name: ['EDM', 'VOLVE'],
  description: ['EDM'], // Not including a source means that source will be ignored for this parameter
  ...,
  kbElevation: ['VOLVE', 'EDM']
}
const ingestedRules: WellMergeRules = await client.wells.mergeRules.set(mergeRules)

// Or merge rules can all be set from one list
const ingestedRules: WellMergeRules = await client.wells.mergeRules.set(['EDM', 'VOLVE'])

// Merge Rules can then be fetched
const ingestedRules: WellMergeRules = await client.wells.mergeRules.retrieve();

Set merge rules for the wellbores

import { WellboreMergeRules } from "@cognite/sdk-wells";

// Merge rules can be set by specifying the order for each attribute directly:
const mergeRules: WellboreMergeRules = {
  name: ["EDM", "VOLVE"],
  description: ["EDM"],
};
const ingestedRules: WellboreMergeRules = await client.wellbores.mergeRules.set(
  mergeRules
);

// Or merge rules can all be set from one list
const ingestedRules: WellboreMergeRules = await client.wellbores.mergeRules.set(
  ["EDM", "VOLVE"]
);

// Merge Rules can then be fetched
const ingestedRules: WellboreMergeRules =
  await client.wellbores.mergeRules.retrieve();