@meddleware/eslint-config

Shared ESLint flat-config fragments for MeddleWare apps: the Sui chain-access boundary and URL-binding rules.
1,636
Install
npm install @meddleware/eslint-config
Latest Version:0.0.3
License:0BSD
Last Updated:Oct 23, 2026
Links: GitHub  ·  npm
Maintainer: primitivelineworks

@meddleware/eslint-config

Shared ESLint flat-config fragments for MeddleWare apps. They enforce the chain-access boundary (workspace ADR-0001): apps call the domain clients — @meddleware/access-gate-client, @meddleware/seal-client, @meddleware/walrus-client, @meddleware/sui-token-client — and the wallet-adapter; they never build transactions or read chain objects themselves. A template rule keeps URL bindings on native elements sanitised.

Use

// eslint.config.ts — after the repo's Vue + TypeScript configs
import { suiBoundary } from '@meddleware/eslint-config'

export default defineConfigWithVueTs(
  // …the repo's existing entries…
  ...suiBoundary(),
)

Append it last. It relies on the @typescript-eslint and vue plugins the repo already registers (e.g. via @vue/eslint-config-typescript and eslint-plugin-vue).

It replaces your own restriction rules. ESLint does not merge rule options across config objects: for the files the boundary covers, its no-restricted-syntax, vue/no-restricted-syntax and @typescript-eslint/no-restricted-imports options replace yours, silently. Pass your own restrictions through extraSyntax, extraTemplateSyntax and extraImportPaths so they stay in force.

What it enforces (in src/**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,vue}, except tests)

Rule Refuses
@typescript-eslint/no-restricted-imports (core no-restricted-imports for .js files) runtime imports of any @mysten/sui/* subpath except utils and bcs (type-only imports allowed); any import of @mysten/sui/jsonRpc, even type-only
no-restricted-syntax new Transaction() and its statics (Transaction.from); any reference to moveCall, splitCoins, mergeCoins, transferObjects, makeMoveVec (calls, .bind, destructuring, tx['moveCall']); calls to publish, upgrade; calls to getObject(s), listOwnedObjects, getOwnedObjects, listEvents, queryEvents, listCoins, listDynamicFields, getDynamicField, getTransaction, simulateTransaction, executeTransaction; dynamic import() (string, template or concatenation) and require() of the restricted paths
vue/no-restricted-syntax on a native element (any tag case): a bound href, src, srcset, action, formaction, poster, data, xlink:href, ping or imagesrcset unless it is a literal, undefined, a call to safeHref, safeIcon, safePath, suiExplorerUrl, walruscanBlobUrl, or a ternary of those; any bound srcdoc or <meta content>; v-bind="object" and :[dynamic] names; url(...) in a bound style
vue/no-v-html v-html

Balance and epoch reads (getBalance, listBalances, getCurrentSystemState) are allowed: they are typed, domain-free queries. src/wallet.ts (the wallet shim, walletFiles) may import the client but still may not build transactions or read objects. Components are exempt from the template rule: a component sanitises its own props.

What it cannot do

The selectors are name-based. They catch accidents and shortcuts (including an agent "fixing" lint by rewording a call), not evasion: a value passed through an arbitrary re-export or helper is not followed; a local const safeHref = (u) => u satisfies the template rule; bus.upgrade() and x.publish() calls are refused too (generic names), so a repository that uses them elsewhere should scope files. Review stays the control for anything a selector cannot see.

Options

suiBoundary({
  files: ['app/**/*.{ts,vue}'],          // where the boundary applies (the template rule follows its .vue entries)
  vueFiles: ['app/**/*.vue'],            // optional: override the derived .vue globs
  ignores: ['**/*.test.ts'],             // exempt entirely (default: tests)
  walletFiles: ['app/wallet.ts'],        // the wallet shim(s) (default: src/wallet.ts)
  urlHelpers: ['myCdnUrl'],              // extra URL helpers this repo provides
  extraSyntax: [{ selector: 'ForInStatement', message: 'no for-in' }],
  extraTemplateSyntax: [],               // your own vue/no-restricted-syntax entries
  extraImportPaths: [{ name: 'lodash', message: 'use the platform' }],
})

If no entry of files can match a .vue file, the template rule is simply not emitted.

The building blocks are exported too: restrictedImportOptions, scriptRestrictions, walletRestrictions, templateUrlRestrictions(helpers), splitGlobs, vueGlobs, URL_HELPERS, URL_ATTRIBUTES, REFUSED_ATTRIBUTES, ALLOWED_SUI_SUBPATHS.

Use eslint --report-unused-disable-directives and require a reason on every eslint-disable of these rules: a disable also hides a real hit.

License

BSD Zero Clause License (0BSD). See LICENSE.

Related Packages

@lehoczky/eslint-config-vue

ESLint Config for Vue3 with TypeScript

2,595 0
@anoesj/eslint-config-vue-ts

Anoesj's ESLint config for Vue and Nuxt projects with TypeScript

1,603 0
@nitra/eslint-config

An ESLint shareable config for projects using Vue and Node

30,246
@dsb-norge/eslint-config-dsb-vue3-ts

ESLint standard config for Vue.js version 3 projects with Typescript support

3,371 0
eslint-config-vue-preset

Provides various ESLint Shareable Configs for eslint-plugin-vue.

2,818 1

Version History

Version Released License
0.0.3 0BSD
0.0.2 0BSD
0.0.1 0BSD
0.0.0 0BSD